Console Login

Container Security in 2016: Stop Exposing Your Kernel to Script Kiddies

You are deploying vulnerabilities, not just containers.

It is October 2016. Docker has fundamentally changed how we ship code. I see it every day: developers spinning up containers on their laptops, pushing to a registry, and deploying to production in minutes. It feels like magic. But there is a dark side to this speed that nobody in the marketing department talks about.

Most of you are running containers as root.

I audited a setup last week for a client in Oslo. They were running a customer-facing Node.js application inside a Docker container. The Dockerfile had no USER instruction. The process inside the container was UID 0 (root). They mounted /var/run/docker.sock to let the app spawn heavy worker containers.

If an attacker manages to inject code into that Node process, they aren't just root in the container. Because of the socket mount, they are effectively root on the host. They can wipe the server, steal data from other containers, or install a persistent rootkit. Game over.

Here is how we fix this mess, using tools available right now in Docker 1.12 and the Linux kernel.

1. The "Default Root" Problem

By default, the user inside the container is the same user as the one creating it. If you don't specify otherwise, that's root. While namespaces isolate the view of the system, a uid 0 process still holds significant power if it breaks out.

The fix is simple, yet 90% of the images on Docker Hub ignore it. Create a specific user for your application.

The Fix: Update Your Dockerfile

FROM ubuntu:16.04

# Install dependencies
RUN apt-get update && apt-get install -y nginx

# Create a dedicated group and user
RUN groupadd -r appsec && useradd -r -g appsec appuser

# Set ownership of necessary directories
RUN chown -R appuser:appsec /var/www/html

# Switch to the non-root user
USER appuser

CMD ["nginx", "-g", "daemon off;"]

When this container runs, the process runs as appuser. Even if there is a remote code execution vulnerability in Nginx, the attacker is stuck with limited permissions.

2. Kernel Capabilities: You Don't Need Them All

Linux divides the privileges traditionally associated with superuser into distinct units, known as capabilities. By default, Docker drops many deep system capabilities, but it leaves enough enabled to be dangerous, such as CHOWN, DAC_OVERRIDE, and FOWNER.

Does your web server need to change file ownerships? No. Does it need to perform raw network socket operations? Probably not if it's just listening on a port.

We can adopt a whitelist approach. Drop everything, then add back only what is strictly necessary. This is paranoia, and in security, paranoia is a virtue.

docker run --d -p 80:80 \ 
  --cap-drop=ALL \ 
  --cap-add=NET_BIND_SERVICE \ 
  --name web_secure \ 
  nginx-custom
Pro Tip: If you are unsure which capabilities your application needs, run it briefly without restrictions and use pscap (from the libcap-ng-utils package) on the host to see what it's actually using.

3. Read-Only Filesystems

Immutability is a core tenant of the DevOps philosophy. If your container is stateless, why is the filesystem writable? A writable filesystem allows an attacker to download exploit kits or modify configuration files.

Docker allows you to mount the container's root filesystem as read-only. If your app needs to write temporary data (like logs or pid files), mount a tmpfs specifically for those paths.

docker run --read-only \ 
  --tmpfs /run \ 
  --tmpfs /tmp \ 
  -v /var/log/nginx:/var/log/nginx \ 
  my-app

This command forces the attacker into a corner. They cannot modify binaries. They cannot save scripts to disk. Their toolkit is neutralized.

4. The Host Architecture: KVM vs. Shared Kernel

This is where the infrastructure choice becomes critical. Container isolation relies on kernel namespaces and cgroups. These are software features. Kernels have bugs. If a kernel vulnerability is discovered (and they are discovered often), container isolation can fail.

If you are running Docker on a cheap OpenVZ VPS or a shared container platform, you are sharing the kernel with hundreds of other tenants. A kernel panic triggered by a "noisy neighbor" takes you down. Worse, a kernel exploit lets them read your memory.

This is why CoolVDS exclusively uses KVM (Kernel-based Virtual Machine).

With KVM, you get your own dedicated kernel. It acts as a hard boundary. Even if a process escapes a container, it is still trapped inside your Virtual Machine. It cannot touch the host hypervisor or other customers.

Feature OpenVZ / LXC Hosting CoolVDS (KVM)
Kernel Shared (High Risk) Dedicated (High Security)
Docker Compatibility Often requires hacks Native, standard behavior
Resource Isolation Soft limits Hard hardware virtualization

5. Network Segmentation and Latency

Security isn't just permissions; it's also about controlling data flow. In 2016, we are seeing more DDoS attacks targeting application logic. You need to ensure your backend database isn't exposed to the public internet.

Use Docker User-Defined Networks (introduced in 1.9) to isolate your tiers.

# Create a backend network
docker network create --driver bridge backend_net

# Run MySQL only on this internal network
docker run -d --net=backend_net --name db mysql:5.7

# Run the Web App on both networks
docker run -d -p 80:80 --net=backend_net --name web my-web-app

In this setup, the db container has no public IP. The outside world literally cannot route packets to it. The only entry point is your web application.

Furthermore, location matters. If your user base is in Norway, hosting in Frankfurt adds unnecessary milliseconds. CoolVDS offers NVMe storage and local peering at NIX (Norwegian Internet Exchange). Low latency means your SSL handshakes happen faster, and your application feels snappier.

Compliance and the "Datatilsynet" Factor

We are all watching the upcoming GDPR regulation (adopted this April). The Norwegian Data Protection Authority (Datatilsynet) is clear: you are responsible for the security of your data processing. Using "it was a container" is not a valid legal defense.

By using a dedicated KVM instance on CoolVDS, you demonstrate a commitment to infrastructure segregation—a key component of data protection strategies.

Conclusion

Containers are powerful, but out-of-the-box Docker is loose. It prioritizes developer experience over security. In a production environment, that trade-off is unacceptable.

  1. Stop running as root.
  2. Drop unused capabilities.
  3. Make filesystems read-only.
  4. Run your Docker host on true hardware virtualization (KVM).

Don't let a misconfigured container compromise your entire infrastructure. Security starts at the foundation.

Ready to harden your stack? Deploy a CoolVDS KVM instance with NVMe today and get full root access to build your fortress.