Veröffentlicht am

Kubernetes Immutable Infrastructure: Read-Only Container

Teilen:
Authors

Kubernetes Immutable Infrastructure: Read-Only Container fuer Hochsicherheit

TL;DR

  • Immutable Infrastructure bedeutet: Container werden nie veraendert, sondern immer ersetzt. Kein SSH, kein kubectl exec, keine Live-Patches.
  • Read-Only Root Filesystem verhindert, dass Angreifer Malware ins Dateisystem schreiben -- selbst nach einem Container-Compromise.
  • Distroless Images enthalten weder Shell noch Package-Manager und reduzieren die Angriffsflaeche um bis zu 90%.
  • GitOps-only Changes stellen sicher, dass jede Aenderung versioniert, reviewed und auditierbar ist.
  • Die Kombination aus Immutability, Pod Security Standards und RBAC bildet eine Defense-in-Depth-Strategie.

Was Immutable Infrastructure bedeutet

Das Prinzip ist einfach: Einmal gebaut, nie veraendert. Container werden nicht gepatcht, nicht konfiguriert, nicht debugged. Jede Aenderung erzeugt ein neues Image, das durch die CI/CD-Pipeline laeuft und das alte ersetzt.

Das steht im Kontrast zu traditioneller Infrastruktur, bei der Admins sich per SSH auf Server verbinden, Pakete updaten und Konfigurationen anpassen. Dieses Modell fuehrt zu Configuration Drift -- dem schleichenden Auseinanderlaufen von Soll- und Ist-Zustand.

In Kubernetes wird Immutability auf mehreren Ebenen durchgesetzt:

EbeneMutable (traditionell)Immutable
Container-ImagePatchen im laufenden ContainerNeues Image bauen und deployen
DateisystemSchreibbarRead-Only Root Filesystem
KonfigurationSSH-Zugriff und manuelle AenderungConfigMaps/Secrets ueber Git
Debuggingkubectl exec, SSHLogs, Metrics, Tracing
UpdatesIn-Place-UpdateRolling Replacement

Read-Only Root Filesystem konfigurieren

Das Read-Only Root Filesystem ist die wichtigste technische Massnahme fuer Immutability. Es verhindert, dass Prozesse im Container Dateien schreiben koennen -- inklusive Malware, Cryptominer oder Reverse Shells.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: secure-webapp
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: secure-webapp
  template:
    metadata:
      labels:
        app: secure-webapp
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 65534
        fsGroup: 65534
      containers:
        - name: webapp
          image: gcr.io/distroless/java17-debian12:nonroot
          securityContext:
            readOnlyRootFilesystem: true
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
          volumeMounts:
            - name: tmp
              mountPath: /tmp
            - name: cache
              mountPath: /app/cache
          resources:
            requests:
              memory: "256Mi"
              cpu: "250m"
            limits:
              memory: "512Mi"
              cpu: "500m"
      volumes:
        - name: tmp
          emptyDir:
            medium: Memory
            sizeLimit: 64Mi
        - name: cache
          emptyDir:
            sizeLimit: 128Mi

Wichtige Details:

  • readOnlyRootFilesystem: true macht das gesamte Container-Dateisystem read-only.
  • EmptyDir-Volumes fuer /tmp und Cache-Verzeichnisse bieten beschreibbare Bereiche, die beim Pod-Neustart geloescht werden.
  • medium: Memory fuer /tmp nutzt tmpfs -- Daten werden nie auf die Disk geschrieben.
  • capabilities: drop: ALL entfernt alle Linux-Capabilities.

Typische Probleme und Loesungen

Viele Anwendungen erwarten ein beschreibbares Dateisystem. Hier die haeufigsten Faelle:

ProblemUrsacheLoesung
Container startet nichtApp schreibt PID-FileEmptyDir fuer PID-Verzeichnis
Log-FehlerApp schreibt in /var/logLogging auf stdout/stderr umstellen
Session-FehlerApp schreibt Session-FilesRedis/Memcached als Session-Store
SSL-FehlerApp aktualisiert CA-BundleCA-Bundle als ConfigMap mounten
Font-RenderingApp cached FontsEmptyDir fuer Font-Cache

Distroless Images: Minimale Angriffsflaeche

Distroless Images enthalten nur die Anwendung und ihre Runtime-Abhaengigkeiten. Keine Shell, kein Package-Manager, kein curl, kein wget. Ein Angreifer, der in einen Distroless Container eindringt, findet keine Tools vor.

