Container Security is a Lie: Hardening Your Stack Before Production
I still remember the silence on the Zoom call when we realized the crypto-miner had been running inside our billing microservice for three weeks. The entry point wasn't a zero-day in the kernel. It was a misconfigured Docker socket and a developer who thought chmod 777 was a valid troubleshooting step.
Containers are not sandboxes. Repeat that until it sticks. By default, a process running as root inside a container is effectively root on the host, separated only by thin kernel namespaces. If that kernel barrier breaks (hello, Dirty Pipe), your entire node is compromised. In the Norwegian market, where Datatilsynet (The Norwegian Data Protection Authority) does not take kindly to GDPR breaches, relying on default settings is negligence.
This isn't a theoretical discussion. This is how you lock down your infrastructure before you deploy.
1. The "Root" of All Evil
The most common vulnerability I see in audits from Oslo to Bergen is running processes as PID 1 (root). It’s convenient. It’s also dangerous. If an attacker gains remote code execution (RCE) in your app, they have root privileges within the namespace. Combined with a capability escape, they own the host.
Stop writing Dockerfiles like it's 2016. Define a user.
# BAD PATTERN
FROM node:18-alpine
WORKDIR /app
COPY . .
CMD ["node", "index.js"]
# BATTLE-HARDENED PATTERN
FROM node:18-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY . .
# Drop privileges immediately
USER appuser
CMD ["node", "index.js"]
This simple change mitigates a vast class of container breakout attacks. But we go further.
2. Kubernetes Pod Security Standards (PSS)
Since Kubernetes 1.25, Pod Security Policies (PSP) are dead. If you are still relying on them in late 2023, you are building technical debt. The replacement is Pod Security Standards (PSS) enforced via the Pod Security Admission (PSA) controller.
You need to enforce the restricted profile for any internet-facing workload. This forces you to drop capabilities and prevents privilege escalation. Here is what a secured Deployment manifest looks like today:
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-payment-gateway
labels:
app: payment
spec:
replicas: 3
selector:
matchLabels:
app: payment
template:
metadata:
labels:
app: payment
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: payment-api
image: registry.coolvds.com/payment:v2.4.1
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
Pro Tip: NoticereadOnlyRootFilesystem: true. Hackers can't install backdoors if they can't write to the disk. We mount a temporaryemptyDirvolume at/tmpfor the application's scratch space needs. This is standard practice on all CoolVDS managed clusters.
3. Supply Chain Security: Trust Nothing
You might have secured your runtime, but what exactly are you running? Public images from Docker Hub are often bloated and outdated. In 2023, supply chain attacks are the norm. You need to scan everything before it touches your cluster.
We use Trivy in our CI/CD pipelines. It scans for OS package vulnerabilities (Alpine, RHEL, Debian) and language-specific dependencies (npm, pip, go.mod).
Here is how you integrate it into a pipeline step:
$ trivy image --severity HIGH,CRITICAL --exit-code 1 python:3.9-slim
If this command finds a critical CVE, the build fails. No human intervention required. No bad code reaches production.
4. Runtime Detection with Falco
Static analysis is great, but it won't catch a zero-day exploit happening in real-time. For that, you need runtime security. Falco is the de facto standard here, acting like a security camera for your syscalls.
Imagine an attacker exploits a vulnerability in your Nginx container and spawns a shell. Falco sees the execve syscall and screams.
Example Falco Rule:
- rule: Terminal shell in container
desc: A shell was used as the entrypoint for a container event
condition: >
spawned_process and container
and shell_procs_entrypoint
and not user_expected_terminal_shell_in_container_conditions
output: >
%evt.time.s,: Shell spawned in a container
(user=%user.name container_id=%container.id container_name=%container.name
shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)
priority: WARNING
When this rule triggers, you can have a webhook kill the pod instantly. That is the level of responsiveness required for modern threats.
The Infrastructure Reality Check
Here is the uncomfortable truth: You can configure Kubernetes perfectly, but if your underlying VPS provider oversubscribes CPUs or uses weak virtualization isolation, you are still at risk. Noisy neighbors can perform side-channel attacks, or a compromised hypervisor can leak data.
This is where architecture matters.
| Feature | Standard VPS | CoolVDS Architecture |
|---|---|---|
| Virtualization | Container-based (LXC/OpenVZ) - Shared Kernel | KVM (Kernel-based Virtual Machine) - Hardware Virtualization |
| Storage Isolation | Shared SATA/SSD | Dedicated NVMe Namespaces |
| Network Latency | Variable (Europe routing) | Direct peering with NIX (Norwegian Internet Exchange) |
At CoolVDS, we don't use container-based virtualization for our instances. We use KVM. This provides a hard hardware-assisted boundary between your container host and the rest of the world. If you are handling sensitive data covered by Schrems II, you need that physical separation.
Why Norway? Why Now?
Data sovereignty is no longer optional. With the shifting legal landscape between the EU and the US, hosting your data within Norwegian borders offers a significant compliance advantage. But compliance shouldn't cost you performance.
Our benchmarks show that local routing matters. Pinging an AWS instance in Frankfurt from Oslo takes ~25-30ms. Pinging a CoolVDS instance in Oslo takes ~2ms. When you are chaining microservices, those milliseconds compound. High I/O databases on our NVMe storage don't just load faster; they lock for shorter periods, reducing race conditions and improving concurrency.
Final Thoughts
Security is not a product you buy; it's a process you execute. Start by dropping root privileges. Enforce read-only filesystems. Scan your images. And ensure your foundation is solid.
Don't let a weak infrastructure undermine your secure code. If you need a sandbox that respects both your latency requirements and your security posture, it's time to stop compromising.
Ready to harden your stack? Deploy a KVM-isolated CoolVDS instance in Oslo today and see the difference a real kernel makes.