Console Login

Locking Down Docker: Survival Guide for Norwegian DevOps in 2016

Locking Down Docker: Survival Guide for Norwegian DevOps in 2016

Everyone is talking about microservices. My LinkedIn feed is drowning in Docker hype. But let’s be honest for a second: most of the container setups I see in production today are terrifyingly insecure. I recently audited a setup for a client in Oslo where the development team had mounted the host's root filesystem into a container running as privileged. One wrong command, and the entire node would have been wiped.

Containers are not Virtual Machines. They are just isolated processes. If the kernel panics, everyone goes down. If a syscall is exploited, the host is compromised. With the recent invalidation of Safe Harbor by the CJEU (Schrems I) last October, storing data securely within Norwegian borders is no longer just 'nice to have'—it is a legal minefield. Here is how we harden containers without killing agility, using the tools available to us right now in March 2016.

The "Root" of the Problem

By default, the user inside a Docker container is root. If an attacker breaks out of the container (and container breakout exploits are not exactly rare), they are root on your host server. This is a disaster waiting to happen.

Until last month's release of Docker 1.10, fixing this was a nightmare of manual UID mapping. Now, we finally have User Namespaces. This allows the root user inside the container to map to a non-privileged user on the host. If they break out, they are nobody.

But you shouldn't rely solely on the daemon. You need to bake security into your images.

1. Stop Running as Root

It sounds simple, yet nobody does it. Create a specific user in your Dockerfile. Don't let your application inherit root permissions it doesn't need.

# Dockerfile best practice
FROM debian:jessie

# Create a group and user
RUN groupadd -r app && useradd -r -g app app

# Install dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    python-mysqldb \
    && rm -rf /var/lib/apt/lists/*

# Switch to user
USER app

CMD ["python", "app.py"]

Kernel Capabilities: The Scalpel, Not the Hammer

Linux root is actually a collection of capabilities. CAP_CHOWN, CAP_NET_BIND_SERVICE, CAP_SYS_ADMIN, etc. Docker grants a restricted set by default, but it's still too much for a simple web worker.

Does your Nginx container need to change system time? No. Does it need to load kernel modules? Absolutely not. Drop everything, then add back only what you need. This approach drastically reduces the attack surface.

# Drop all capabilities, then add only NET_BIND_SERVICE to bind port 80
docker run --d -p 80:80 \
  --cap-drop=ALL \
  --cap-add=NET_BIND_SERVICE \
  nginx:1.9

Pro Tip: Never use the --privileged flag unless you are actually running Docker-in-Docker or managing hardware. It grants all capabilities and disables Seccomp profiles. It's essentially giving the container the keys to the castle.

The Storage Bottleneck and Security

Security isn't just about permissions; it's about availability. A common DDoS vector against containerized environments is disk I/O exhaustion. If I can force your application to write massive logs or temp files, I can starve the host's I/O, causing the Docker daemon to hang. I've seen this take down entire clusters.

Using --read-only ensures the container root file system is immutable. Applications that need to write data should write to a volume or a tmpfs.

docker run --d \
  --read-only \
  --tmpfs /run \
  --tmpfs /tmp \
  -v /var/lib/mysql:/var/lib/mysql:rw \
  mysql:5.6

This is where infrastructure choice becomes critical. Spinning disks (HDD) cannot handle the random I/O patterns of high-density container deployments. At CoolVDS, we enforce NVMe storage for all instances because the latency on standard SSDs creates race conditions during high-concurrency builds. When you have fifty containers logging simultaneously, IOPS is your lifeline.

The Isolation Layer: Why KVM Still Matters

There is a dangerous trend of running "Bare Metal Containers" to squeeze out 2% more performance. In a multi-tenant environment, this is reckless. The Linux kernel isolation (cgroups and namespaces) is robust, but it is not bulletproof. Kernel exploits happen.

If you are processing sensitive data—especially under the watchful eye of Datatilsynet here in Norway—you need a hard boundary. This is why we architect CoolVDS on KVM (Kernel-based Virtual Machine).

Feature Bare Metal Containers CoolVDS (KVM)
Kernel Isolation Shared Kernel Dedicated Kernel
Neighbor Risk High (Kernel Panic affects all) Zero (Hardware Virtualization)
Custom Modules Impossible Allowed

By running your Docker hosts inside a KVM VPS, you get the best of both worlds: the workflow agility of containers and the hardware-level isolation of virtualization. If a container compromises the kernel, it compromises your kernel, not the physical host or your neighbors.

Network Segregation

Docker's default bridge network allows containers to talk to each other by IP. If your frontend is compromised, can it scan your database container? By default, yes.

Create specific networks for application stacks.

docker network create --driver bridge backend-net
docker run -d --net=backend-net --name=db mysql
docker run -d --net=backend-net --name=api my-api

Conclusion

The container ecosystem is moving fast. Docker 1.10 and the just-released Kubernetes 1.2 are changing the game, but the fundamentals of Linux security haven't changed. Principle of Least Privilege. Isolation. Defense in Depth.

Don't let the convenience of docker run blind you to the risks. Secure your images, drop capabilities, and ensure your runtime environment is physically isolated.

If you need a sandbox to test these configurations without risking your production rig, spin up a CoolVDS instance. We offer pure KVM virtualization with NVMe storage in our Oslo datacenter, ensuring your data stays strictly under Norwegian jurisdiction with the performance required for modern container workloads.