Networking

Azure App Service : valider le routage VNet de tout le trafic avant la bascule en production

Un runbook de production pour valider le routage VNet de tout le trafic App Service entre appels applicatifs, image pull, stockage de contenu, sauvegarde, identité managée, preuves firewall et rollback.

14 sept. 2026 azureapp-servicevnet-integrationoutbound-routingudrnsgazure-firewallmanaged-identityobservabilityautomationrunbookrollbackproduction

Une application App Service joint déjà une API privée avec VNet Integration. L’équipe réseau veut maintenant faire passer chaque flux sortant par le subnet d’intégration et son chemin d’egress contrôlé. Activer outboundVnetRouting.allTraffic ressemble à un changement de routage unique. Cette propriété déplace aussi le trafic de configuration : extraction d’image conteneur, accès au partage de contenu, opérations de sauvegarde et acquisition de jetons d’identité managée.

L’application peut donc réussir son health check alors que le prochain déploiement, le renouvellement d’un jeton ou une sauvegarde échoue. Ce runbook construit la décision de bascule à partir des propriétés déployées, des contrôles du subnet, d’une matrice de dépendances et d’un canari. L’objectif est d’activer le routage de tout le trafic sans confondre la joignabilité applicative avec celle des flux de configuration, tout en conservant un rollback précis.

Figer le contrat de routage

Commencez par la raison du changement et les flux qui doivent rester sains. La cible ne doit pas se résumer à « tout envoyer au firewall ». Nommez les sources de preuve et les conditions qui arrêtent la bascule.

yaml app-service-routing-contract.yml
app: app-orders-prod
region: westeurope
integration_subnet: snet-appservice-integration
change: enable-outbound-vnet-routing-all-traffic

required_flows:
application:
- private-orders-api:443
- public-payment-api:443
configuration:
- container-image-pull
- content-share-access
- backup-restore
- managed-identity-token-acquisition

cutover_requires:
- canary-starts-with-the-approved-image
- application-probes-pass
- managed-identity-call-succeeds
- expected-firewall-egress-is-visible

rollback_on:
- image-pull-or-startup-failure
- token-acquisition-regression
- missing-egress-proof
- dependency-latency-above-budget

Conservez l’artefact applicatif, le commit d’infrastructure, les IP de sortie actuelles et le dernier déploiement réussi. Une sonde HTTP valide ne qualifie pas à elle seule un trafic de configuration qui n’apparaît qu’au démarrage, au déploiement ou pendant une sauvegarde.

Lire les propriétés App Service effectives

App Service expose le routage du trafic applicatif et celui de tout le trafic sous properties.outboundVnetRouting. Les réglages historiques vnetRouteAllEnabled et WEBSITE_VNET_ROUTE_ALL peuvent encore exister. Inventoriez donc les propriétés actuelles et les anciens paramètres avant toute modification.

bash 01-read-app-service-routing.sh
RG="rg-orders-prod"
APP="app-orders-prod"

az resource show --resource-group "$RG" --name "$APP" --resource-type "Microsoft.Web/sites" --query "{subnet:properties.virtualNetworkSubnetId,routing:properties.outboundVnetRouting,legacyRouteAll:properties.vnetRouteAllEnabled}" --output json > app-routing-before.json

az webapp config appsettings list --resource-group "$RG" --name "$APP" --query "[?name=='WEBSITE_VNET_ROUTE_ALL' || name=='WEBSITE_CONTENTOVERVNET'].{name:name,value:value}" --output table

az webapp vnet-integration list --resource-group "$RG" --name "$APP" --output table

Joignez app-routing-before.json au changement. Si l’IaC déclare un modèle tandis que la ressource déployée conserve un réglage historique, résorbez cette dérive avant la bascule. Sinon, un déploiement ultérieur peut rétablir silencieusement un autre comportement de routage.

Séparer trafic applicatif et trafic de configuration

Le trafic applicatif est généré par le workload. Le trafic de configuration porte le cycle de vie de la plateforme. Ils peuvent échouer à des moments différents et demander des règles de destination différentes.

