Container & Kubernetes

Container härten: So bekommst du Docker und Podman sicher in den Griff

Die größte Angriffsfläche schleppt dein Basis-Image mit, nicht die Anwendung. Ein schlankes Image, ein nicht-privilegierter Benutzer und regelmäßige Scans erledigen den Großteil, lange bevor du an Laufzeit-Policies denkst.

4 Kapitel mit allen Befehlen
DevOps-Engineer erklärt einem Kollegen Container-Dashboards am Stehtisch
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Seit 1997 am Markt Präsenz & Live-Online 4,9 aus 503 Google-Bewertungen Auch Inhouse für dein Team
Worum es geht

Warum Härtung beim Container an anderer Stelle ansetzt als beim Host

Auf einem klassischen Server weißt du, wo du ansetzt: Dienste abschalten, nftables konfigurieren, SELinux im Enforcing-Modus betreiben, Updates einspielen. Bei Containern verschiebt sich ein großer Teil dieser Verantwortung nach vorne in das Image und nach hinten in die Runtime. Ein Image, das vor acht Monaten gebaut wurde, enthält den Patch-Stand von vor acht Monaten, unabhängig davon, wie gut der Host gepflegt ist. Und ein Container, der mit --privileged oder mit gemountetem Docker-Socket startet, hebelt die Isolation weitgehend aus, egal wie sauber das Image war.

Typisch sind immer wieder dieselben Muster. Der Prozess im Container läuft als root, weil das Basis-Image keinen USER setzt und niemand es nachgeholt hat. Als Basis dient ein vollständiges Distributionsimage mit Paketmanager, Shell und Build-Werkzeugen, obwohl die Anwendung ein statisches Binary ist. Secrets landen als ARG oder als Umgebungsvariable im Layer und lassen sich später aus dem Image herauslesen. Container hängen alle im Default-Bridge-Netz und können sich gegenseitig erreichen. Das Rootfs ist beschreibbar, Capabilities werden nicht reduziert, und ob ein Prozess zur Laufzeit plötzlich eine Shell startet, merkt niemand.

Der Druck kommt inzwischen nicht mehr nur aus dem Betrieb. NIS2 und der Cyber Resilience Act stellen Anforderungen an Schwachstellenmanagement und an die Nachvollziehbarkeit der Software-Lieferkette. Damit wird die Frage, welche Komponenten in welcher Version in einem ausgelieferten Image stecken, von einer Fleißaufgabe zu einer Nachweispflicht. Eine SBOM pro Build und ein reproduzierbarer Scan-Bericht sind dann keine Kür mehr.

Miniatur-Szene: Hafen mit gestapelten Containern, ein Kran hebt einen davon an, daneben ein Steuerrad
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt

Härtungskette vom Image bis zur Laufzeit

  1. 01 Basis-Image minimieren und pinnen
  2. 02 Build ohne Secrets, Multi-Stage
  3. 03 Scan und SBOM als Gate
  4. 04 Rootless und Capabilities reduziert
  5. 05 Admission-Policies im Cluster
  6. 06 Runtime-Erkennung und Alarme
Was du mitnimmst

Die Kette vom Basis-Image bis zur Laufzeit

Container-Härtung funktioniert nur als durchgehende Kette. Jede Stufe entfernt einen Teil der Angriffsfläche, und keine einzelne Stufe ersetzt die anderen. Die folgenden Schritte kannst du unabhängig voneinander einführen und schrittweise verschärfen.

Basis-Image klein und nachvollziehbar halten

Wähle ein minimales Basis-Image, distroless oder Alpine für kompilierte Anwendungen, ein schlankes Distributionsimage dort, wo du wirklich Systempakete brauchst. Baue mit Multi-Stage-Builds, damit Compiler und Build-Abhängigkeiten nicht im Endergebnis landen, und pinne Basis-Images per Digest statt per beweglichem Tag. Rebuilds gehören in einen regelmäßigen Rhythmus, sonst veraltet der Patch-Stand im Image still vor sich hin.

Nicht als root laufen und rootless betreiben

