Infrastructure

Déploiement Azure depuis un runner privé : diagnostiquer le pipeline avant de le relancer

Un runbook de production pour qualifier un échec de déploiement Azure lancé depuis un runner privé en séparant identité, DNS, routage, NSG, NAT, accès aux dépendances, logs et rollback.

22 juin 2026 azuredevopsgithub-actionsself-hosted-runneridentityoidcdnsroutingnsgnat-gatewaykqlautomationrunbookrollback

Un déploiement Azure peut échouer alors que le code applicatif n’a pas changé. Le pipeline lance le même template, le même script ou le même plan Terraform, mais depuis un runner privé placé dans un VNet, derrière un firewall, avec une identité fédérée ou managée, des accès Key Vault, un registry privé et parfois des endpoints de contrôle Azure filtrés. Relancer le job sans diagnostic peut masquer une panne réseau, consommer le quota de changement ou appliquer un rollback au mauvais endroit.

Le cas d’usage est un pipeline GitHub Actions ou Azure DevOps exécuté sur un runner privé. Il déploie une application Azure, lit des secrets, pousse une image, applique de l’infrastructure et déclenche une validation. L’objectif du runbook est simple : décider si l’échec vient du runner, de l’identité, du chemin réseau, de la dépendance appelée, du code de déploiement ou d’un changement déjà appliqué partiellement.

Fixer l’état exact du déploiement

Avant de relancer, il faut figer ce qui a réellement été exécuté. Un pipeline peut échouer avant authentification, pendant la lecture des secrets, au moment de joindre Azure Resource Manager, après un apply partiel ou pendant une validation post-déploiement. Ces états n’appellent pas le même rollback.

text deployment-state-record.txt
Etat a capturer
Run ID et commit deploye
Runner utilise, groupe et subnet
Identite Azure demandee
Etape exacte en echec
Ressources creees, modifiees ou non touchees
Correlation ID Azure ou client request ID
Dernier changement reseau, secret, role ou policy

Decision possible
Echec avant authentification: verifier federation, secret ou identite
Echec avant changement Azure: corriger chemin runner ou dependance
Echec pendant apply/deploy: qualifier etat partiel avant relance
Echec apres deploy: valider impact applicatif avant rollback

Cette trace protège contre le faux réflexe “rerun”. Si le premier passage a déjà modifié une route, une App Service config ou une image de conteneur, le deuxième passage peut aggraver le diagnostic au lieu de le résoudre.

Séparer runner, identité et autorisation

Un runner privé ajoute une confusion fréquente : l’erreur visible dans le pipeline mélange souvent le poste d’exécution, le jeton d’identité et les permissions Azure. Il faut prouver séparément que le runner est sain, que l’identité est bien celle attendue et que les droits correspondent à l’opération.

bash 01-runner-identity-check.sh
az account show --query '{tenant:tenantId, subscription:id, user:user.name}' --output json

az ad signed-in-user show --query '{id:id, userPrincipalName:userPrincipalName}' --output json 2>/dev/null || echo "No interactive user, check service principal, workload identity or managed identity"

az role assignment list --assignee "$AZURE_CLIENT_ID" --scope "/subscriptions/$AZURE_SUBSCRIPTION_ID" --query '[].{role:roleDefinitionName, scope:scope}' --output table

az deployment sub list --query '[0:5].{name:name, state:properties.provisioningState, timestamp:properties.timestamp}' --output table

Dans un modèle OIDC, vérifie aussi le sujet fédéré, l’environnement GitHub ou Azure DevOps autorisé, la branche et le workflow. Un 403 peut venir d’un rôle absent, mais aussi d’une fédération qui ne correspond plus au contexte du job.

Prouver le chemin réseau du runner

Le runner privé doit joindre plusieurs familles de cibles : Azure Resource Manager, Entra ID, Key Vault, Container Registry, backend Terraform, endpoint applicatif de validation et parfois une API interne. Un seul accès cassé peut faire échouer le déploiement.

text runner-network-map.txt
Runner prive
Subnet, NSG, route table, resolver DNS
Sortie Internet via NAT Gateway ou firewall
Proxy explicite ou inspection TLS

Cibles de deploiement
management.azure.com pour ARM
login.microsoftonline.com pour authentification
vault.azure.net pour secrets
*.azurecr.io pour images
backend state Terraform ou stockage d'artefacts
endpoint prive ou public de validation applicative

Preuves attendues
Resolution DNS depuis le runner
Connexion TCP/TLS avec le vrai FQDN
IP sortante observee par les services autorises
Regle firewall ou NSG qui explique autorisation ou blocage

Private Endpoint peut intervenir pour Key Vault, Storage ou ACR, mais il ne doit pas devenir le seul prisme du diagnostic. Le runner peut aussi échouer sur un endpoint public Azure, une allowlist partenaire, une UDR vers firewall ou une inspection TLS qui casse le flux.

Tester DNS, TLS et sortie sans toucher au déploiement

