Cloud

Azure Container Apps : diagnostiquer l'egress sortant avant de changer le code

Un runbook de production pour qualifier les pannes de sortie Azure Container Apps en séparant DNS, UDR, NSG, NAT Gateway, firewall, identité, logs et rollback avant de modifier l'application.

21 juin 2026 azurecontainer-appsegressnat-gatewayudrdnsnsgkqlobservabilityrunbookrollback

Une application Azure Container Apps peut recevoir correctement le trafic entrant et échouer dès qu’elle appelle un service externe ou une dépendance privée. Le symptôme arrive souvent comme un timeout, un 403, une erreur TLS ou une file de retries. La tentation est de redéployer l’image, d’augmenter le timeout ou de changer une variable d’environnement. En production, il faut d’abord prouver le chemin sortant.

Le cas d’usage est une API hébergée sur Container Apps qui doit appeler plusieurs dépendances : une API partenaire publique autorisée par IP, Azure SQL ou Key Vault, un service interne derrière firewall, et un endpoint de télémétrie. L’environnement Container Apps est intégré à un VNet. Le trafic peut passer par une UDR, Azure Firewall, NAT Gateway, Private DNS ou des règles NSG. Le runbook vise une décision simple : corriger le réseau, ajuster une dépendance, rollbacker un changement d’infrastructure ou revenir au code seulement si le chemin sortant est sain.

Cartographier le chemin egress avant l’incident

Le trafic sortant Container Apps n’est pas seulement “Internet depuis le conteneur”. Selon l’environnement, il peut traverser un subnet délégué, une route forcée, une firewall policy, une NAT Gateway, une résolution DNS privée ou publique, puis la règle d’accès de la dépendance. Si ces pièces ne sont pas écrites, chaque équipe va diagnostiquer sa couche en parallèle.

text container-apps-egress-map.txt
Container app
Revision active, replicas, variables de configuration
Identite managée ou secret applicatif
Client HTTP, SDK ou connecteur utilise

Container Apps environment
VNet integration
Subnet dedie ou workload profile
DNS utilise par le runtime
Logs system et console

Routage Azure
Route effective vers Internet ou reseau prive
UDR vers Azure Firewall si force tunneling
NAT Gateway si IP sortante stable attendue
NSG sur subnet et reseaux intermediaires

Dependance appelee
FQDN, port, protocole et SNI attendu
Firewall, allowlist IP, Private Link ou endpoint public
Logs cote service, correlation ID et fenetre de test

Decision attendue
Chemin sain, corriger application
DNS incorrect, corriger resolver ou zone
Route/NSG/firewall bloque, corriger infrastructure
IP sortante instable, verifier NAT Gateway
Identite ou secret en echec, traiter l'authentification

Cette carte force une distinction utile : un timeout vers une API partenaire ne se traite pas comme un 403 Key Vault, et une erreur DNS ne se corrige pas avec un rollback applicatif.

Qualifier le symptôme par famille de panne

Avant de modifier une route ou un déploiement, classe le symptôme. Le même appel sortant peut échouer à la résolution DNS, à la connexion TCP, à la négociation TLS, à l’autorisation réseau ou à l’authentification applicative.

text egress-symptom-classification.txt
Symptome observe
no such host, ENOTFOUND, NameResolutionFailure
  Priorite: DNS, zone privee, forwarder, resolver, suffixe FQDN

timeout, connection refused, no route to host
  Priorite: UDR, NSG, Azure Firewall, port, service indisponible

TLS handshake failed, certificate verify failed
  Priorite: SNI, FQDN appele, inspection TLS, chaine de certificats

HTTP 403 ou denied by firewall
  Priorite: IP sortante, allowlist, Private Link, identite, policy service

HTTP 429 ou retries massifs
  Priorite: dependance saturee, retry policy, scale replicas, quotas

Erreur uniquement sur une revision
  Priorite: configuration revision, secret, variable, image ou SDK

