CI · Quality
Qualité & hygiène du dépôt
Avant de parler « sécu image », je m’assure que le Dockerfile et les
assets de démo sont sains. Sur ce kit static : Hadolint, présence de
app/index.html / nginx.conf, build Docker local,
probe HTTP /health. Sur une app Node (ZENORA) : lint,
typecheck, tests, coverage, build.
Pourquoi : un Dockerfile pourri ou un healthcheck mort
ne doit pas arriver jusqu’à la signature. Sonar Community sans
sonar.branch.name — les flags PR/branch cassent l’édition gratuite.
CI · Secrets
Gitleaks — secrets dans le repo
Scan du tree avec Gitleaks en conteneur éphémère. Pas de token Harbor,
pas de clé SSH qui se balade dans un commit « oublié ».
Pourquoi : la supply chain commence dans Git. Un secret
commité reste un incident même si l’image est parfaite.
Security · SAST / SCA
Trivy filesystem + config, CodeQL
Trivy gate HIGH/CRITICAL sur le filesystem et la config
IaC/Compose/Dockerfile (unfixed ignorés volontairement — je ne bloque pas
sur ce que le vendor n’a pas encore patché). SARIF poussé vers l’onglet
Security GitHub.
CodeQL security-extended : sur ce repo static
il n’y a pas de JS applicatif — j’analyse le langage actions
(workflows). Sur ZENORA : javascript-typescript.
Pourquoi : SAST sur le code/workflows + SCA/config avant
même de builder l’image runtime. CodeQL mal calibré (JS sur un repo sans JS)
fait échouer le gate pour de mauvaises raisons — autant scanner ce qui existe.
Security · DAST
OWASP ZAP baseline
Baseline ZAP en cron hebdo + workflow_dispatch, mode
-I (informational) pour ne pas casser le gate sur du bruit
edge/Cloudflare. Rapport HTML/JSON en artifact.
Pourquoi : DAST sur une URL réelle complète la vue
« code + image ». Je ne veux pas qu’un faux positif WAF fasse croire
que la supply chain est rouge chaque lundi.
Release · Build
Build local, push : false
Buildx charge l’image en local (supply-chain-web:ci-candidate).
Aucun push Harbor tant que le scan image n’est pas vert.
C’est non négociable : le registry n’est pas une poubelle de candidats.
Release · Image gate
Trivy image HIGH/CRITICAL
Scan vuln + secret + misconfig sur l’image candidate. Échec = pas de tag
sha-* dans Harbor. SARIF image uploadé aussi.
Pourquoi : scanner le Dockerfile ne suffit pas. La surface
runtime (nginx alpine + packages) est ce que vous exposez vraiment.
Release · Registry
Push Harbor + digest immuable
Push sha-<7 chars> (+ latest sur main comme
alias pratique, jamais utilisé pour le deploy). Digest résolu via
RepoDigests locaux après push — pas de crane digest
GET qui se fait jeter par une policy Cosign Harbor (HTTP 412).
Release · Sign & SBOM
Cosign keyless, SBOM SPDX, provenance
Cosign keyless OIDC GitHub Actions (Fulcio / Rekor) —
pas de clé privée à rotater dans les secrets pour la démo. Signatures sur
REPO@DIGEST. SBOM SPDX via Anchore/Syft attaché à l’image.
Provenance build : GitHub Attestations (push-to-registry: false
— Harbor 412 sur upload OCI d’attestations).
Pourquoi keyless : identité = workflow GitHub + OIDC.
Auditable, pas de PEM Cosign qui fuit. Pourquoi SBOM :
inventaire exploitable le jour du prochain CVE nginx/openssl.
Deploy
Verify → SSH mux → runtime → smoke
1) cosign verify sur le digest avant toute ouverture SSH.
2) Une session SSH ControlMaster (UFW limit + scp/ssh
en rafale = timeouts — déjà vécu).
3) Image : pull @sha256, ou docker load de l’artifact
release-image si Harbor Cosign policy bloque le pull (412).
4) Health /health, rollback avec preuve, smoke sur le réseau
Docker du reverse proxy (pas seulement HTTPS public — Cloudflare peut 403).