CI/CD und Supply-Chain-Sicherheit
Sichere Delivery-Pipeline
Eine kleine Python-API, ausgeliefert nach DevSecOps-Art: Jede Änderung wird getestet und gescannt, das Image wird einmal gebaut, signiert und per GitOps ausgerollt, und der Cluster startet nur Images, die diese Pipeline signiert hat.
Auf einen Blick
- 6
- automatische Sicherheitsprüfungen
- 0
- gespeicherte Signaturschlüssel
- 1
- menschliche Freigabe für Produktion
- < 3 Min.
- vom Merge bis dev
Das Ziel
Viele Angriffe auf Software brechen heute nicht die App, sondern den Weg, wie sie gebaut und ausgeliefert wird: ein geleaktes Token, ein manipuliertes Image oder eine manuelle Änderung in Produktion. Das Ziel: ein Auslieferungssystem, in dem jeder Schritt automatisch, geprüft und nachvollziehbar ist, und in dem Produktion nur annimmt, was die Pipeline gebaut und signiert hat. Die App ist bewusst klein; der Wert liegt im System darum herum.
Was es zeigt
- Continuous Integration
- ruff (mit bandit-Regeln), pytest mit 90 % Coverage-Grenze, ein Smoke-Test des echten Containers.
- Shift-left-Sicherheit
- gitleaks für Secrets, Semgrep für den Code, Trivy und kubeconform für Dockerfile und Kubernetes-Dateien.
- Supply Chain
- Trivy-Image-Scan, Syft-SBOM (CycloneDX), cosign-Signatur ohne Schlüssel, SBOM-Attestation, SLSA-Build-Provenance.
- Auslieferung
- Kustomize-Overlays, das Image per Digest fixiert, Argo CD synchronisiert dev selbst, Produktion über einen geprüften Pull Request.
- Laufzeitsicherheit
- Pod Security „restricted“, kein root, schreibgeschütztes Dateisystem, keine Capabilities, seccomp, Default-Deny-Netzwerkregel.
- Admission Control
- Kyverno lässt nur Images zu, die dieses Repository signiert hat, und nur Pods mit Limits und Probes.
Architektur
Eine Änderung, vom Entwickler bis in den Cluster. Die Pipeline bekommt nie Zugang zum Cluster: Argo CD holt sich die Änderung aus Git.
Schritt für Schritt
Pull Request
Lint, Unit-Tests, Secret-Scan, SAST und IaC-Prüfungen laufen parallel. Das Image wird gebaut, getestet, gescannt und erhält eine SBOM. Noch wird nichts veröffentlicht.
Merge nach main
Dieselben Prüfungen laufen erneut. Das Image geht per Digest nach GHCR, wird mit cosign signiert (ohne Schlüssel, mit der GitHub-Identität) und erhält SBOM-Attestation und SLSA-Provenance.
Ausrollen nach dev
Die Pipeline schreibt den neuen Digest in das dev-Overlay. Argo CD sieht den Commit und synchronisiert dev selbst.
Freigabe für Produktion
Die Pipeline öffnet einen Pull Request für das prod-Overlay mit demselben Digest. Ein Mensch prüft und merged ihn: Dieser Merge ist das Release. Rollback = git revert.
Admission
Bevor ein Pod startet, prüft Kyverno die Signatur und die Identität der Pipeline sowie Limits und Probes. Alles andere wird abgewiesen.
Nachweis aus einem echten Lauf
Lauf auf dem Branch main am 2026-10-27, aus GitHub Actions. Dauer je Job:
- Lint and unit tests 12s
- Secret scan (gitleaks) 10s
- SAST (semgrep) 33s
- IaC and manifest checks 15s
- Build, scan, SBOM, sign 1m 53s
- Deploy to dev (GitOps commit) 4s
Diesen Lauf öffnen (opens in a new tab)
· deploy(dev): shop-api bf471203925f
Sicherheitskontrollen
| Kontrolle | Was sie verhindert |
|---|---|
| gitleaks in pre-commit und CI | Passwörter und Tokens in Git. |
| Semgrep SAST | Injection, unsichere Funktionen und schwache Kryptografie im Code. |
| Trivy-Image-Scan mit Grenze | Ausliefern bekannter kritischer Schwachstellen. |
| Digest statt Tag | Ein anderes Image hinter demselben Tag. |
| cosign ohne Schlüssel + Kyverno | Images, die die Pipeline nicht gebaut und signiert hat. |
| Pull-basiertes GitOps | Gestohlene CI-Zugangsdaten, die den Cluster erreichen. |
| Restricted Pods + Default-Deny-Netzwerk | Ausbruch und Ausbreitung von einem gehackten Pod. |
| Actions auf Commit-SHAs fixiert | Eine veränderte fremde Action in der Pipeline. |
Selbst ausprobieren
make install test # Python 3.12+: lint, tests, 90 % coverage gate
make run # http://127.0.0.1:8080/docs
docker compose up --build # the hardened container: read-only, non-root, no capabilities
make kind-up # local Kubernetes with ingress, Kyverno and Argo CD
# check the signature of a published image (keyless, GitHub OIDC identity)
cosign verify ghcr.io/s0sta/secure-delivery-pipeline@sha256:… \
--certificate-identity-regexp 'https://github.com/s0sta/secure-delivery-pipeline/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.comWas ich gelernt habe
- Faire Grenzen werden akzeptiert: Zuerst nur bei neuen kritischen Funden stoppen, dann die Messlatte Schritt für Schritt erhöhen.
- Eine Signatur zählt nur, wenn etwas sie prüft: Die Regel im Cluster ist die eigentliche Kontrolle.
- Ein echter CI-Lauf findet, was lokale Tests übersehen: ein gelöschtes Tool-Release, einen fehlenden Pfad, eine Repository-Einstellung.