Cette lecture évite un mauvais réflexe fréquent : ouvrir trop largement le firewall parce que le message d’erreur dit “access denied”, alors que l’identité managée ou le secret a simplement changé.

Prouver DNS et TLS depuis le même chemin que l’app

Le diagnostic doit partir d’un contexte proche du runtime. Un poste admin ou un runner CI hors VNet ne prouve pas le chemin Container Apps. Si l’application ne contient pas d’outil de debug, crée une révision temporaire ou un job Container Apps contrôlé, avec les mêmes contraintes réseau, pour tester uniquement la résolution et la connectivité.

bash 01-aca-egress-dns-tls-check.sh
TARGET_FQDN=api.partner.example.com
TARGET_PORT=443

getent hosts "$TARGET_FQDN" || nslookup "$TARGET_FQDN"

timeout 5 sh -c "cat </dev/null >/dev/tcp/$TARGET_FQDN/$TARGET_PORT" && echo "tcp_connect_ok=true" || echo "tcp_connect_ok=false"

openssl s_client -connect "$TARGET_FQDN:$TARGET_PORT" -servername "$TARGET_FQDN" </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer

curl -vk --connect-timeout 5 "https://$TARGET_FQDN/health" -H "x-correlation-id: aca-egress-check-$(date +%Y%m%d%H%M%S)"

Si le FQDN doit résoudre vers une adresse privée, vérifie explicitement la cible. Si le service partenaire attend une IP publique fixe, note l’adresse vue côté partenaire ou via un endpoint de diagnostic. L’information utile n’est pas seulement “ça marche” ; c’est “ça sort par le chemin prévu”.

Lire routes, NSG et NAT sans supposer le résultat

Quand Container Apps est intégré à un VNet, l’équipe réseau doit pouvoir répondre à trois questions : quelle route est appliquée, quelle règle autorise ou bloque, et quelle IP sortante est présentée à la dépendance. NAT Gateway est utile pour stabiliser l’IP, mais elle ne corrige pas une UDR qui envoie le flux au mauvais endroit ni une règle firewall trop restrictive.

bash 02-aca-egress-network-review.sh
RG=rg-prod-apps
ENV=aca-prod-weu
SUBNET_ID="/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-network-prod/providers/Microsoft.Network/virtualNetworks/vnet-prod/subnets/snet-aca-prod"

az containerapp env show --name "$ENV" --resource-group "$RG" --query '{name:name, infrastructureSubnetId:properties.infrastructureSubnetId, outboundType:properties.vnetConfiguration.outboundType}' --output table

az network vnet subnet show --ids "$SUBNET_ID" --query '{routeTable:routeTable.id, nsg:networkSecurityGroup.id, natGateway:natGateway.id, delegations:delegations[].serviceName}' --output json

# Completer avec Network Watcher, firewall logs et route table effective selon le design du subnet.
# L'objectif est de prouver le prochain saut et la regle qui accepte ou bloque le flux.

Les commandes exactes dépendent du type d’environnement et de l’outillage réseau disponible. Le point stable du runbook est la preuve : route table attachée, NSG attaché, NAT Gateway attachée ou absente, firewall traversé ou non, et dépendance qui voit la bonne IP.

Corréler les logs Container Apps et réseau

Pendant l’incident, les logs applicatifs seuls peuvent être trompeurs. Un SDK peut résumer DNS, TLS et HTTP dans une exception générique. Il faut lire les logs Container Apps avec les signaux réseau ou firewall sur la même fenêtre.

kusto 03-aca-egress-correlation.kql
let Window = 2h;
let App = "orders-api";
let Target = "api.partner.example.com";
let Console =
ContainerAppConsoleLogs_CL
| where TimeGenerated > ago(Window)
| where ContainerAppName_s == App
| where Log_s has_any (Target, "timeout", "ENOTFOUND", "403", "TLS", "retry", "connection")
| project TimeGenerated,
        Source="container-console",
        App=ContainerAppName_s,
        Revision=RevisionName_s,
        Message=Log_s;
