Container Images sind unsicher#
Öffentliche, häufig genutzte Images haben hunderte CVEs, die von Paketen kommen, von denen du 90 Prozent überhaupt nicht brauchst (Sysdig 2023 Report: Nur 15 % der kritischen CVEs befinden sich in Paketen, die zur Laufzeit geladen werden). Wichtig: Nicht jede gefundene CVE ist auch tatsächlich ausnutzbar — viele betreffen Pakete, die im Image liegen, aber nie ausgeführt werden.
Sind deine Container Images sicher?
Über 80 Prozent der Images in Produktionsumgebungen haben hohe und/oder kritische Sicherheitslücken (Sysdig 2023 Cloud-Native Security Report, Datadog State of DevSecOps 2024). Die Hauptursache ist meistens nicht die Applikation selbst, sondern liegt in der Base-Image-Schicht, also debian-slim, Ubuntu oder andere.
Nehmen wir das Image debian:12-slim:
- Größe: 28 MB
- Syft SBOM (Software Bill of Materials): 88 Pakete
- Trivy: 4 Critical, 17 High, 57 Medium
- Grype: 7 Critical, 17 High, 50 Medium
Nehmen wir eine aktuellere Version - trixie-slim:
- Größe: 29 MB
- Syft SBOM: 78 Pakete
- Trivy: 3 Critical, 18 High, 52 Medium
- Grype: 7 Critical, 19 High, 45 Medium
Vergleichen wir das mit einem glibc-based Image, Wolfi, das von Chainguard maintained wird:
- Größe: 7 MB
- Syft SBOM: 15 Pakete
- Trivy: 0 Critical, 2 High, 10 Medium
- Grype: 2 Critical, 18 High, 10 Medium
Brauchst du kein glibc, ist Alpine Linux eine der besten, wenn nicht die beste Alternative. Hinweis: Alpine nutzt musl statt glibc — manche Python-Libraries (z.B. numpy, pandas, cryptography) kompilieren unter musl nicht oder nur mit zusätzlichem Aufwand.
- Größe: 3.8 MB
- Syft SBOM: 16 Pakete
- Trivy: 0 Critical, 0 High, 0 Medium
- Grype: 0 Critical, 0 High, 3 Medium
Das lässt sich beliebig weiterführen mit Minimal-Images, wie Distroless, Minimal usw.
Stand: 16.07.2026 - 15:00 Uhr — CVE-Zahlen sind Momentaufnahmen und können sich durch Updates der Images oder der Scanner-Datenbanken jederzeit ändern.
Das Windows aus der Container Welt#
Das Problem sind nicht die Base-Images selbst und erst recht nicht die Distribution. Debian ist hervorragend und ich liebe es, da es eines der wenigen alleinstehenden Open Source Projekte ist, das wirklich souverän genutzt werden kann.
Es sind die Abhängigkeiten, darunter transitive, im Image, die nicht genutzt, aber auch nicht aus dem Image entfernt werden.
Beispiel#
Nehmen wir das Image python:3.14.6-trixie:
python:3.14.6-trixie:
137 critical, 562 high, 608 medium, 134 low, 930 negligible (219 unknown)
python:3.14.6-slim:
7 critical, 23 high, 53 medium, 5 low, 53 negligible
python:3.14.6-alpine:
0 critical, 3 high, 8 medium, 0 low, 0 negligible
cgr.dev/chainguard/python:3.14.6 (Chainguard Partner-Image, kostenpflichtig):
0 critical, 0 high, 2 medium, 0 low, 0 negligible
Stand: 03.08.2026 - 16:00 Uhr — CVE-Zahlen sind Momentaufnahmen und können sich durch Updates der Images oder der Scanner-Datenbanken jederzeit ändern.
Zwischenstand#
Auch die “großen”, öffentlichen Image Repos bieten mittlerweile gute Alternativen zum Standard-Image, wie Alpine oder slim. Nur durch die Nutzung von Python-Slim oder Python-Alpine sind die Pakete von knapp 480 auf 95 bzw. 38 (Alpine) geschrumpft.
Alleine durch das geringere Paketaufkommen werden einige überhaupt nicht “mitinstalliert”.
Wichtig ist eine schmale Basis zu wählen und diese danach nicht aufzupumpen –> Alpine, Slim oder Distroless. Letzteres enthält keine Shell, was Debugging erschwert — dafür reduziert es die Angriffsfläche auf ein Minimum.
Denn viele Teams nutzen die Base Images und packen anschließend Zusatzpakete für ihre eigene Applikation hinein. Genau hier folgt das nächste Problem. Wer auf die Base Images baut, muss das Wissen und die Zeit haben, die Images zu überprüfen und nicht verwendete Pakete zu filtern.
Images altern schneller als Menschen#
Wer glaubt, mit einer guten Basis und wenigen Paketen wäre alles getan, merkt nach einer Woche, dass die CVE-Findings steigen und es zu einem Folgeproblem wird – deine Pakete werden Eltern, Großeltern, und irgendwann solltest du sie gehen lassen.
Deshalb solltest du Images entweder täglich, aber besser stündlich, aktualisieren.
Hier gibt es 3 grundlegende Optionen:
- Mutable Tags (oder auch Floating Tags)
- Immutable Tags
- Digest Pinning
Mutable Tags sind Image Tags, also z.B. python:3.14.6, hinter denen sich das Image ändern kann (siehe Docker Docs: Image Tags). Das passiert, wenn der Maintainer das Image aufgrund von Fixes für Sicherheitslücken aktualisiert und das Tag updatet. In sicheren Produktivumgebungen willst du das nicht nutzen, da die Eindeutigkeit des Images nicht gewährleistet ist. Für Security Updates durch eine vorherige Automationsschicht jedoch sehr gut nutzbar.
Immutable Tags sind das Gegenteil. Diese nutzen Maintainer, um ein Image auf eine Version zu pinnen. Sowas wäre z.B. python:3.14.6-r4. Diese Image Tags erhalten keine Updates und der Konsument erhält dauerhaft, hoffentlich (dazu komme ich gleich), dasselbe Image.
Jetzt zu dem hoffentlich. Immutable Tags sind nicht unveränderbar. Es ist nur eine Vorgabe oder ein Prozess. Ein Angreifer kann das Immutable Tag trotzdem ändern und dein Cluster erhält ein verändertes Image, weil du dem Tag Vertrauen geschenkt hast. Dabei merkt das System, das das Image empfängt, erstmal nichts.
Digest Pinning ermöglicht dir genau diese Vertrauensschicht nicht zu benötigen. Du pinnst das Image auf einen Digest, also einen SHA-Hash, der einmalig für jeden Image Upload ist (siehe Docker Docs: Content Trust). Z.B.: python@sha256:ac7e69ab65032e9db6d4699b8aab8a0d7c052ef45f5ad3a4b0d905df5fc55fb4. Bedeutet aber auch, dass du regelmäßig diese Hashes gegen aktuelle tauschen musst.
Die Lösung#
Erstmal ist es wichtig, Digest Pinning zu nutzen und durch Richtlinien zu gewährleisten, dass jedes Image den Digest anstelle von Image Tags nutzt –> Hier hilft OPA oder Kyverno. Kyverno bietet dafür vorgefertigte Policies an, die sich direkt in bestehende Kubernetes-Cluster integrieren lassen — der Einstieg ist damit einfacher als mit OPA.
Anschließend kümmerst du dich mit Tools wie Renovate oder Dependabot darum, dass eine Pipeline läuft, die Image Tags oder Digests auf Aktualisierungen prüft. Dieser Admission Controller kann durch Policies zudem Signaturen, CVE-Grenzwerte, Whitelists von sicheren Registries und vieles mehr erzwingen (z.B.: https://main.kyverno.io/policies/other/verify-image-ivpol/verify-image-ivpol/).
Wichtiger Unterschied: Renovate kann Docker-Image-Digests automatisch aktualisieren, Dependabot unterstützt aktuell nur Image-Tags, keine Digests (Stand: 10.08.2026). Wird ein Update gefunden, erzeugt das Tool einen PR im Git-Repository mit der aktuellen Version und einer Digest-Änderung im jeweiligen YAML-Manifest. Deine Aufgabe ist es, den Digest zu prüfen.
Image-Scanning - Aber vorher#
Kurzer Einschub der Vollständigkeit halber: Es ist wichtig, Images vor der Nutzung auf Docker- oder Kubernetes-Hosts zu scannen. Entweder aus der CI/CD-Pipeline heraus (also Tekton, Gitlab, usw.) oder direkt in einer privaten Registry (Harbor, Nexus, Artifactory, Gitlab CR). Durch diese Methodik wird vermieden, dass Sicherheitslücken bereits bestehen. Gleichzeitig gibt sie der Automatisierung oder Administratoren die Möglichkeit, das Image noch einmal zu überprüfen und anschließend mit Sicherheitsupdates neu zu bauen.
Sobald das Image (je nach Unternehmenspolicy, oft: Alles über hoch ist böse) den Sicherheitsanforderungen entspricht, darf es vom Cluster geladen werden. Dazu gibt es in vielen privaten Registries Einstellungen, die ein Pulling ab bestimmten CVE-Schwellenwerten verbieten.
Ähnliches gilt für Software Bill of Materials (SBOM) — die Zutatenliste unseres Images. Ein SBOM sollte bei jedem Image erstellt und sicher gespeichert werden. Eine Archivierung ist, je nach Einsatzzweck, ab Ende 2027 durch den Cyber Resilience Act sogar Pflicht. Tools wie Syft oder Trivy helfen mit einem Einzeiler dabei: syft python:3.11. SBOMs sind wichtig, da sie nachweisen, welche Pakete, Libraries oder Binaries enthalten waren und dementsprechend nachgewiesen werden kann, ob ein System von einer Sicherheitslücke betroffen ist oder war.
Optimalerweise scannst du im Cluster oder auf dem Docker-Host kontinuierlich, mit aktueller CVE-Datenbank (Standard: 6-Stunden-Updates).
Die Herkunft verifizieren#
Da nun aktuelle Images alle paar Stunden neu gebaut werden, um Sicherheitsupdates einzupflegen, wurde dieser Prozess selbstverständlich bereits automatisiert. Die Digests finden Einzug in die Manifests und es ist das Image, das du haben wolltest.
Doch eines fehlt: Die Herkunft. Weißt du, von wem das Image stammt? Na klar! Vom Docker Hub oder der GitHub Container Registry. Die Repos sind Trusted! (Anmerkung: Docker Hub bietet ein „Trusted Content"-Programm an, das Verified Publisher und Docker-Sponsored OSS-Images auszeichnet — was aber keine kryptographische Verifizierung der Image-Inhalte bedeutet.)
Du willst verifizieren, dass das Image, das du herunterlädst, von einer nachweisbar vertrauenswürdigen Quelle stammt. Das erreichst du mit Image Signaturen. Der Maintainer, z.B. die Debian Community, stellt den Public-Key zur Verfügung, der zum Private-Key gehört, mit dem das Image signiert wurde. Die Signatur des Images wird in der OCI-Registry neben dem Image abgelegt (siehe OCI Image Specification). Wenn du das Image herunterlädst, kannst du zusätzlich die Signatur überprüfen, indem du den Public-Key nutzt. Das geht z.B. durch gängige private Registries oder Pipeline-Tools. Das verbreitetste Tool dafür ist Cosign aus dem Sigstore-Projekt, das Keyless-Signing und Transparency-Logs bereitstellt. Es ist der De-facto-Standard für Container-Signing geworden. Der letzte Punkt sollte eine Richtlinie innerhalb von Kubernetes sein, die die Signatur des Images überprüft.
Ab diesem Zeitpunkt kannst du sicher sein, dass ein sicheres, aktuelles, verifiziertes Image gepullt wurde.
–> Bis neue Sicherheitslücken auftauchen.
Wer tiefer eintauchen möchte: Reproduzierbare Builds, also das Erstellen desselben Images aus demselben Source Code, sind die nächste Stufe. Ich werde eventuell explizit über Image Buildprozesse in einem weiteren Artikel schreiben.
Verifizierbare, Minimale, freie Images#
Woher bekommst du nun solche Images?
Die Antwort ist nicht einfach. Es gibt bereits einige freie Lösungen, die aktuelle, sichere und freie Images anbieten.
Red Hat bietet mit Project Hummingbird seit einigen Monaten Images an.
Chainguard bietet als Basis das Wolfi-Image (Server Standort leider USA): github.com/wolfi-dev. Chainguard Images gibt es als kostenlose Dev-Variante und als kostenpflichtige Production-Variante mit Support.
Debian Slim als OSS Alternative: hub.docker.com/_/debian
Alpine-basierte Images: hub.docker.com/_/alpine
Distroless von Google: GoogleContainerTools/distroless
Ein auf MIT-Lizenz basiertes, mit dem Chainguard Toolset (Wolfi, Melange und Apko) erstelltes alternatives Image-Angebot: rtvkiz/minimal
Fazit#
Sichere Container-Images beruhen auf drei Säulen:
- Minimale Base-Images — weniger Pakete, weniger Angriffsfläche.
- Aktualisierte Digests — regelmäßig erneuert und per Richtlinie erzwungen.
- Verifizierte Herkunft — Image-Signaturen, die nachweisbar bestätigen, wer das Image gebaut hat.
Fehlt eine dieser Säulen, bleibt ein Angriffsvektor offen. Die Tools dafür sind da — es fehlt meist an der Umsetzung.
Und genau da liegt das Problem. Die meisten Teams machen bei Step 1 halt. Ein schlankes Base-Image gewählt, ein paar CVEs mitigiert, fertig. Das ist aber nur der Anfang. Digest Pinning und Image Signing sind kein Nice-to-have, sondern das, was aus einem schlanken Image ein sicheres Image macht. Ohne Digest weißt du nicht, ob sich das Image über Nacht geändert hat. Ohne Signatur nicht, wer es gebaut hat.
Quick Wins? Fang mit Digest Pinning und Renovate an. Das lässt sich in einem Nachmittag umsetzen und schließt den größten Angriffsvektor. Image Signing anschließend.
Container Security ist kein Projekt, das du abschließt. Es ist ein Prozess — neue CVEs erscheinen täglich, Base-Images ändern sich. Du bist damit nie fertig. In der DevOps-Welt kommen schnell Veränderungen, und mit jeder Veränderung auch Prozesse und Sicherheitsaktualisierungen, die du beachten musst.
Deshalb MUSS automatisiert werden.
Souveräne Images?#
Ich bereite einen Blog-Beitrag über souveräne Images vor. Wie die Lage in der EU ist und welche Images du souverän nutzen kannst – und was das für uns alle bedeutet.
#
Hinweis: Die CVE-Zahlen in diesem Beitrag wurden mit den jeweils aktuellen Versionen von Syft, Trivy und Grype zum genannten Stand ermittelt. Ergebnisse können je nach Scanner-Version und Datenbank-Stand abweichen.