Vergleich: Standard vs. Slim vs. Distroless

Image-TypGroesse (Java-App)PackagesShellAngriffsflaeche
ubuntu:24.04450 MBca. 100JaHoch
eclipse-temurin:17-jre-alpine180 MBca. 30Ja (ash)Mittel
gcr.io/distroless/java17220 MBca. 15NeinNiedrig
gcr.io/distroless/static2 MB0NeinMinimal

Multi-Stage Build fuer Distroless

# Build Stage
FROM eclipse-temurin:17-jdk AS build
WORKDIR /app
COPY . .
RUN ./gradlew bootJar --no-daemon

# Runtime Stage -- Distroless
FROM gcr.io/distroless/java17-debian12:nonroot
COPY --from=build /app/build/libs/app.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]

Fuer Go-Anwendungen ist das noch radikaler:

FROM golang:1.22 AS build
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /server .

FROM gcr.io/distroless/static:nonroot
COPY --from=build /server /server
ENTRYPOINT ["/server"]

Das resultierende Image ist wenige MB gross und enthaelt ausschliesslich die kompilierte Binary.

CVE-Vergleich

Ein Trivy-Scan zeigt den Unterschied deutlich:

# Ubuntu-basiertes Image
trivy image myapp:ubuntu
# Ergebnis: 45 LOW, 12 MEDIUM, 3 HIGH, 1 CRITICAL

# Distroless Image
trivy image myapp:distroless
# Ergebnis: 2 LOW, 0 MEDIUM, 0 HIGH, 0 CRITICAL

Weniger Packages bedeutet weniger CVEs bedeutet weniger Patching-Aufwand. Fuer eine umfassende Sicherheitsstrategie: Kubernetes Security Hardening.

No-SSH-Policy durchsetzen

In einer Immutable Infrastructure gibt es keinen SSH-Zugang zu Nodes oder Containern. Auch kubectl exec wird eingeschraenkt oder komplett deaktiviert.

kubectl exec per RBAC einschraenken

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: no-exec-policy
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["pods/log"]
    verbs: ["get"]
  # pods/exec ist NICHT enthalten -- damit kein exec moeglich

Fuer Notfaelle kann ein separates Break-Glass-ClusterRole existieren, das nur nach einem Approval-Prozess zugewiesen wird:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: break-glass-exec
  annotations:
    description: "Nur fuer Notfaelle -- erfordert Ticket und Approval"
rules:
  - apiGroups: [""]
    resources: ["pods/exec"]
    verbs: ["create"]

Detaillierte RBAC-Konfiguration mit Namespace-Isolation: RBAC fuer Enterprise-Umgebungen.

Pod Security Standards fuer Immutability

Pod Security Standards (PSS) auf Namespace-Ebene erzwingen Immutability-Regeln fuer alle Pods:

apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

Das restricted-Profil erzwingt unter anderem:

  • runAsNonRoot: true
  • allowPrivilegeEscalation: false
  • Alle Capabilities muessen gedroppt werden
  • Bestimmte Volume-Typen sind verboten

Fuer die vollstaendige PSS-Konfiguration: Pod Security Standards im Detail.

GitOps-only Changes: Kein manuelles kubectl apply

In einer Immutable Infrastructure werden Aenderungen ausschliesslich ueber Git vorgenommen. Kein Entwickler fuehrt kubectl apply manuell aus. Stattdessen:

  1. Aenderung im Git-Repository vornehmen (Pull Request)
  2. Review und Approval durch Kollegen
  3. Merge in den Main-Branch
  4. GitOps-Controller (Flux oder ArgoCD) synchronisiert den Cluster

Flux-Konfiguration fuer Immutable Deployments

apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: production-apps
  namespace: flux-system
spec:
  interval: 1m
  url: https://github.com/company/k8s-production
  ref:
    branch: main

---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: production-apps
  namespace: flux-system
spec:
  interval: 5m
  path: ./clusters/production
  prune: true
  sourceRef:
    kind: GitRepository
    name: production-apps
  validation: client
  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: secure-webapp
      namespace: production

Die Option prune: true ist entscheidend: Ressourcen, die aus dem Git-Repository entfernt werden, werden auch aus dem Cluster geloescht. Damit bleibt der Cluster-Zustand immer identisch mit dem Git-Repository.

Fuer eine vollstaendige GitOps-Einfuehrung mit Flux: GitOps mit Flux.

