Leitfaden · 6. September 2026

Kubernetes Admission Control für Container-Images: was am Eingang zu prüfen ist.

Ein Validating Admission Webhook ist die eine Stelle, die jeder Pod passiert, bevor er läuft, gleich wer ihn angewendet hat. Dieser Leitfaden behandelt, was dieses Gate von einem Container-Image verlangen sollte, was zu tun ist, wenn es noch keine Antwort hat, und wie man prüft, ob es wirklich wirkt.

Warum am Eingang, nicht im Postmortem

Runtime-Sicherheit meldet Ihnen, dass sich ein Container um drei Uhr morgens seltsam verhält. Admission Control entscheidet, ob er überhaupt startet. Beide beantworten verschiedene Fragen, und die zweite lässt sich günstiger richtig beantworten: Bei der Admission wartet der API-Server ohnehin auf ein Ja oder Nein, die Image-Referenz steht direkt im Pod-Spec, und eine Ablehnung kostet ein fehlgeschlagenes Deployment statt eines Vorfalls.

Weil die Prüfung in der Admission-Kette des API-Servers sitzt, spielt es keine Rolle, wer anwendet – kubectl, Argo CD, Flux, ein Job, ein Operator, der seine eigene CRD reconciled. Jedes Pod-CREATE und -UPDATE außerhalb einer kurzen Liste ausgenommener Namespaces passiert denselben Webhook, und ein GitOps-Sync, der an einer Policy scheitert, meldet die Ablehnung als Fehler – genau dort, wo man sie lesen möchte.

Die fünf Prüfungen

Das sind die Fragen, die ein Image-Gate aus dem Pod-Spec und einem Scan-Cache beantworten kann, in der Reihenfolge, in der sich das Einschalten lohnt. Die ersten drei kommen ganz ohne Scanner aus.

  1. Tag-Hygiene. Ein veränderlicher Tag kann ändern, was läuft, ohne dass jemand deployt. :latest abzulehnen ist die kleinstmögliche Regel und die, die sich vom ersten Tag an am meisten lohnt.
  2. Registry-Allowlist. Alles, was nicht aus Ihren Registries kommt, wird direkt abgelehnt. Eine leere Liste erlaubt jede Registry, eine nicht leere lehnt alle anderen ab.
  3. Digest-Pinning. Drei Stufen: Tags erlauben, einen Digest bevorzugen, einen Digest verlangen. Einen Digest zu verlangen ist die stärkste Aussage darüber, was lief, und der strengste Rollout; die meisten Umgebungen beginnen mit „bevorzugen“ und verschärfen je Namespace.
  4. Schwachstellen-Schwellenwerte. Ablehnen bei jedem kritischen Befund, bei jedem hohen Befund oder ab einer Obergrenze für mittlere und niedrige. Das ist die Prüfung, die einen Scanner im Hintergrund braucht, und für sie ist der nächste Abschnitt entscheidend.
  5. Signaturen und Attestations. Eine verifizierte cosign-Signatur, eine SBOM-Attestation und eine Attestation des Schwachstellen-Scans verlangen und Attestations ablehnen, die älter als ein Höchstalter sind. Schalten Sie das ein, sobald Ihre Build-Pipeline sie tatsächlich erzeugt; vorher wird alles abgelehnt.

Über das Image hinaus kann dieselbe Prüfung den Workload betrachten: Privilegierte Container, hostPath-Mounts und Verwandtes sind Härtungsbefunde, und eine Policy entscheidet, ob sie zur Ablehnung, zu einer Warnung oder zu nichts führen.

Ein noch nie gescanntes Image

Ein Scan dauert Minuten, der API-Server wartet Sekunden. Ein Gate, das inline scannt, läuft also irgendwann in einen Timeout und reißt Deployments mit. Das tragfähige Design trennt beides: Ein Scanner füllt im Hintergrund einen Cache, und die Admission liest den Cache. Eine langsame Registry kann ein Deployment dann nicht verzögern.

Die Folge, über die Sie vor der Installation entscheiden müssen: Ein Digest, den noch niemand gesehen hat, hat noch kein Scan-Ergebnis. Es gibt zwei ehrliche Antworten, und in Attestkeep wählt das Policy-Feld admissionTiming eine davon:

  • Zulassen und scannen. Das unbekannte Image zulassen, den Scan sofort einreihen und bei jeder späteren Admission dieses Digests anhand des fertigen Berichts entscheiden. Einführungsfreundlich und die Voreinstellung: Nichts, was Sie am ersten Tag deployen, wird abgelehnt, nur weil es neu ist.
  • Ablehnen bis gescannt. Das unbekannte Image mit „a scan has been queued — retry shortly“ ablehnen und zulassen, sobald der Bericht vorliegt. Jedes Deployment eines neuen Digests kostet einen zweiten Versuch. Wählen Sie das für die Namespaces, die es verdient haben.

