Cloud

Azure ACR et AKS : vérifier la signature d’une image avant la promotion

Un runbook de production pour figer un digest ACR, vérifier sa signature Notation, borner la politique de confiance, promouvoir par digest et revenir en arrière sans désactiver le contrôle.

25 août 2026 azureacraksnotationnotary-projectcontainer-securitysupply-chaindevopsautomationguardrailsrunbookrollbackproduction

Une image peut être saine au scanner et rester impropre à la production. Le tag attendu peut avoir été déplacé, le build peut provenir d’un pipeline non approuvé, ou la signature peut être valide cryptographiquement mais émise par une identité qui n’a rien à publier dans ce repository. Dans ce cas, redéployer latest ou contourner le contrôle d’admission restaure peut-être le service, mais supprime précisément la preuve recherchée.

Le cas d’usage est un pipeline qui construit une API, pousse son image dans Azure Container Registry puis la déploie sur AKS. L’équipe veut autoriser la promotion seulement si le digest est immuable, si une signature Notation est présente, si elle respecte une politique de confiance bornée et si le même digest arrive réellement dans le canari. Le runbook doit aboutir à l’une de trois décisions : promouvoir, mettre en attente, ou revenir à la dernière politique de confiance connue sans accepter une image non vérifiée.

Figer le contrat de promotion

Ne commencez pas par la signature. Commencez par l’objet exact à autoriser. Un tag est une référence modifiable ; le digest est l’identité du manifeste OCI vérifié.

yaml image-promotion-contract.yml
artifact:
registry: acrprodweu.azurecr.io
repository: payments/api
candidate_digest: sha256:<candidate-digest>
source_pipeline_run: build-20260825.4
trust:
policy_version: prod-images-v7
registry_scope: acrprodweu.azurecr.io/payments/api
expected_publisher: x509.subject:<approved-subject>
controls:
verify_in_pipeline: true
deploy_by_digest: true
canary_namespace: payments-canary
admission_rollout: audit-before-enforce
decision:
promote_only_if:
  - digest resolved from the candidate tag
  - signature passes strict verification
  - publisher matches the approved identity
  - canary runs the verified digest
rollback:
last_known_good_digest: sha256:<previous-approved-digest>
last_known_good_policy: prod-images-v6

Conservez avec la demande de promotion le digest, l’exécution du pipeline, la version de la politique, l’identité attendue et la sortie de vérification. Sans ces éléments, un succès notation verify reste difficile à relier au déploiement réel.

Résoudre le digest avant toute vérification

Identifiez le manifeste associé au tag candidat, puis cessez d’utiliser le tag dans la suite du runbook. La commande d’inventaire varie selon la version de l’Azure CLI ; l’important est d’obtenir un digest depuis ACR et de le reporter dans une référence complète.

bash 01-resolve-candidate-digest.sh
ACR="acrprodweu"
LOGIN_SERVER="acrprodweu.azurecr.io"
REPOSITORY="payments/api"
TAG="build-20260825.4"

az acr manifest list-metadata --registry "$ACR" --name "$REPOSITORY" --query "[?contains(tags, '$TAG')].{digest:digest,tags:tags,created:createdTime,lastUpdate:lastUpdateTime}" --output table

CANDIDATE_DIGEST="sha256:<digest-returned-by-acr>"
IMAGE="$LOGIN_SERVER/$REPOSITORY@$CANDIDATE_DIGEST"
printf '%s
' "$IMAGE"

Bloquez la promotion si le tag pointe vers plusieurs résultats inattendus, si le digest diffère de la sortie du build ou si le manifeste a changé après l’étape de signature. Ne tentez pas de « réparer » cette divergence en signant a posteriori un digest dont la provenance n’est pas établie.

Distinguer présence et confiance

notation ls permet d’inspecter les signatures associées au manifeste. Leur présence ne prouve ni leur validité ni l’identité du signataire. C’est seulement un inventaire avant vérification.

bash 02-inspect-signatures.sh
az acr login --name "$ACR"

notation ls "$IMAGE"

# L'étape suivante doit utiliser une politique importée et versionnée.
notation policy show

Une absence de signature est un résultat exploitable : le candidat reste en attente et le pipeline de publication doit être corrigé. Elle ne justifie pas l’ajout immédiat d’un signataire générique ni le passage de la politique en mode permissif.

Borner la politique de confiance

Une politique utile restreint à la fois le repository, le niveau de vérification, le trust store et l’identité autorisée. Évitez * sur le scope et sur les identités dans la politique de production : cela transforme un contrôle d’origine en simple test de présence d’un certificat.

json trustpolicy.json
{
"version": "1.0",
"trustPolicies": [
  {
    "name": "payments-production",
    "registryScopes": [
      "acrprodweu.azurecr.io/payments/api"
    ],
    "signatureVerification": {
      "level": "strict"
    },
    "trustStores": [
      "ca:payments-builders"
    ],
    "trustedIdentities": [
      "x509.subject: <approved-subject>"
    ]
  }
]
}

Le certificat racine ou intermédiaire doit être installé dans le trust store par un mécanisme contrôlé, puis la politique doit être importée depuis une version relue. La vérification s’effectue ensuite contre la référence par digest.

bash 03-verify-candidate.sh
POLICY_FILE="trustpolicy.json"
EVIDENCE_DIR="promotion-evidence"

mkdir -p "$EVIDENCE_DIR"
notation policy import "$POLICY_FILE"
notation policy show > "$EVIDENCE_DIR/trust-policy.txt"