let System =
ContainerAppSystemLogs_CL
| where TimeGenerated > ago(Window)
| where ContainerAppName_s == App
| where Log_s has_any ("revision", "replica", "probe", "scale", "failed")
| project TimeGenerated,
        Source="container-system",
        App=ContainerAppName_s,
        Revision=RevisionName_s,
        Message=Log_s;
Console
| union System
| order by TimeGenerated desc

Si Azure Firewall, NSG flow logs ou les logs de la dépendance sont disponibles, ajoute une requête parallèle avec le même correlation_id, la même IP source ou la même fenêtre. Une décision de correction doit s’appuyer sur au moins deux vues quand c’est possible : runtime et réseau, ou runtime et dépendance.

Séparer erreur réseau et erreur d’identité

Les dépendances Azure brouillent parfois la lecture. Un appel Key Vault, Storage, SQL ou Service Bus peut échouer parce que le réseau est fermé, parce que le DNS pointe au mauvais endroit, ou parce que l’identité managée n’a pas le droit attendu. Ouvrir le réseau pour résoudre une erreur RBAC crée une dette de sécurité inutile.

text dependency-decision-matrix.txt
Dependance Azure avec echec 403
Verifier d'abord:
  Le FQDN appele et sa resolution
  L'IP ou le chemin prive attendu
  Le firewall ou public network access du service
  L'identite reelle de la revision Container Apps
  Les logs d'audit du service cible

Decision
DNS faux
  Corriger zone, record ou forwarder, puis retester sans changer les roles

Firewall bloque avec identite correcte
  Corriger allowlist, private path ou NAT, puis garder preuve de l'IP source

Identite refusee avec reseau sain
  Corriger RBAC ou access policy, puis verifier qu'aucune ouverture reseau n'a ete ajoutee

Revision seule impactee
  Comparer secrets, variables, identity binding et image avant rollback

Cette matrice garde le changement minimal. Elle protège aussi le rollback : revenir à l’ancienne révision ne sert à rien si la firewall policy bloque toutes les révisions.

Décider correction, maintien ou rollback

Le runbook doit se terminer par une décision explicite, pas par une accumulation de contournements. Le rollback peut être applicatif, réseau ou dépendance selon la preuve.

text egress-decision-and-rollback.txt
Decision: corriger le reseau
DNS, route, NSG, firewall ou NAT explique le symptome
Le meme test passe apres correction
La dependance voit la source attendue
Aucun changement applicatif n'est necessaire

Decision: corriger l'application ou la configuration
DNS, route et connectivite sont prouves
L'erreur suit une revision, une variable, un secret ou une version SDK
Le rollback de revision restaure le service
Une correction code/config est ouverte avec preuve

Decision: rollback infrastructure
Une UDR, NSG, firewall policy ou NAT Gateway recente a change le chemin
L'impact depasse une seule application
Le retour arriere restaure la connectivite sans ouvrir large
Les logs de la fenetre sont conserves

Decision: maintien sous surveillance
Le flux est retabli mais la cause exacte reste partielle
Les logs et probes sont ajoutes
Une revue courte est planifiee avant le prochain deploiement

Le meilleur rollback est celui qui retire le dernier changement prouvé, pas celui qui semble le plus rapide. Si une UDR récente force tout le trafic vers un firewall qui ne connaît pas la destination, rollbacker la révision Container Apps ne fait que masquer l’analyse.

Conclusion

Diagnostiquer l’egress Azure Container Apps demande de traiter le trafic sortant comme un chemin de production complet. DNS, UDR, NSG, NAT Gateway, firewall, identité, logs runtime et journaux de dépendance doivent être lus avant de toucher au code.

La décision devient alors exploitable : corriger le réseau quand le chemin est faux, corriger l’application quand le chemin est sain, ou rollbacker l’infrastructure quand un changement récent a déplacé la sortie. Ce qui compte n’est pas seulement de rétablir l’appel sortant, mais de savoir par quel chemin il passe, quelle IP il présente et quelle preuve permettra de ne pas répéter l’incident.