In beiden Fällen läuft der erste Scan eines neuen Digests im Hintergrund. Auf einem frischen Cluster kann er einige Minuten dauern – der Scanner lädt das Image, und die Schwachstellendatenbank ist noch kalt –, und bis er fertig ist, ist das Image unknown, nie compliant. Beide Einstellungen gibt es in jeder Attestkeep-Edition, auch in Community.

Fail-open oder Fail-closed

Die andere Grundsatzentscheidung betrifft nicht das Image, sondern das Gate selbst. Was soll der API-Server tun, wenn Ihr Webhook nicht antwortet? Kubernetes nennt das die failurePolicy des Webhooks, und keiner der beiden Werte ist immer richtig.

  • Ignore (Fail-open) hält den Cluster während eines Webhook-Ausfalls deploybar und hinterlässt eine Lücke: In diesem Zeitfenster wurde nichts geprüft. Eine Kontrolle, der man vertrauen kann, zeichnet dieses Fenster auf, statt stillschweigend ein sauberes Quartal zu zeigen.
  • Fail (Fail-closed) ergibt eine Kontrolle, die nachweislich nie eine Lücke hatte, bedeutet aber, dass ein Webhook-Ausfall Deployments stoppt. Das sind echte Kosten, und man wählt sie bewusst, abgesichert durch genügend Replicas und Monitoring.

Was während einer Lücke durchkam, läuft auch danach noch. Finden lässt es sich mit einem periodischen Abgleich: den beobachteten Image-Digest jedes laufenden Containers mit dem Admission-Ledger vergleichen und die ohne Entscheidung dahinter melden – oder stoppen und neu zulassen. Attestkeep liefert standardmäßig Ignore aus, zeichnet jedes Ausfallfenster für das Nachweispaket auf und führt diesen Abgleich stündlich durch.

Belegen, dass es wirkt

Ein Admission-Webhook, der unbemerkt nicht läuft, sieht genauso aus wie ein konformer Cluster. Das Erste nach der Installation eines Gates und nach jedem Upgrade ist deshalb, zuzusehen, wie es etwas ablehnt. Mit der Standard-Policy von Attestkeep ist der kleinste Verstoß der Tag :latest:

kubectl run enforcement-check --image=nginx:latest

Error from server: admission webhook "image-security.attestkeep.com" denied the request:
image security policy: nginx:latest: the :latest tag is blocked by policy

kubectl get pod enforcement-check
Error from server (NotFound): pods "enforcement-check" not found

Zwei Dinge fallen auf. Der Fehler kommt als Error from server: Die Ablehnung geschah in der Admission-Kette des API-Servers, nicht in einem Agent, der vielleicht gerade nicht lief. Und der Grund nennt die Regel; wer ihn in einem CI-Log liest, weiß, was zu beheben ist. Wurde der Pod stattdessen angelegt, prüfen Sie die üblichen Verdächtigen der Reihe nach: ein ausgenommener Namespace, eine Policy im Audit-Modus, ein Webhook im Fail-open, eine nie aktivierte Installation.

Protokoll führen

Eine Ablehnung ohne Aufzeichnung ist Durchsetzung ohne Nachweis. Zeichnen Sie Freigaben genauso auf wie Ablehnungen – ein Nachweis, der nur Ablehnungen auflistet, kann nicht zeigen, dass eine Kontrolle gewirkt hat –, und zeichnen Sie jede Entscheidung unter dem Hash der Policy auf, die sie getroffen hat. Dann ist „welche Regel galt, als das zugelassen wurde?“ eine Abfrage statt Archäologie in der Git-Historie.

Das ist der Teil, den kostenlose Werkzeuge nicht liefern, und der Teil, den ein Auditor tatsächlich liest. Attestkeep hasht jede Entscheidung beim Schreiben, versiegelt das Ledger unter signierten, verketteten Checkpoints und macht aus den Entscheidungen eines Zeitraums ein signiertes Nachweispaket, zugeordnet zu dem Kontrollkatalog, den Sie wählen. Wie dieses Ledger jede Manipulation erkennbar macht und wo genau seine Garantien enden, steht auf der Seite evidence trust model (auf Englisch).

Jede hier genannte Einstellung ist dokumentiert: Policies mit der Feldreferenz und direkt anwendbaren Beispielen, Admission für die beiden Grundsatzeinstellungen und Prove it is enforcing mit dem vollständigen Runbook. Die Community Edition ist kostenlos und enthält jede Prüfung auf dieser Seite.