Console Login

The Root of All Evil: Hardening Container Infrastructure for the Norwegian Threat Landscape (2025 Edition)

The Root of All Evil: Hardening Container Infrastructure for the Norwegian Threat Landscape

Check your uptime. Now check your UID. If it's 0, you aren't just taking a risk; you are actively inviting a breach. In the last decade of managing infrastructure across Europe, I have seen more clusters compromised by lazy Dockerfile configurations than by zero-day kernel exploits. But in 2025, with the proliferation of AI-generated boilerplate code, the attack surface has shifted. We aren't just fighting script kiddies anymore; we are fighting automated supply chain poisoning.

Most developers treat containers like lightweight VMs. They aren't. They are just processes with a fancy hat (cgroups and namespaces). If that hat falls off—and it does—you need to ensure the floor isn't made of lava. This guide cuts through the vendor noise to focus on what actually stops a breakout: immutability, capability dropping, and the often-ignored isolation of the underlying host.

1. The "Read-Only" Reality Check

If your application writes to its own filesystem at runtime, your architecture is flawed. Mutable containers allow attackers to download payloads, modify binaries, and establish persistence. In 2025, there is zero excuse for not running with a read-only root filesystem. Keep your state in databases or mounted volumes, not in the container layer.

Here is how you force this discipline in Kubernetes. This configuration breaks 90% of poorly written apps, which is exactly why you need it:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: secure-app-v2
  labels:
    app: secure-gateway
spec:
  selector:
    matchLabels:
      app: secure-gateway
  template:
    metadata:
      labels:
        app: secure-gateway
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 10001
        runAsGroup: 10001
        fsGroup: 10001
      containers:
      - name: main
        image: registry.coolvds.com/secure-gateway:v2.4.1
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          capabilities:
            drop:
            - ALL
        volumeMounts:
        - name: tmp
          mountPath: /tmp
      volumes:
      - name: tmp
        emptyDir: {}

Note the drop: - ALL. By default, Docker grants capabilities like NET_RAW (ping) or CHOWN. A web server doesn't need to change file ownership. Drop it.

Pro Tip: If your app crashes with Read-only file system errors, don't revert the security setting. Mount an emptyDir volume to the specific path creating the noise (usually /tmp or /var/run). Fix the app, don't lower the shield.

2. Supply Chain: Trust Nothing, Sign Everything

The "latest" tag is a lie. In 2025, supply chain attacks targeting open-source dependencies are the norm. If you pull node:22-alpine directly from Docker Hub without verification, you are trusting every maintainer in that chain. We use Cosign (part of the Sigstore project) to sign and verify images before they ever touch our CoolVDS staging environments.

The verification process in your CI/CD pipeline should look like this:

# 1. Verify the signature against your public key
cosign verify --key cosign.pub registry.example.com/myapp:v1.0.0

# 2. Scan for vulnerabilities (ignoring won't-fix upstream issues)
trivy image --severity HIGH,CRITICAL --ignore-unfixed registry.example.com/myapp:v1.0.0

If the signature doesn't match, the deployment fails. Hard stop. No manual overrides.

3. The Network is the Firewall

By default, all pods in a Kubernetes cluster can talk to each other. This is a flat network, and it is a disaster waiting to happen. If your frontend gets compromised via a Struts vulnerability, it shouldn't be able to probe your Redis backend or reach out to a C2 server in a non-GDPR compliant jurisdiction.

We implement Default Deny policies everywhere. If traffic isn't explicitly allowed, it's dropped. This is critical for compliance with Norwegian data protection standards (Datatilsynet gets very unhappy about data exfiltration).

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
--- 
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: kube-system
    ports:
    - protocol: UDP
      port: 53

4. The Host Layer: Why Your VPS Provider Matters

This is where the rubber meets the road. You can have the best seccomp profiles in the world, but containers share the host kernel. If there is a kernel panic or a noisy neighbor exhausting I/O, your security posture degrades into an availability issue. Availability is part of security.

Many budget providers in Europe still use container-based virtualization (LXC/OpenVZ) for their VPS offerings. This means you are essentially running a container inside a container. If the host kernel is patched late, you are vulnerable.

At CoolVDS, we exclusively use KVM (Kernel-based Virtual Machine). Each instance has its own isolated kernel. This provides a hard boundary. Even if a container breakout occurs within your VM, the attacker is trapped inside your guest OS, not roaming the hypervisor. Combined with our NVMe storage, this ensures that high-iops logging (like Auditd or Falco) doesn't choke your application performance.

5. Runtime Detection with Falco

Static analysis is great, but it doesn't catch runtime exploits. We deploy Falco to monitor syscalls in real-time. It uses eBPF to tap into the stream of events with minimal overhead.

Here is a custom rule we use to detect if a shell is spawned inside a container—a classic sign of a breach:

- rule: Terminal Shell in Container
  desc: A shell was used as the entrypoint for a container user
  condition: >
    spawned_process and 
    container 
    and shell_procs and 
    proc.tty != 0 and 
    container_entrypoint
  output: "Shell spawned in a container (user=%user.name %container.info)"
  priority: WARNING

6. Local Compliance: The Norwegian Context

Operating in Norway brings specific legal obligations. The Nasjonal sikkerhetsmyndighet (NSM) guidelines emphasize data sovereignty. When you deploy containers, ensure your persistent volumes and backups reside physically within the EEA (or specifically Norway if dealing with sensitive health/financial data).

CoolVDS data centers in Oslo are built for this. We provide low latency access to the Norwegian internet exchange (NIX), but more importantly, we guarantee that your bits don't silently replicate to a server farm in a jurisdiction with lax privacy laws. This simplifies your GDPR Article 30 records significantly.

Quick-Fire Hardening Checklist

  • Disable Root: USER 1000 in Dockerfile.
  • Set Resource Quotas: Prevent DoS by capping CPU/RAM.
  • Scan Images: Automate trivy in CI.
  • Rotate Secrets: Never bake .env files into images.
  • Update Kernel: Rely on CoolVDS to maintain the hypervisor, but keep your guest OS (Debian/Almalinux) patched.

Security is not a product; it's a process of eliminating easy wins for the attacker. By hardening your container runtime and running it on isolated, high-performance infrastructure like CoolVDS, you turn a potential disaster into a minor log entry.

Ready to lock down your infrastructure? Deploy a KVM-isolated instance on CoolVDS today and get the dedicated kernel resources your security tools demand.