Setze im Dockerfile ein explizites USER mit einer festen UID und stelle sicher, dass die Anwendung ohne Schreibrechte im Systemverzeichnis auskommt. Auf Hostseite ist der rootless Betrieb der größere Hebel: Podman läuft rootless von Haus aus über User-Namespaces, Docker bietet den Rootless Mode an. Damit endet ein Ausbruch aus dem Container nicht direkt bei root auf dem Host.

Runtime-Optionen restriktiv setzen

Read-Only-Rootfs mit gezielten tmpfs-Mounts für Schreibpfade, alle Capabilities per --cap-drop ALL entfernen und nur die wirklich benötigten zurückgeben, no-new-privileges setzen, seccomp- und AppArmor- beziehungsweise SELinux-Profile aktiv lassen statt sie mit unconfined abzuschalten. Dedizierte Netze pro Anwendungsgruppe verhindern, dass jeder Container jeden anderen erreicht. Den Docker-Socket in einen Container zu mounten ist praktisch gleichbedeutend mit root auf dem Host.

Schwachstellen und SBOM in der Pipeline

Ein Scan im Build-Job liefert dir CVEs zu Betriebssystempaketen und Anwendungsabhängigkeiten, bevor das Image überhaupt in die Registry kommt. Trivy erzeugt in einem Durchlauf Scan-Ergebnis und SBOM im CycloneDX- oder SPDX-Format, prüft zusätzlich IaC-Dateien und Kubernetes-Manifeste und lässt sich über Exit-Codes und Schweregrad-Schwellen als Gate einsetzen. Wichtig ist eine bewusste Regel für unfixed CVEs, sonst gewöhnt sich das Team an rote Builds.

Policies statt Absprachen im Cluster

In Kubernetes hältst du die Härtung über Pod Security Admission und einen Policy-Engine wie Kyverno durch: kein privilegierter Pod, kein hostPath, kein hostNetwork, runAsNonRoot erzwungen, nur Images aus der eigenen Registry, idealerweise mit Signaturprüfung. Der Vorteil gegenüber Review-Absprachen ist, dass die Regel auch dann greift, wenn nachts jemand ein Manifest anpasst.

Erkennung zur Laufzeit

Statische Prüfungen sehen nicht, was im laufenden Betrieb passiert. Falco wertet Syscalls über ein Kernel-Modul oder eBPF aus und schlägt an, wenn in einem Container eine Shell gestartet wird, sensible Dateien gelesen werden oder unerwartete ausgehende Verbindungen entstehen. Entscheidend ist das Tuning der Regeln auf die eigenen Workloads, sonst ertrinkt das Team in Fehlalarmen und schaltet die Alarme irgendwann stumm.

Tutorial

Container absichern, vom Image bis zur Laufzeit

Container sind keine Sicherheitsgrenze im Sinne einer virtuellen Maschine, sie teilen sich den Kernel des Wirts. Absicherung passiert deshalb auf drei Ebenen: im Image, beim Start und zur Laufzeit. Dieser Teil geht alle drei durch.

01

Das Image ist die größte Angriffsfläche

Die meisten Schwachstellen in einem Container stecken nicht in deiner Anwendung, sondern in den Paketen des Basis-Images. Ein schlankes Image reduziert die Zahl der Befunde oft um eine Größenordnung.

Dockerfile, mehrstufig und schlank
# Stufe 1: bauen
FROM golang:1.23 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app ./cmd/server

# Stufe 2: nur das Ergebnis, kein Compiler, keine Shell
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /app /app
USER nonroot:nonroot
EXPOSE 8080
ENTRYPOINT ["/app"]

Ein Distroless- oder Alpine-Image ohne Shell nimmt einem Angreifer nach dem Einbruch die Werkzeuge. Ohne bash, curl und Paketmanager wird das Nachladen deutlich schwerer.

Images prüfen, bevor sie produktiv gehen
# Schwachstellen im Image
trivy image --severity HIGH,CRITICAL meinimage:1.4.2
grype meinimage:1.4.2

# Stückliste erzeugen (für CRA und Lieferkettennachweise)
syft meinimage:1.4.2 -o cyclonedx-json > sbom.json

# Dockerfile auf typische Fehler prüfen
hadolint Dockerfile

# In der CI: Build abbrechen bei kritischen Befunden
trivy image --exit-code 1 --severity CRITICAL meinimage:1.4.2