text routing-dependency-matrix.txt
Flux                           Moment                    Preuve
Requete vers API privee       regime nominal             DNS, TCP/TLS, trace app
Requete vers SaaS public      regime nominal             reponse, IP egress observee
Extraction image conteneur    deploiement et restart     pull et demarrage reussis
Acces au partage contenu      demarrage et acces fichier lecture/ecriture canari
Sauvegarde et restauration    planifie ou manuel         sauvegarde canari terminee
Jeton identite managee        demarrage et refresh       jeton et appel cible reussis

Pour chaque ligne, capturer
FQDN de destination ou frontiere du service
adresse resolue depuis le contexte applicatif
route et next hop attendus
proprietaire des policies NSG et firewall
IP source ou chemin prive attendu
source de logs et fenetre de validation

Un Private Endpoint éventuel définit uniquement la destination privée de la dépendance concernée. Il ne prouve ni la route du subnet d’intégration, ni la réponse DNS, ni l’autorisation firewall, ni le chemin du trafic de configuration.

Prouver les contrôles du subnet d’intégration

La propriété de routage décide ce qui entre dans le VNet. Le subnet décide ensuite où ce trafic peut aller. Lisez sa délégation, sa table de routes, son NSG et son rattachement NAT comme une seule surface de contrôle.

bash 02-read-integration-subnet.sh
VNET_RG="rg-network-prod"
VNET="vnet-prod-spoke"
SUBNET="snet-appservice-integration"

az network vnet subnet show --resource-group "$VNET_RG" --vnet-name "$VNET" --name "$SUBNET" --query "{prefix:addressPrefix,delegations:delegations[].serviceName,routeTable:routeTable.id,nsg:networkSecurityGroup.id,natGateway:natGateway.id}" --output json > integration-subnet.json

ROUTE_TABLE_ID=$(jq -r '.routeTable // empty' integration-subnet.json)
if [ -n "$ROUTE_TABLE_ID" ]; then
az network route-table route list   --ids "$ROUTE_TABLE_ID"   --query "[].{name:name,prefix:addressPrefix,nextHop:nextHopType,nextHopIp:nextHopIpAddress}"   --output table
fi

Une UDR 0.0.0.0/0 vers Azure Firewall ou une NVA doit être cohérente avec le DNS, les règles de destination et les routes de retour. Un NAT Gateway rattaché au subnet ne remplace pas une UDR qui envoie le trafic vers une virtual appliance. Prédisez le next hop avant de générer le trafic de test.

Tester depuis le contexte applicatif

Lancez les sondes depuis la console applicative ou un endpoint de diagnostic du canari. Une VM placée ailleurs dans le VNet peut utiliser d’autres routes, serveurs DNS et règles NSG.

bash 03-runtime-network-probes.sh
PRIVATE_HOST="orders-api.internal.example"
PUBLIC_HOST="payments.example"

printenv | grep WEBSITE_PRIVATE_IP
nslookup "$PRIVATE_HOST"
nslookup "$PUBLIC_HOST"

curl --fail --silent --show-error --connect-timeout 5 "https://$PRIVATE_HOST/health"

curl --fail --silent --show-error --connect-timeout 5 "https://$PUBLIC_HOST/health"

# Appeler un endpoint applicatif borne qui acquiert son jeton d'identite
# managee et lit une valeur non sensible sur le service cible approuve.
curl --fail --silent --show-error "https://app-orders-canary.azurewebsites.net/ops/identity-probe"

Sur une application Windows native, utilisez les outils de diagnostic App Service comme nameresolver.exe et tcpping.exe au lieu de supposer que les utilitaires réseau usuels sont disponibles. Horodatez chaque sonde afin de corréler les logs applicatifs, firewall et destination.

Basculer un canari avec la topologie de production

Utilisez une application hors production équivalente, reliée à un subnet portant les mêmes routes, NSG, DNS et politiques d’egress. Déployez d’abord l’artefact approuvé, capturez la baseline, puis ne modifiez que la propriété de routage.

