Container Security
„Docker macht Deployment einfach. Docker Security macht Deployment zum Alptraum."
Sinn & Zweck
Container haben die Softwarewelt revolutioniert: Packe alles in ein Image, schieb es in die Cloud, fertig. Das Problem? Du packst auch alle Vulnerabilities mit ein – und in der Cloud haben sie mehr Angriffsfläche als je zuvor.
Container Security bedeutet: Das gesamte Container-Lifecycle absichern – vom Base Image bis zum laufenden Container, von der Registry bis zum Orchestrator.
Das Container-Sicherheitsmodell
Isolation – aber nicht wirklich
Container teilen sich den Kernel mit dem Host. Das ist keine VM-Isolation, sondern Namespace-Separation. Ein Kernel-Exploit = Game Over für alle Container.
┌──────────────────────────────────────────────────┐
│ Host Kernel │
├────────────┬────────────┬────────────────────────┤
│ Container A│ Container B│ Host Processes │
│ (App 1) │ (App 2) │ │
├────────────┴────────────┴────────────────────────┤
│ Shared Kernel Vulnerabilities │
│ (wenn einer bricht...) │
└──────────────────────────────────────────────────┘
Die Angriffsfläche
| Ebene | Risiken |
|---|---|
| Image | Vulnerable Base Images, Malware, Secrets |
| Registry | Image Tampering, Unauthorized Access |
| Orchestrator | Misconfiguration, RBAC-Fehler |
| Runtime | Container Escape, Resource Abuse |
| Network | Lateral Movement, Unencrypted Traffic |
Image Security
Base Images – Das Fundament
Das Problem:
FROM ubuntu:latest # 300 Pakete, 47 CVEs
RUN apt-get install -y everything-and-the-kitchen-sink
Die Lösung:
FROM gcr.io/distroless/static:nonroot # 0 Pakete, 0 Shell, 0 CVEs
# oder
FROM alpine:3.18 # Minimal, aber mit Shell
Image Scanning
Tools:
| Tool | Typ | Integration |
|---|---|---|
| Trivy | Open Source | CI/CD, Registry |
| Grype | Open Source | CI/CD |
| Clair | Open Source | Registry (Quay) |
| Snyk Container | Commercial | Alles |
| Anchore | Open Source/Ent | CI/CD, Registry |
| Prisma Cloud | Commercial | Enterprise |
Beispiel: Trivy
# Image scannen
trivy image myapp:latest
# Nur HIGH und CRITICAL
trivy image --severity HIGH,CRITICAL myapp:latest
# In CI/CD blockieren
trivy image --exit-code 1 --severity CRITICAL myapp:latest
Dockerfile Best Practices
# Multi-stage Build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM gcr.io/distroless/nodejs18-debian11
COPY --from=builder /app/node_modules /app/node_modules
COPY . /app
WORKDIR /app
# Non-root User
USER nonroot:nonroot
# Read-only Filesystem
# (wird zur Runtime erzwungen)
CMD ["server.js"]
Secrets in Images
So nicht:
ENV API_KEY=sk-1234567890abcdef # Für immer im Image
COPY .env /app/.env # Auch schlecht
Besser:
# Secrets zur Runtime injizieren
# Via Environment Variables oder Secrets Management
Registry Security
Private Registries
Warum?
- Kontrolle über Images
- Vulnerability Scanning
- Access Control
- Audit Logging
Optionen:
- Harbor (Open Source, empfohlen)
- AWS ECR
- Google Container Registry
- Azure Container Registry
- JFrog Artifactory
Image Signing & Verification
Cosign (Sigstore):
# Image signieren
cosign sign --key cosign.key myregistry.com/myapp:v1.0.0
# Signatur verifizieren
cosign verify --key cosign.pub myregistry.com/myapp:v1.0.0
Kubernetes Policy:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-images
spec:
rules:
- name: verify-signature
match:
resources:
kinds:
- Pod
verifyImages:
- image: "myregistry.com/*"
key: |-
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
Runtime Security
Container Hardening
Pod Security Standards (Kubernetes):
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
limits:
memory: "128Mi"
cpu: "500m"
Runtime Monitoring
Falco – Der Syscall-Wächter:
- rule: Terminal shell in container
desc: Detect shell execution in container
condition: >
spawned_process and container and
shell_procs and proc.tty != 0
output: >
Shell executed in container
(user=%user.name container=%container.name)
priority: WARNING
Was Falco erkennt:
- Shell in Container gestartet
- Verdächtige Prozesse
- Filesystem-Änderungen
- Netzwerk-Anomalien
- Privilegierte Operationen
Container Escape Prevention
Gefährliche Konfigurationen:
# NIEMALS in Production:
securityContext:
privileged: true # Container hat Root auf Host
hostNetwork: true # Sieht alle Host-Netzwerk-Traffic
hostPID: true # Sieht alle Host-Prozesse
hostIPC: true # Zugriff auf Host IPC
volumes:
- hostPath:
path: / # Host-Root gemountet
Kubernetes Security
RBAC – Role-Based Access Control
# Least Privilege Service Account
apiVersion: v1
kind: ServiceAccount
metadata:
name: myapp-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: myapp-role
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: myapp-binding
subjects:
- kind: ServiceAccount
name: myapp-sa
roleRef:
kind: Role
name: myapp-role
Network Policies
# Default: Deny all
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
# Explizit erlauben
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
spec:
podSelector:
matchLabels:
app: backend
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
Admission Controllers
OPA Gatekeeper / Kyverno:
# Kyverno: Keine privilegierten Container
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-privileged
spec:
validationFailureAction: enforce
rules:
- name: deny-privileged
match:
resources:
kinds:
- Pod
validate:
message: "Privileged containers are not allowed"
pattern:
spec:
containers:
- securityContext:
privileged: "!true"
Secrets Management in Containern
Das Anti-Pattern
# So nicht:
env:
- name: DB_PASSWORD
value: "SuperSecret123" # Im YAML, im etcd, überall
Kubernetes Secrets (Basis)
# Etwas besser:
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
password: U3VwZXJTZWNyZXQxMjM= # base64 != encryption
External Secrets Operator
# Best Practice: Secrets aus Vault
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
spec:
secretStoreRef:
name: vault-backend
target:
name: db-credentials
data:
- secretKey: password
remoteRef:
key: database/creds
property: password
Risiken & Grenzen
Shared Kernel
Ein Kernel-Exploit betrifft alle Container. Grsecurity, SELinux, AppArmor helfen, aber sind nicht perfekt.
Supply Chain
Dein Base Image hat Dependencies, die Dependencies haben, die... CVE-Party.
Komplexität
Kubernetes + Istio + OPA + Falco + Vault + ... =
"Niemand versteht mehr, was passiert"
Day-2 Operations
Images bauen ist einfach. Images aktuell halten ist ein Vollzeitjob.
Fehlkonfiguration
Die meisten Container-Breaches kommen von:
- Öffentlichen Dashboards
- Default Credentials
- Misconfigured RBAC
- Offenen etcd-Ports
Vorteile
Immutability
Container sind immutable. Ein kompromittierter Container kann einfach gelöscht und neu deployed werden.
Isolation (wenn richtig gemacht)
Mit guten Policies, Namespaces und Network Segmentation bieten Container solide Isolation.
Standardisierung
Einheitliche Security-Policies über alle Container hinweg.
Reproducibility
Das Image ist das Image ist das Image. Was getestet wurde, wird deployed.
Schnelle Updates
Vulnerable Image? Neues Image bauen, deployen, fertig. (Theoretisch.)
Best Practices Checkliste
Build Time
- Minimale Base Images (Distroless, Alpine)
- Multi-stage Builds
- Keine Secrets im Image
- Image Scanning in CI/CD
- Fixed Image Tags (nicht
:latest) - Image Signing
Runtime
- Non-root User
- Read-only Root Filesystem
- Keine Privileged Container
- Dropped Capabilities
- Resource Limits
- Seccomp/AppArmor Profile
Orchestration
- RBAC mit Least Privilege
- Network Policies (Default Deny)
- Pod Security Standards
- Admission Controllers
- Secrets aus externem Vault
- Audit Logging aktiviert
Monitoring
- Falco oder äquivalent
- Container Logs zentral
- Anomaly Detection
- Runtime Vulnerability Scanning
Fazit
Container Security ist keine einzelne Maßnahme, sondern ein Ökosystem aus Tools, Policies und Prozessen. Die gute Nachricht: Mit modernen Tools lässt sich viel automatisieren. Die schlechte Nachricht: Die Komplexität ist real, und die Angriffsfläche wächst mit jedem neuen Container.
Container isolieren nicht von Dummheit. Sie verpacken sie nur hübscher.
Weiterführende Ressourcen: