Container Security: Paranoia is a Feature, Not a Bug
Letβs address the elephant in the server room. It is December 2021. If you are reading this, you probably haven't slept much this week thanks to CVE-2021-44228 (Log4Shell). The Java logging vulnerability has exposed a brutal truth about modern infrastructure: we have become complacent with our supply chains and our runtime isolation.
I have spent the last 72 hours patching Elasticsearch clusters and patching Java applications I didn't even know we were running. But while everyone is scrambling to update JAR files, they are missing the architectural flaw that makes these exploits catastrophic: excessive permission and weak isolation. If your container gets popped, does the attacker get the keys to the host? In 90% of setups I audit, the answer is yes.
This isn't a high-level policy document for the board. This is a technical breakdown of how to lock down your runtime right now, using tools available today, on infrastructure that actually supports security boundaries.
1. The Root Problem (Literally)
The default behavior of Docker is to run processes as root. This is convenient for development and terrifying for production. If an attacker achieves Remote Code Execution (RCE) via something like Log4j inside a root container, they are effectively root on the kernel. If you are running on a cheap VPS provider using container-based virtualization (like OpenVZ or LXC), they are root on the host node. Game over.
You must enforce non-root users. Do not rely on the developer to remember this.
The Fix: Enforce User Context
In your Dockerfile, stop letting the daemon decide.
FROM alpine:3.14
# Create a group and user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# Tell docker that all future commands should run as the appuser
USER appuser
WORKDIR /app
COPY --chown=appuser:appgroup . .
ENTRYPOINT ["./entrypoint.sh"]If you are deploying to Kubernetes (running 1.21 or 1.22), you need to enforce this at the Pod level using securityContext. This is not optional.
apiVersion: v1
kind: Pod
metadata:
name: secured-pod
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
containers:
- name: my-app
image: my-app:1.4.2
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: truePro Tip: ThereadOnlyRootFilesystem: trueflag is your best friend. If an attacker exploits a vulnerability to drop a reverse shell script into/binor/tmp, this flag stops the write operation dead in its tracks. It breaks many legacy apps, but it saves lives.
2. Capabilities: Drop 'Em All
Linux capabilities break down the power of root into distinct units. By default, Docker gives a container about 14 capabilities, including NET_RAW (hello, packet spoofing). You rarely need these.
Adopt a whitelist approach. Drop everything, then add back only what is strictly necessary. For a standard Nginx web server or a Go binary, you usually need... nothing.
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx:alpineIn a CoolVDS environment, where we provide dedicated KVM instances, we see a distinct difference in I/O performance when capabilities are restricted, as the kernel spends less time handling privileged system calls from noisy processes.
3. The Supply Chain: Trust No One
Pulling node:latest is negligence. You have no idea what is in that image layer. With the rise of crypto-mining malware embedded in public Docker Hub images during 2021, scanning is mandatory.
We use Trivy (by Aqua Security) in our CI/CD pipelines. It is faster than Clair and easier to set up.
# Install Trivy (v0.21.2)
$ apt-get install wget apt-transport-https gnupg lsb-release
$ wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | apt-key add -
$ echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | tee -a /etc/apt/sources.list.d/trivy.list
$ apt-get update && apt-get install trivy
# Scan your image before deployment
$ trivy image --severity HIGH,CRITICAL python:3.4-alpineIf this command returns a non-zero exit code, the build should fail. Do not deploy known vulnerabilities.
4. Infrastructure Matters: The KVM Difference
Here is the reality of the Nordic hosting market: many providers selling "VPS" are actually selling containers (LXC/OpenVZ). They oversell RAM and, more critically, you share the kernel with your neighbors.
If a neighbor on a shared-kernel VPS gets hit with a kernel panic or a container escape exploit, your database goes down too. Or worse, your data is exposed.
At CoolVDS, we refuse to use container-based virtualization for customer instances. We use KVM (Kernel-based Virtual Machine). Each VPS has its own dedicated kernel. This provides a hard hardware virtualization boundary.
- Isolation: A compromised container inside your VM cannot escape to the hypervisor easily.
- Compliance: For Norwegian companies dealing with Datatilsynet and GDPR requirements post-Schrems II, knowing your data processing is physically isolated is a massive compliance advantage.
- Performance: We back this with NVMe storage. When you are scanning thousands of container layers or handling heavy log ingestion (Logstash/Fluentd), spinning rust (HDD) or shared SATA SSDs will choke your I/O.
5. Network Policies: The Forgotten Firewall
By default, all pods in a Kubernetes cluster can talk to all other pods. If your frontend is compromised, it can port scan your database. Use NetworkPolicies to lock this down.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
spec:
podSelector: {}
policyTypes:
- IngressThis "deny-all" policy forces you to explicitly whitelist traffic. It is painful to set up initially, but it prevents lateral movement.
Final Thoughts
Security is not about buying a fancy "AI-powered" firewall. It is about reducing the attack surface. Drop capabilities, run as non-root, scan your images, and ensure your underlying infrastructure provides true kernel isolation.
The Log4Shell vulnerability is a wake-up call. Don't hit the snooze button.
Need a sandbox to test your hardened configurations? Deploy a KVM-based, NVMe-powered instance on CoolVDS. Our Oslo data center offers low latency to the NIX (Norwegian Internet Exchange), ensuring your security doesn't come at the cost of speed.