notation verify "$IMAGE" > "$EVIDENCE_DIR/notation-verify.txt" 2>&1

printf '%s
' "$IMAGE" > "$EVIDENCE_DIR/verified-image.txt"

Archivez ces preuves avec le commit GitOps ou la demande de changement. N’enregistrez pas seulement exit code 0 : le digest, la politique et l’identité vérifiée sont nécessaires pour expliquer la décision.

Qualifier un échec sans élargir la confiance

Un échec de vérification appartient généralement à l’une de quatre familles. Les séparer évite de remplacer un diagnostic par une exception globale.

text signature-failure-matrix.txt
Symptom                         Evidence to inspect                 Bounded action
No signature found               notation ls, build publication       fix signing stage; hold image
Signature invalid                digest, signature, certificate        reject candidate; rebuild
Identity not trusted             policy scope, X.509 subject           correct reviewed policy or signer
Registry access failed           ACR login, RBAC, network path         restore read access; retry verify
Certificate expired or rotated   chain, validity, trust-store version  deploy reviewed trust bundle

Never solve these failures by trusting every identity or deploying by tag.

Une rotation de certificat mérite une double validation : l’ancien et le nouveau trust bundle peuvent coexister pendant une fenêtre bornée, mais la nouvelle identité ne doit signer qu’après approbation. Le rollback porte alors sur la version du trust store, pas sur la désactivation complète de la vérification.

Mettre le gate dans le pipeline

Placez la vérification après le push et la signature, mais avant la modification du manifeste de déploiement. Le pipeline transmet un digest vérifié au dépôt GitOps ; il ne transmet pas un tag à résoudre plus tard dans le cluster.

yaml promotion-gate.yml
stages:
- build_and_push
- sign_digest
- verify_digest:
    inputs:
      - fully_qualified_digest
      - trust_policy_version
    outputs:
      - verification_evidence
      - verified_digest
    stop_conditions:
      - signature_missing
      - publisher_not_trusted
      - digest_changed
- prepare_gitops_change:
    image_reference: acrprodweu.azurecr.io/payments/api@sha256:<verified-digest>
- deploy_canary
- validate_or_rollback

Le compte qui signe et celui qui promeut ne devraient pas être confondus. Le premier atteste l’origine ; le second décide si cette origine et ce digest satisfont la politique de l’environnement. Cette séparation permet de révoquer une capacité sans rendre le registre inutilisable.

Déployer l’admission sans bloquer le cluster

La vérification dans le pipeline réduit le risque, mais elle ne couvre pas un déploiement manuel ou un autre contrôleur. Une politique d’admission peut vérifier les signatures au moment de créer le workload. Déployez-la d’abord sur un namespace ou un cluster de préproduction, en audit, avec des images signées et volontairement non signées.

L’expérience managée AKS Image Integrity s’appuie sur Ratify, Azure Policy et Gatekeeper, mais reste une fonctionnalité en préversion avec un effet d’audit seulement et des limites qui ne conviennent pas à une dépendance de production. Utilisez-la pour évaluer le signal. Pour un contrôle bloquant en production, choisissez un mécanisme supporté par votre organisation, testez sa disponibilité et gardez le gate CI/CD comme première barrière.

Le passage d’audit à enforcement exige quatre preuves : le vérificateur accède à ACR, le trust store est disponible, les workloads système sont explicitement traités et une panne du vérificateur a un comportement décidé. Un webhook qui échoue sans stratégie claire peut arrêter tous les déploiements, y compris le rollback.

Valider le canari par digest réel

Après la promotion, vérifiez la référence désirée et l’imageID remonté par le runtime. Le tag affiché dans un manifeste ne suffit pas.

bash 04-validate-canary-digest.sh
NAMESPACE="payments-canary"
DEPLOYMENT="payments-api"

kubectl rollout status --namespace "$NAMESPACE" deployment/"$DEPLOYMENT" --timeout=10m

kubectl get pods --namespace "$NAMESPACE" -l app=payments-api -o custom-columns='POD:.metadata.name,DESIRED:.spec.containers[*].image,RUNTIME:.status.containerStatuses[*].imageID,READY:.status.containerStatuses[*].ready'

kubectl get events --namespace "$NAMESPACE" --sort-by=.lastTimestamp

La validation fonctionnelle reste indispensable : disponibilité, erreurs, dépendances et métriques métier du canari. Une signature prouve l’intégrité et l’identité selon la politique ; elle ne prouve pas que le code se comporte correctement.

Décider promotion, attente ou rollback

Promouvez uniquement si la vérification stricte réussit, si le digest déployé correspond au digest vérifié et si le canari est sain. Mettez en attente si l’origine ne peut pas être démontrée, même si le scanner ne remonte aucune vulnérabilité.

Si une nouvelle politique bloque des images auparavant approuvées, revenez à la dernière version connue du trust store ou de la politique, puis revérifiez le même digest. Ne désactivez pas globalement l’admission. Si l’image elle-même régresse, déployez le dernier digest sain qui passe encore la politique actuelle. Ces deux rollbacks doivent rester indépendants.

Conclusion

La promotion d’une image ACR ne doit pas dépendre de la confiance accordée à un tag. Elle doit relier un digest immuable, une signature valide, une identité de publication approuvée, une politique versionnée et le digest réellement exécuté par AKS.

La sortie du runbook est nette : promouvoir avec des preuves, mettre le candidat en attente, ou restaurer une politique connue puis revérifier. Le rollback utile conserve le contrôle d’origine ; il ne transforme jamais l’urgence en permission de déployer une image non vérifiée.