Die Stückliste ist keine Formalie mehr: Der Cyber Resilience Act verlangt für Produkte mit digitalen Elementen den Nachweis der verwendeten Komponenten.

02

Rechte beim Start begrenzen

Die Voreinstellungen der Laufzeitumgebungen sind auf Bequemlichkeit ausgelegt, nicht auf Sicherheit. Vier Optionen verändern das grundlegend.

Abgesicherter Start
podman run -d \
  --user 1000:1000 \
  --read-only --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  --cap-drop=ALL --cap-add=NET_BIND_SERVICE \
  --security-opt no-new-privileges \
  --memory 512m --cpus 1 --pids-limit 200 \
  --network app-netz \
  meinimage:1.4.2

--pids-limit wird oft vergessen und verhindert, dass ein Prozess im Container den Wirt durch eine Fork-Bombe lahmlegt. Die Speichergrenze schützt vor dem OOM-Killer, der sonst womöglich einen anderen Dienst trifft.

Was die Optionen bewirken

OptionWirkungKosten
--userkein root im ContainerAnwendung muss ohne privilegierte Ports auskommen
--read-onlynichts kann abgelegt werdenSchreibpfade müssen als tmpfs oder Volume benannt werden
--cap-drop=ALLkeine Kernel-Sonderrechteeinzelne Rechte gezielt wieder hinzufügen
no-new-privilegeskein Rechtegewinn über SUIDin der Regel keine
03

Rootless betreiben

Der wirksamste Einzelschritt: Läuft die Laufzeitumgebung selbst ohne Root, landet ein Ausbruch bei den Rechten eines unprivilegierten Kontos statt bei Root auf dem Wirt.

Podman rootless mit systemd
# UID- und GID-Bereiche für den Benutzer prüfen
grep meinapp /etc/subuid /etc/subgid

# Container als Quadlet beschreiben
# ~/.config/containers/systemd/meinapp.container
#   [Container]
#   Image=registry.intern/meinapp:1.4.2
#   PublishPort=8080:8080
#   ReadOnly=true
#   NoNewPrivileges=true
#   DropCapability=ALL
#
#   [Install]
#   WantedBy=default.target

systemctl --user daemon-reload
systemctl --user start meinapp

# Damit der Dienst auch ohne Anmeldung läuft
sudo loginctl enable-linger meinapp

Ohne enable-linger beendet systemd die Benutzerinstanz beim Abmelden, und der Container stoppt. Das ist der häufigste Stolperstein bei rootless Betrieb.

04

Laufzeit überwachen

Auch ein sauber gebauter Container kann zur Laufzeit auffällig werden. Zwei Werkzeuge geben dir dabei Sichtbarkeit.

Falco beobachtet Systemaufrufe und schlägt bei verdächtigem Verhalten an, etwa wenn in einem Container plötzlich eine Shell gestartet oder eine Datei in einem Systemverzeichnis geschrieben wird. Es stammt aus dem CNCF-Umfeld und lässt sich mit eigenen Regeln erweitern. Für Kubernetes-Umgebungen ergänzt eine Pod Security Admission das Ganze, indem sie Pods mit zu weiten Rechten gar nicht erst zulässt.

Beispielregel für Falco
- rule: Shell im Container gestartet
  desc: Interaktive Shell in einem Produktionscontainer
  condition: >
    container.id != host and
    proc.name in (bash, sh, zsh) and
    not container.image.repository in (registry.intern/wartung)
  output: >
    Shell im Container (user=%user.name container=%container.name
    image=%container.image.repository befehl=%proc.cmdline)
  priority: WARNING

Fang mit wenigen, klaren Regeln an. Ein Regelwerk, das hundert Meldungen pro Tag erzeugt, wird nach einer Woche ignoriert und ist dann wertlos.

Gut zu wissen

Häufige Fragen zu Container-Härtung

Noch etwas offen? Wir sind ohne Warteschleife für dich da.

