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 withRead-only file systemerrors, don't revert the security setting. Mount anemptyDirvolume to the specific path creating the noise (usually/tmpor/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 1000in Dockerfile. - Set Resource Quotas: Prevent DoS by capping CPU/RAM.
- Scan Images: Automate
trivyin CI. - Rotate Secrets: Never bake
.envfiles 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.