bash 04-enable-all-traffic-canary.sh
RG="rg-orders-canary"
APP="app-orders-canary"

az resource update --resource-group "$RG" --name "$APP" --resource-type "Microsoft.Web/sites" --set properties.outboundVnetRouting.allTraffic=true --output none

az resource show --resource-group "$RG" --name "$APP" --resource-type "Microsoft.Web/sites" --query "properties.outboundVnetRouting" --output json

# Redemarrer uniquement le canari pour forcer les chemins startup et image pull.
az webapp restart --resource-group "$RG" --name "$APP"

Rejouez les sondes applicatives, forcez un déploiement ou un restart qui prouve le chemin de l’image, testez l’identité managée et exécutez une sauvegarde non critique si elle entre dans le périmètre. Ne promouvez pas après avoir observé uniquement un processus déjà démarré.

Corréler les échecs avec le changement de route

Le changement doit produire une timeline lisible : mise à jour de propriété, restart ou déploiement, résultat runtime et décision réseau. Adaptez les noms de tables aux diagnostics activés dans l’environnement.

kusto 05-app-service-routing-timeline.kql
let Start = datetime(2026-09-14T06:30:00Z);
let End = datetime(2026-09-14T07:30:00Z);
union isfuzzy=true
(
AzureActivity
| where TimeGenerated between (Start .. End)
| where ResourceProviderValue =~ "MICROSOFT.WEB"
| where ResourceGroup =~ "rg-orders-canary"
| project TimeGenerated, Source="AzureActivity", Detail=OperationNameValue, Result=ActivityStatusValue
),
(
AppServiceConsoleLogs
| where TimeGenerated between (Start .. End)
| where _ResourceId has "/sites/app-orders-canary"
| project TimeGenerated, Source="AppServiceConsoleLogs", Detail=ResultDescription, Result="runtime"
)
| order by TimeGenerated asc

Pour les logs firewall, filtrez la même fenêtre sur le subnet d’intégration et les destinations attendues. Un deny explicite fournit une preuve de policy. L’absence d’événement firewall pour une requête horodatée ramène vers le DNS, le routage, le filtrage local ou un test qui n’a jamais quitté le processus.

Décider promotion, routage sélectif ou rollback

yaml app-service-routing-decision.yml
promote_all_traffic:
when:
- application_and_configuration_matrix_passes
- expected_firewall_or_nat_egress_is_proven
- restart_and_deployment_complete
- managed_identity_refresh_is_validated

use_selective_routing:
when:
- application_traffic_requires_vnet
- one_configuration_flow_is_not_ready
action:
- keep_applicationTraffic_true
- enable_only_qualified_configuration_properties
- open_a_bounded_follow_up_for_missing_flow

hold:
when:
- destination_inventory_is_incomplete
- dns_or_next_hop_is_ambiguous
- firewall_evidence_is_missing

rollback:
action:
- restore_app-routing-before.json_through_iac
- restart_the_canary
- repeat_the_same_probe_matrix
- confirm_deployment_token_and_backup_return_to_baseline

Le routage sélectif est un état intermédiaire contrôlé, pas une exception non documentée. Conservez les propriétés choisies applicationTraffic, imagePullTraffic, contentShareTraffic, backupRestoreTraffic et managedIdentityTraffic dans l’IaC, avec un propriétaire et une condition de sortie.

Conclusion

Activer le routage VNet de tout le trafic App Service ne modifie pas seulement le chemin des appels HTTP émis par l’application. Ce changement peut placer l’image pull, l’accès au contenu, les sauvegardes et l’acquisition des jetons d’identité managée derrière le DNS, les UDR, le NSG, le firewall et le NAT du subnet d’intégration.

Promouvez uniquement après qu’un canari a prouvé les trafics applicatifs et de configuration avec la topologie de production. Si un flux de cycle de vie n’est pas prêt, gardez un routage sélectif et visible. Si le démarrage, l’identité ou le déploiement régresse, restaurez le jeu de propriétés capturé et rejouez la même matrice avant de clôturer le changement.