DevSecOps-Projekte

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.

  • GitHub Actions
  • Python
  • Docker
  • Trivy
  • Semgrep
  • gitleaks
  • Syft
  • cosign
  • SLSA
  • Kustomize
  • Argo CD
  • Kyverno
  • Kubernetes

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.

From commit to production: checks, build, scan, sign, GitOps, admissionGitHub Actions (every change)Developerbranch + PRTests + lintruff · pytest ≥ 90 %SecretsgitleaksSASTSemgrepIaCTrivy config · kubeconformBuild + smoke testdocker · non-rootruns the containerScan + SBOMTrivy image (gate)Syft CycloneDXSign + attestcosign keyless (OIDC)SBOM + SLSA provenanceGHCRimage by digestsha256:…Git: overlays/devcommit by the pipelineGit: overlays/prodpull request + human mergecommit digestpromotion PRKubernetes clusterArgo CDpulls from Gitno CI credentialsKyvernosignature + identitylimits + probesshop-api podsrestricted PSAread-only, non-rootdefault-deny networkpull

Schritt für Schritt

  1. 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.

  2. 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.

  3. Ausrollen nach dev

    Die Pipeline schreibt den neuen Digest in das dev-Overlay. Argo CD sieht den Commit und synchronisiert dev selbst.

  4. 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.

  5. 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

KontrolleWas sie verhindert
gitleaks in pre-commit und CIPasswörter und Tokens in Git.
Semgrep SASTInjection, unsichere Funktionen und schwache Kryptografie im Code.
Trivy-Image-Scan mit GrenzeAusliefern bekannter kritischer Schwachstellen.
Digest statt TagEin anderes Image hinter demselben Tag.
cosign ohne Schlüssel + KyvernoImages, die die Pipeline nicht gebaut und signiert hat.
Pull-basiertes GitOpsGestohlene CI-Zugangsdaten, die den Cluster erreichen.
Restricted Pods + Default-Deny-NetzwerkAusbruch und Ausbreitung von einem gehackten Pod.
Actions auf Commit-SHAs fixiertEine 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.com

Was 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.
Nächste Fallstudie Azure-k3s-Plattform