Console Login

Container Security in 2021: Stop Running as Root and Start Fearing the Kernel

Container Security in 2021: Stop Running as Root and Start Fearing the Kernel

Most developers treat Docker containers like lightweight Virtual Machines. They aren't. They are just processes lying to themselves about how much access they have to the host kernel. If you are deploying containers in production today—especially here in Norway where Datatilsynet is watching—and you haven't hardened your runtime, you are one kernel exploit away from a total compromise.

I have seen production clusters taken down by simple cryptojacking scripts because someone left the Docker socket exposed or ran a container as --privileged. It's messy. It's expensive. And it is entirely preventable.

1. The "Root" of All Evil

By default, processes inside a Docker container run as root. If a malicious actor breaks out of the container (which happens more often than the brochure admits), they are root on your host node. Game over.

The fix is boring but mandatory: Create a specific user in your Dockerfile. Do not rely on the default.

# The Wrong Way
FROM node:14-alpine
WORKDIR /app
COPY . .
CMD ["node", "index.js"]

# The Right Way (March 2021 Standard)
FROM node:14-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY . .
USER appuser
CMD ["node", "index.js"]

When you switch to a non-root user, you will immediately hit permission errors. Good. That means the system is working. Fix the permissions explicitly rather than granting blanket access.

2. Drop Capabilities Like They’re Hot

Even if you are not root, the Linux kernel grants specific "capabilities" to processes. Does your Nginx container really need CAP_SYS_ADMIN or CAP_NET_ADMIN? Absolutely not.

We operate on a principle of least privilege. In 2021, the best practice is to drop all capabilities and add back only what is strictly necessary. Here is how you do it in a standard docker run command:

docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE my-web-server

For Kubernetes (v1.19+), you define this in your Pod's securityContext. This is non-negotiable for any workload exposed to the public internet.

apiVersion: v1
kind: Pod
metadata:
  name: secure-nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.19
    securityContext:
      capabilities:
        drop:
        - ALL
        add:
        - NET_BIND_SERVICE
      runAsNonRoot: true
      readOnlyRootFilesystem: true
Pro Tip: notice readOnlyRootFilesystem: true? This prevents attackers from writing malicious binaries or modifying configuration files inside the container. If they get in, they can't stay. To make this work, you'll need to mount /tmp as an emptyDir volume so the app can still write temporary data.

3. The Supply Chain Trap

The SolarWinds hack late last year taught us that you can't trust your vendors blindly. Docker Hub is full of images containing vulnerabilities. If you are pulling node:latest, you are asking for trouble.

Use a scanner like Trivy or Clair in your CI/CD pipeline. If the scan fails, the build breaks. No exceptions.

# Scan an image with Trivy (v0.16.0)
trivy image coolvds-app:v1.0.0

If you see High or Critical CVEs, you fix them or you don't deploy. It is that simple.

4. Infrastructure Matters: The CoolVDS Isolation Layer

Here is the dirty secret about cheap VPS providers: many use container-based virtualization (like OpenVZ/LXC) to oversell resources. In that environment, your "server" is just a container sharing a kernel with the "server" next door. If your neighbor gets DDoS'd or exploits a kernel bug, you go down with them.

This is why we architect CoolVDS on strict KVM (Kernel-based Virtual Machine) hypervisors. KVM provides hardware-level virtualization. Your kernel is your kernel. This isolation is critical for security compliance, especially when handling sensitive data.

Comparison: Shared vs. Dedicated Kernels

Feature Container Virtualization (Common) KVM (CoolVDS Standard)
Kernel Isolation Shared (High Risk) Dedicated (High Security)
Noisy Neighbors Common Eliminated via strict resource limits
Docker Support Often requires tricks Native, behaves like bare metal

5. Norway, Schrems II, and Data Residency

We need to talk about the legal side. Since the Schrems II ruling last July, transferring personal data to US-owned cloud providers has become a legal minefield. The Privacy Shield is dead.

If your servers are physically located in Frankfurt but owned by a US entity, you are in a gray area that makes compliance officers sweat. Hosting on CoolVDS keeps your data physically in Norway, under Norwegian jurisdiction, and compliant with European standards. Our NVMe storage arrays are located in Oslo datacenters, ensuring that your data doesn't accidentally take a trip across the Atlantic.

6. Network Policies: Don't Talk to Strangers

By default, all pods in a Kubernetes cluster can talk to each other. Your frontend has no business talking to your Redis cache directly if there is a backend API in the middle.

Use NetworkPolicies to lock down traffic. Deny everything, then allow only specific paths.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

This applies to your VPS firewall too. If you are running Docker directly on a CoolVDS instance, use ufw or iptables to restrict access to the Docker daemon port (2375/2376). Never expose that to the public internet.

Final Thoughts

Security isn't a product you buy; it's a process you suffer through. But the suffering pays off when you are the only one online during a massive exploit campaign. By hardening your container runtime and running on true KVM virtualization, you reduce your attack surface by 99%.

Don't let a shared kernel be your single point of failure. Deploy your hardened containers on CoolVDS today. Our NVMe-backed KVM instances in Oslo are ready for your production workload.