Frag uns direkt
Ist Podman rootless sicherer als Docker?
Podman läuft standardmäßig rootless und ohne dauerhaften Daemon, deshalb ist der Standardfall dort strenger als bei Docker. Docker bietet mit dem Rootless Mode aber ein vergleichbares Modell an, sodass der Unterschied weniger im Werkzeug als in der gewählten Konfiguration liegt. Wichtiger als die Entscheidung zwischen beiden ist, dass du überhaupt rootless betreibst und den Socket nicht großzügig weitergibst.
Reicht ein Image-Scan aus, um Container abzusichern?
Nein, ein Scan zeigt bekannte Schwachstellen in Paketen und Abhängigkeiten zum Zeitpunkt des Scans, sagt aber nichts über Fehlkonfigurationen beim Start oder über Angriffe zur Laufzeit. Ein Container mit null CVEs kann trotzdem privilegiert laufen und den Host-Socket eingebunden haben. Der Scan ist eine Stufe der Kette, nicht die Kette.
Was bringt eine SBOM konkret?
Eine SBOM listet die Komponenten und Versionen, die in einem Image stecken, in einem maschinenlesbaren Format wie CycloneDX oder SPDX. Wenn eine neue Schwachstelle in einer verbreiteten Bibliothek bekannt wird, kannst du damit innerhalb von Minuten beantworten, welche deiner Images betroffen sind, statt jedes Image erneut zu bauen und zu durchsuchen. Für Nachweise im Rahmen von NIS2 und dem Cyber Resilience Act ist genau diese Auskunftsfähigkeit der Kern.
Wie viele Alarme erzeugt Falco am Anfang?
Mit dem Regelsatz aus der Standardinstallation sind zu Beginn viele Treffer normal, weil legitime Abläufe wie Init-Skripte, Debug-Zugriffe oder Backup-Jobs den generischen Regeln entsprechen. Der eigentliche Einführungsaufwand liegt darin, diese Fälle als Ausnahmen zu beschreiben und die Regeln auf die eigenen Workloads zuzuschneiden. Danach bleibt ein Alarmvolumen übrig, das ein Team tatsächlich bearbeiten kann.
Brauche ich SELinux oder AppArmor noch, wenn ich Container nutze?
Ja, denn beide wirken als zusätzliche Schicht genau dort, wo Namespaces und Capabilities nicht greifen. Container-Runtimes setzen für jeden Container ein eigenes Label beziehungsweise Profil, und dieses verhindert im Ausbruchsfall den Zugriff auf Host-Ressourcen. Wer die Profile mit unconfined abschaltet, um ein Mount-Problem schnell zu lösen, gibt genau diese Schicht auf.

Zuletzt geprüft am 26. Juli 2026.

Das sagen Teilnehmer

Echte Stimmen aus unseren IT-Kursen

Es war eine sehr gute Lernatmosphäre und der Trainer verstand sein Thema sehr gut.
Rückmeldung aus dem Kurs „SELinux Training: Grundlagen und Administration (SEL1)“
Sehr kompetenter Dozent der gut auf alle Fragen eingegangen ist.
Rückmeldung aus dem Kurs „Kubernetes Grundkurs“
Persönlich für dich da

Deine Ansprechpartner

Du bist dir nicht sicher, welcher Kurs oder welches Level zu dir passt? Wir beraten dich persönlich und kostenlos.

Yves Hoppe

Yves Hoppe

Weiterbildung & Beratung

Hilft dir, aus dem Linux-Programm den passenden Kurs oder Lernpfad zu finden.

Norbert Jansen

Norbert Jansen

Beratung & Inhouse

Plant mit dir Inhouse-Trainings, die exakt auf eure Systemlandschaft und Distributionen zugeschnitten sind.

Nächster Schritt

Container-Härtung mit uns durchgehen

Wenn du die Kette im eigenen Umfeld aufbauen willst, findest du bei cmt die passenden Bausteine: der Linux Container Workshop mit Docker und Podman für Grundlagen und Runtime-Optionen, die Trivy Schulung für Scans, SBOM und Pipeline-Gates, die Kyverno Schulung für Policies im Cluster und die Falco-Schulung für Runtime Security. Wer den Zertifizierungsweg gehen möchte, ist mit CKS oder LFS460 Kubernetes Security Fundamentals richtig. Alle Kurse gibt es als Präsenztermin, Live-Online oder als Inhouse-Variante mit deinen eigenen Images. Sag uns kurz, wo ihr heute steht, dann schlagen wir dir eine sinnvolle Reihenfolge vor.