La relance du pipeline ne doit pas être le premier test réseau. Un job de diagnostic read-only, exécuté sur le même runner ou dans le même groupe, permet de vérifier les dépendances sans appliquer de changement.

bash 02-runner-network-probe.sh
for host in management.azure.com login.microsoftonline.com "$KEYVAULT_NAME.vault.azure.net" "$ACR_NAME.azurecr.io"
do
echo "== $host =="
getent hosts "$host" || nslookup "$host"
timeout 5 bash -lc "cat </dev/null >/dev/tcp/$host/443"   && echo "tcp_connect_ok=true"   || echo "tcp_connect_ok=false"
openssl s_client -connect "$host:443" -servername "$host" </dev/null 2>/dev/null   | openssl x509 -noout -subject -issuer
done

curl -sS --connect-timeout 5 https://ifconfig.me || true

Le résultat doit être comparé au design attendu : résolution privée ou publique, sortie par NAT Gateway, passage firewall, proxy, ou refus documenté. Une résolution “qui marche” n’est pas suffisante si elle sort par le mauvais chemin.

Lire les logs comme une chronologie

Un run de déploiement doit être corrélé avec les logs Azure et les journaux réseau quand ils existent. L’objectif n’est pas de collecter tous les signaux, mais de reconstruire l’ordre : authentification, lecture des dépendances, appel ARM, changement de ressource, validation.

kusto 03-deployment-correlation.kql
let Window = 2h;
let CorrelationId = "00000000-0000-0000-0000-000000000000";
AzureActivity
| where TimeGenerated > ago(Window)
| where CorrelationId == CorrelationId
 or Caller has_any ("github", "devops", "spn", "managedidentity")
| project TimeGenerated,
        OperationNameValue,
        ActivityStatusValue,
        ResourceGroup,
        ResourceProviderValue,
        ResourceId,
        Caller,
        CorrelationId,
        Properties
| order by TimeGenerated asc

Pour Key Vault, ACR, Storage ou firewall, ajoute une vue parallèle avec le même créneau horaire, l’identité du runner, l’IP source ou le client request ID. La bonne décision vient rarement d’un seul log de pipeline.

Décider relance, correction ou rollback

La relance est acceptable seulement si elle est idempotente et que la cause est comprise. Sinon, il faut corriger le chemin, réduire le périmètre ou rollbacker le changement partiel.

text pipeline-decision-matrix.txt
Relancer le pipeline
L'echec est transitoire et prouve
Aucun changement partiel dangereux
Le plan ou template reste identique
Les validations read-only passent depuis le runner

Corriger le runner ou le reseau
DNS, NSG, UDR, firewall, proxy ou NAT explique l'echec
Le deploiement n'a pas touche la ressource cible
Le test reseau passe avant nouvelle execution

Corriger identite ou autorisation
L'identite reelle est prouvee
Le refus vient de RBAC, federation OIDC, policy ou Key Vault
Aucun contournement reseau n'est ajoute pour masquer un 403

Rollbacker
Un changement partiel a modifie production
La validation applicative echoue
La relance risque d'elargir l'impact
Le retour arriere est plus sur qu'un deuxieme apply

Le point important est de ne pas confondre rollback du pipeline et rollback de production. Annuler un workflow ne retire pas une ressource déjà modifiée. Inversement, rollbacker l’application ne corrigera pas une fédération OIDC cassée ou une route runner mal appliquée.

Garder un mode de reprise borné

Après correction, la reprise doit rester contrôlée. Un pipeline de production devrait pouvoir rejouer une étape ciblée, lancer un plan sans appliquer, vérifier les dépendances depuis le runner et produire un résumé d’impact.

yaml safe-rerun-controls.yml
rerun_controls:
require_same_commit: true
require_plan_before_apply: true
require_runner_network_probe: true
allow_targeted_stage:
  - authenticate
  - validate_dependencies
  - plan
  - apply_scoped
  - post_deploy_checks
block:
  - apply_all_after_unknown_partial_failure
  - rotate_secret_during_network_incident
  - widen_firewall_without_correlation_id
rollback_record:
  include:
    - changed_resources
    - deployment_correlation_id
    - identity_used
    - validation_result

Ce mode de reprise transforme le pipeline en outil d’exploitation, pas seulement en bouton de déploiement. Il donne une trajectoire claire : prouver, corriger, rejouer avec limites, puis conserver l’évidence.

Conclusion

Un pipeline Azure exécuté depuis un runner privé est un composant de production. Il dépend d’un réseau, d’une identité, de routes, de DNS, de journaux et de services appelés pendant le déploiement. Quand il échoue, relancer immédiatement revient souvent à perdre l’information la plus utile.

Le runbook doit donc aboutir à une décision explicite : relancer si l’échec est compris et idempotent, corriger le runner ou l’identité si le chemin est faux, ou rollbacker si un changement partiel a touché la production. La qualité du déploiement ne se mesure pas seulement au succès du job, mais à la capacité de prouver ce qui s’est passé avant de relancer.