The Myth of Isolation
If I had a krone for every time a developer told me "it's secure because it's in a container," I could retire to a cabin in Hemsedal. Let’s get one thing straight: containers are not Virtual Machines. They are isolated processes sharing a kernel. If that kernel panics, or if a syscall exploit slips through, the isolation dissolves faster than snow in May.
We are still feeling the aftershocks of the Log4j (Log4Shell) vulnerability from last December. It taught us a brutal lesson: scanning your code isn't enough; you must secure the runtime environment. Whether you are running a single Docker host or a Kubernetes cluster, the principles of defense-in-depth apply.
As we head further into 2022, the threat landscape has shifted. Supply chain attacks are up, and for those of us operating in Norway, the Schrems II ruling means we can't just blindly pipe data to US-owned registries without legal headaches from Datatilsynet. Here is how we lock it down.
1. Drop Root. Seriously.
Running containers as root (UID 0) is the default behavior for Docker, and it is arguably the most dangerous. If an attacker breaks out of a root container, they are root on your host. Game over.
You must explicitly define a user in your Dockerfile. Here is how you do it properly in an Alpine-based image:
FROM node:16-alpine
# Create a group and user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# Tell Docker to use this user
USER appuser
WORKDIR /home/appuser/app
COPY . .
CMD ["node", "index.js"]By switching to a non-privileged user, even if an RCE (Remote Code Execution) vulnerability is exploited, the attacker finds themselves trapped with limited permissions, unable to install packages or modify system files.
2. The Principle of Least Privilege: Capabilities
Linux capabilities break down the power of root into distinct units. By default, Docker grants a container a subset of these capabilities, but it's still too many for a web app. Does your Nginx container need to change the system time? No.
I recommend a whitelist approach: drop everything, then add back only what is strictly necessary.
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE --name web-app my-imageIn the command above, we drop all capabilities and add back only NET_BIND_SERVICE to allow binding to a port (though even this isn't needed if you bind to a high port > 1024 internally).
3. Immutable Infrastructure: Read-Only Filesystems
If an attacker gets a shell, their first move is often to download a payload or overwrite a configuration file. Make their life miserable by mounting the container's root filesystem as read-only.
You will need to use volumes for the directories that actually require write access (like /tmp or /run).
version: "3.8"
services:
app:
image: my-secure-app:v1.2
read_only: true
tmpfs:
- /tmp
- /run
volumes:
- app-data:/var/lib/app/dataThis simple change in your docker-compose.yml mitigates a massive class of potential exploits.
Pro Tip: For high-performance workloads involving databases, avoid using the default bridge network. Use --network host sparingly and only if you understand the security implications. Better yet, rely on the high I/O capabilities of NVMe storage on the host to mitigate the overhead of network bridging.4. Secure the Supply Chain: Scan Before You Push
You wouldn't eat food from a dumpster; don't pull images from untrusted sources. Docker Hub is convenient, but it's a minefield of outdated, vulnerable images.
Use tools like Trivy or Clair in your CI/CD pipeline. If the scan finds a vulnerability with a severity of "High" or "Critical," the build should fail. Here is a quick example of running Trivy against an image before deployment:
# Install Trivy (v0.28.0 is current as of April 2022)
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin v0.28.0
# Run the scan
trivy image --exit-code 1 --severity HIGH,CRITICAL coolvds/my-app:latest5. The Host Layer Matters: Virtualization vs. Containerization
This is where infrastructure choices become critical. Containers share the host kernel. If you are running your containers on a "Cheap VPS" that is actually just an OpenVZ container itself, you are nesting containers. This is a performance nightmare and a security liability.
To achieve true isolation, your container host must be a hardware-virtualized VM (KVM). This creates a hard boundary between your container's kernel and the physical hardware.
This is why we architect CoolVDS strictly on KVM with NVMe storage. When you deploy a Docker host on our platform, you aren't fighting for kernel resources with a neighbor. You have your own dedicated kernel. If a neighbor on the same physical rack gets DDOSed or compromised, the hardware virtualization layer protects your workload. In the context of Norwegian data privacy laws, knowing exactly where your data sits and how it is isolated is paramount for GDPR compliance.
Latency and Legalities
For those of us serving the Nordic market, latency to Oslo is a key metric. But beyond ping times, there is the legal latency of data crossing borders. Hosting your container registry and runtime environments within Norway (or the EEA) simplifies your ROPA (Record of Processing Activities) immensely.
6. Network Segmentation
Never expose a database port (3306, 5432) to the public internet. Docker's default bridge network allows containers to talk to each other, but you should explicitly define networks to isolate tiers.
docker network create --driver bridge --internal backend-netAttach your database to backend-net and your web application to both frontend-net and backend-net. This ensures that even if the web container is compromised, the attacker cannot easily pivot to other services that aren't on the shared network.
Conclusion
Security is not a product; it's a process. In 2022, the tools available to us—from Trivy for scanning to AppArmor profiles for runtime protection—are robust. But they require configuration.
Don't let your infrastructure be the weak link. Start with a solid foundation. Deploy your hardened containers on a KVM-backed instance where you control the kernel.
Need a secure sandbox to test these configurations? Spin up a CoolVDS NVMe instance in Oslo. It takes 55 seconds, and it's cheaper than a security breach.