Hook – Warum ein unsichtbarer Angreifer heute Ihre Produktions-Container übernehmen kann
Stellen Sie sich vor, Sie bestellen ein neues Smartphone, packen es aus und plötzlich fängt es an, E‑Mails an Ihre Kontakte zu senden. Der Schaden ist nicht nur technisch, sondern auch reputativ. Ähnlich funktioniert das heute in vielen CI/CD‑Pipelines: Ein manipuliertes Image, das Sie für gut gehalten haben, kann Ihre gesamte Infrastruktur kompromittieren. Und das passiert ohne dass jemand im Team ein falsches Docker‑File commitet – das Image wird unterwegs von einem Angreifer "infiziert". Die einzige Möglichkeit, solche Überraschungen zu verhindern, ist eine kryptografische Signatur, die vom Build‑ bis zum Produktions‑Node unverändert bleibt. Hier kommt Cosign ins Spiel, ein Open‑Source‑Tool von Sigstore, das das Signieren und Verifizieren von Container‑Images so einfach wie das Installieren einer App auf Ihrem Smartphone macht.
Was ist Cosign und wie funktioniert es? {#erklärung}
Cosign ist ein leichtgewichtiges CLI‑Tool, das Signaturen (und optional Attestations) für OCI‑Images erstellt. Das Besondere: Es benötigt keine komplizierten PKI‑Infrastrukturen. Stattdessen nutzt es Keyless Signing (über OpenID‑Connect) oder klassische Schlüsselpaare, die Sie selbst generieren können. Der Signatur‑Hash wird dabei in das Image‑Manifest geschrieben und kann später von jedem Tool (kubectl, crane, etc.) verifiziert werden.
Beispiel – Schlüssel‑Paar generieren
# Cosign installieren (Linux x86_64)
curl -sSL https://github.com/sigstore/cosign/releases/download/v2.2.3/cosign-linux-amd64 -o cosign
chmod +x cosign && sudo mv cosign /usr/local/bin/
# Schlüssel‑Paar in ~/.cosign erzeugen
cosign generate-key-pair
# → ~/.cosign/cosign.key (private) & ~/.cosign/cosign.pub (public)
Einschätzung
Für die meisten Unternehmen ist das Erzeugen eines lokalen Schlüsselpaars ein Win‑Win: Sie behalten die komplette Kontrolle über die privaten Schlüssel, während die Public‑Keys leicht in GitOps‑Repos oder Kubernetes‑Secrets verteilt werden können. Der Aufwand ist minimal, und Sie haben bereits den wichtigsten Baustein für eine belastbare Supply‑Chain‑Security.
Signing eines Docker‑Images – Der komplette Durchlauf {#signing}
Erklärung
Ein Image zu signieren bedeutet: Der Hash des Images wird mit Ihrem privaten Schlüssel verschlüsselt und als Annotation an das Image-Manifest angehängt. Jeder, der das Image später zieht, kann die Signatur überprüfen – vorausgesetzt, er kennt den zugehörigen Public‑Key.
Beispiel 1 – Signieren eines lokalen Image
# Build ein Beispiel‑Image
docker build -t ghcr.io/meinefirma/simple-app:1.0 .
# Signieren mit dem zuvor erzeugten Schlüssel
COSIGN_PASSWORD=geheimesPasswort \
cosign sign --key ~/.cosign/cosign.key ghcr.io/meinefirma/simple-app:1.0
Cosign legt danach ein neues Artifact ghcr.io/meinefirma/simple-app:1.0.sig an, das die Signatur enthält. Der Registry‑Eintrag wird automatisch aktualisiert, sodass docker pull das gleiche Image plus Signatur liefert.
Beispiel 2 – Keyless Signing (OIDC‑Token)
# Keine Schlüssel speichern – Cosign holt ein Kurzzeit‑Token von GitHub Actions
export COSIGN_EXPERIMENTAL=1
cosign sign ghcr.io/meinefirma/simple-app:1.0
Das Tool nutzt das OIDC‑Token des CI‑Runners, um eine Ephemeral Key zu erzeugen und das Image zu signieren. Die Public‑Key‑Information wird im Rekor‑Transparency‑Log veröffentlicht, sodass jede Vertrauenskette nachvollziehbar bleibt.
Beispiel 3 – Signieren in einer GitHub‑Actions‑Pipeline
name: Build & Sign Image
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build image
run: |
docker build -t ghcr.io/meinefirma/simple-app:${{ github.sha }} .
echo ${{ secrets.COSIGN_PASSWORD }} | docker login ghcr.io -u ${{ secrets.GHCR_USER }} --password-stdin
docker push ghcr.io/meinefirma/simple-app:${{ github.sha }}
- name: Sign image
env:
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
run: |
cosign sign --key ${{ secrets.COSIGN_PRIVATE_KEY }} ghcr.io/meinefirma/simple-app:${{ github.sha }}
Durch die Kombination von cosign sign und GitHub‑Secrets erhalten Sie eine end‑to‑end‑verifizierbare Lieferkette – sogar wenn das Image mehrmals in unterschiedlichen Registries repliziert wird.
Einschätzung
Der Unterschied zwischen klassischem Schlüssel‑Paar‑Signing und Keyless‑Signing liegt vor allem im Betriebskosten‑Modell: Wenn Sie bereits CI‑Runner mit OIDC‑Support besitzen, reduziert Keyless‑Signing Ihren Wartungsaufwand erheblich. Allerdings müssen Sie sich mit den Transparency‑Logs vertraut machen, um die Herkunft nachzuverfolgen. Für stark regulierte Branchen (z. B. Finanz‑ oder Gesundheitswesen) empfehle ich jedoch ein festes Schlüssel‑Paar, weil Audits klare Key‑Nachweise verlangen.
Verifikation – Wie Sie sicherstellen, dass nur signierte Images laufen {#verification}
Erklärung
Das eigentliche Sicherheits‑Gewinn‑Potential von Cosign entfaltet sich erst beim Verifizieren. Hierbei prüft das Tool, ob das Image eine gültige Signatur enthält und ob diese von einem vertrauenswürdigen Public‑Key stammt. In Kubernetes‑Umgebungen lässt sich das mittels Admission‑Controller automatisieren.
Beispiel 4 – Lokale Verifikation vor dem Pull
# Verifiziere das Image mit dem öffentlichen Schlüssel
cosign verify --key ~/.cosign/cosign.pub ghcr.io/meinefirma/simple-app:1.0
# Ausgabe: Verification succeeded for ...
Falls das Image manipuliert worden ist, bricht die Verifikation ab und das Pull‑Kommando schlägt fehl. Das ist ein einfacher, aber effektiver Schutzmechanismus für Entwickler‑Workstations.
Beispiel 5 – Kubernetes‑Admission‑Controller aktivieren
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: cosign-webhook
webhooks:
- name: cosign.sigstore.dev
clientConfig:
service:
name: cosign-webhook
namespace: cosign-system
path: /validate
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
admissionReviewVersions: ["v1"]
failurePolicy: Fail
Der Cosign‑Webhook prüft bei jedem Pod‑Erstellungs‑Request, ob das referenzierte Image eine gültige Signatur besitzt. Fehlt die Signatur, wird das Deployment abgewiesen – wie ein Türsteher, der nur Besucher mit Ausweis lässt.
Beispiel 6 – OPA‑Policy für Signatur‑Check
package cosign
default allow = false
allow {
input.review.object.spec.containers[_].image == "ghcr.io/meinefirma/simple-app:1.0"
signed := cosign.verify(image = input.review.object.spec.containers[_].image)
signed == true
}
Durch die Kombination von OPA (Open Policy Agent) und Cosign erhalten Sie granulare, deklarative Sicherheitsregeln, die nicht nur das Vorhandensein, sondern auch das Vertrauen in den Signierer überprüfen.
Einschätzung
Die Integration in Kubernetes ist kein Nice‑to‑have, sondern ein must‑have für Produktions‑Umgebungen. Einmal eingerichtet, schützt es automatisiert vor dem Einschleusen von kompromittierten Images. Der Aufwand ist am Anfang spürbar, aber die langfristigen Einsparungen – insbesondere durch vermiedene Incident‑Response‑Kosten – rechtfertigen die Investition voll und ganz.
Häufige Fehler und wie Sie sie umgehen {#fehler}
-
Privaten Schlüssel im Repository speichern – Viele Teams legen den privaten Schlüssel versehentlich in Git. Das führt zu sofortigem Schlüssel‑Leak.
- Lösung: Nutzen Sie Git‑Crypt oder SOPS, oder – noch besser – setzen Sie auf Keyless‑Signing, das keine persistente Private‑Key‑Datei erzeugt.
-
Signatur‑Verifikation vernachlässigen – Oft wird nur das Signieren, nicht aber das Verifizieren automatisiert.
-
Lösung: Binden Sie
cosign verifyin Ihre CI‑Jobs ein und setzen Sie einen Admission‑Controller durch.
-
Lösung: Binden Sie
-
Nicht‑Versionierung des Public‑Keys – Wenn Sie den Public‑Key aktualisieren, vergessen Sie die entsprechenden Deployments zu updaten.
- Lösung: Speichern Sie den Public‑Key als ConfigMap in Kubernetes und referenzieren Sie ihn in Ihrer Webhook‑Konfiguration. Aktualisieren Sie die ConfigMap via GitOps, sodass jede Änderung versioniert wird.
-
Fehlende Transparenz‑Logs – Ohne Rekor‑Log können Sie nicht nachvollziehen, wer wann signiert hat.
-
Lösung: Aktivieren Sie
cosign uploadzum Rekor‑Log und prüfen Sie regelmäßig die Einträge.
-
Lösung: Aktivieren Sie
Fazit und konkreter nächster Schritt {#fazit}
Cosign macht das Signieren und Verifizieren von Container‑Images zu einer alltagsnahen Praxis – kein übertriebenes PKI‑Projekt, sondern ein paar Zeilen Code, die Ihre Lieferkette von diesem Tag an immun gegen Manipulationen machen. Die drei wichtigsten Takeaways:
- Schlüssel‑Management: Entscheiden Sie, ob Sie permanente Schlüssel (Compliance) oder Keyless‑Signing (Bequemlichkeit) benötigen.
-
Automatisierte Verifikation: Integrieren Sie
cosign verifyin CI‑Pipelines und setzen Sie einen Admission‑Controller in Kubernetes ein. - Transparenz: Nutzen Sie Rekor‑Logs, um jede Signatur nachvollziehbar zu dokumentieren.
Konkreter nächster Schritt:
- Installieren Sie Cosign auf Ihrem Build‑Server (
curl … && chmod +x …). - Generieren Sie ein Schlüssel‑Paar (
cosign generate-key-pair) und speichern Sie das Private‑Key sicher (z. B. in HashiCorp Vault). - Passen Sie Ihre CI‑Pipeline an, um das Image nach dem Build zu signieren.
- Deployen Sie den Cosign‑Admission‑Webhook in Ihrem Kubernetes‑Cluster und testen Sie ihn mit einem unsignierten Image.
Wenn Sie diese vier Schritte innerhalb der nächsten zwei Wochen abschließen, haben Sie nicht nur Compliance, sondern auch Peace‑of‑Mind – und können sicher sein, dass Ihr nächstes Deployment tatsächlich das ist, was Sie gebaut haben.
Top comments (0)