Debugging ohne SSH und exec

Ohne SSH und kubectl exec stellt sich die Frage: Wie debugged man Probleme? Die Antwort liegt in Observability:

Logs

# Logs eines Pods anzeigen
kubectl logs deployment/secure-webapp -n production --tail=100

# Logs aller Container eines Pods
kubectl logs pod/secure-webapp-abc123 -n production --all-containers

# Vorherige Container-Instanz (nach Crash)
kubectl logs pod/secure-webapp-abc123 -n production --previous

Ephemeral Debug Containers

Seit Kubernetes 1.25 gibt es Ephemeral Containers. Sie werden temporaer zu einem laufenden Pod hinzugefuegt, ohne den Pod neu zu starten:

# Debug-Container an laufenden Pod anhaengen
kubectl debug -it secure-webapp-abc123 \
  -n production \
  --image=busybox:latest \
  --target=webapp

Der Debug-Container teilt den Process-Namespace des Ziel-Containers und kann dessen Prozesse sehen. Das Original-Container-Image bleibt unveraendert.

Metrics und Tracing

Statt interaktivem Debugging setzen Immutable-Infrastructure-Teams auf:

  • Prometheus + Grafana: Metriken fuer CPU, Memory, Request-Latenz, Error-Rates
  • Jaeger oder Tempo: Distributed Tracing fuer Request-Flow-Analyse
  • Loki oder Elasticsearch: Zentrale Log-Aggregation mit Volltextsuche

Image-Signing und Supply Chain Security

Immutable Images muessen verifizierbar sein. Cosign und Sigstore stellen sicher, dass nur signierte Images deployed werden:

# Image signieren
cosign sign --key cosign.key gcr.io/company/webapp:v1.2.3

# Signatur verifizieren
cosign verify --key cosign.pub gcr.io/company/webapp:v1.2.3

In Kubernetes erzwingt ein Admission Controller (z.B. Kyverno oder OPA Gatekeeper) die Signatur-Pruefung:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signature
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-signature
      match:
        any:
          - resources:
              kinds:
                - Pod
      verifyImages:
        - imageReferences:
            - "gcr.io/company/*"
          attestors:
            - entries:
                - keys:
                    publicKeys: |-
                      -----BEGIN PUBLIC KEY-----
                      MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
                      -----END PUBLIC KEY-----

Checkliste: Immutable Infrastructure Readiness

BereichMassnahmeStatus
ImagesDistroless oder Minimal-Base-Images--
ImagesMulti-Stage Builds, keine Build-Tools im Runtime--
ImagesImage-Signing mit Cosign--
DateisystemreadOnlyRootFilesystem: true--
DateisystemEmptyDir fuer tmp und Cache--
ZugriffNo-SSH-Policy dokumentiert--
Zugriffkubectl exec per RBAC eingeschraenkt--
ZugriffBreak-Glass-Prozess definiert--
DeploymentGitOps-only (Flux oder ArgoCD)--
DeploymentKein manuelles kubectl apply--
SecurityPod Security Standards: restricted--
SecurityCapabilities: drop ALL--
ObservabilityLogs, Metrics, Tracing statt exec--

Fuer die Security-Audit-Perspektive auf diese Massnahmen: Kubernetes Security Audit.

Fazit

Immutable Infrastructure ist kein theoretisches Ideal, sondern eine praktische Notwendigkeit fuer sicherheitskritische Kubernetes-Umgebungen. Die Kombination aus Read-Only Root Filesystem, Distroless Images, No-SSH-Policy und GitOps-only Changes reduziert die Angriffsflaeche drastisch.

Der Einstieg erfolgt schrittweise:

  1. Sofort: readOnlyRootFilesystem fuer neue Deployments aktivieren.
  2. Kurzfristig: Bestehende Images auf Distroless umstellen.
  3. Mittelfristig: GitOps-only-Workflow einfuehren, manuelles kubectl apply abschaffen.
  4. Langfristig: kubectl exec per RBAC einschraenken, Observability-Stack ausbauen.

Jeder Schritt erhoet die Sicherheit, auch ohne die gesamte Kette sofort umzusetzen.


Wenn Sie Unterstuetzung bei der Einfuehrung von Immutable Infrastructure in Ihren Kubernetes-Clustern benoetigen, melden Sie sich gerne fuer ein unverbindliches Gespraech unter /kontakt.

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen