Cloud

Azure App Service : diagnostiquer un endpoint privé avant de redéployer

Construire un runbook opérationnel pour les pannes App Service en accès privé en séparant DNS, Private Endpoint, access restrictions, Application Gateway, logs applicatifs et rollback.

12 juin 2026 azureapp-serviceprivate-endpointdnskqllogsmonitoringrunbookidentityrollbackautomation

Un App Service exposé en privé peut échouer sans que le dernier déploiement applicatif soit responsable. Le nom peut encore résoudre vers l’adresse publique, le Private Endpoint peut être approuvé mais absent du réseau appelant, une access restriction peut bloquer Application Gateway ou APIM, le health check peut viser une route non prête, ou l’application peut répondre 403, 502, 503 avant de produire des logs utiles.

Le cas d’usage est une application interne hébergée sur Azure App Service, appelée depuis un réseau privé via Application Gateway, APIM interne, une probe synthétique ou un service consommateur. L’objectif du runbook est simple : prouver où la requête s’arrête avant de redéployer, d’ouvrir l’accès public ou de modifier une règle WAF trop largement.

Lire App Service comme un chemin de production

Un App Service privé n’est pas seulement un hostname. C’est une chaîne qui combine résolution DNS, Private Link, point d’entrée éventuel, restrictions d’accès, runtime applicatif, identité et observabilité. Le diagnostic doit donc suivre cette chaîne dans l’ordre.

text app-service-private-path.txt
Client interne, APIM ou probe
Résout app.internal.example.com depuis le réseau consommateur
Envoie le bon Host header, un correlation ID et le chemin réel

Point d'entrée éventuel
Application Gateway ou APIM interne
Préserve TLS/SNI, host header et x-correlation-id
Remonte les codes WAF, gateway ou policy sans les mélanger

App Service
Private Endpoint approuvé sur le site Web
Public network access et access restrictions cohérents
Health check aligné avec une route applicative stable

Dépendances
Key Vault, stockage, base de données ou API aval joignables par le chemin attendu
Identité managée autorisée uniquement sur le périmètre nécessaire

Observabilité
AppServiceHTTPLogs, traces applicatives et gateway logs corrélables
Rollback limité à la couche qui a réellement changé

Cette carte évite deux réflexes coûteux : redéployer alors que DNS est faux, ou ouvrir l’accès public alors que la requête n’atteint même pas le runtime.

Classer le symptôme avant la correction

La première décision consiste à séparer un échec d’entrée privée d’un échec applicatif. Si la requête n’apparaît pas dans les logs App Service, le code n’est pas encore la piste principale.

text app-service-private-symptoms.txt
Symptôme
DNS retourne une adresse publique
  Vérifier zone privatelink.azurewebsites.net, lien VNet et forwarding DNS hybride

Application Gateway retourne 502
  Vérifier backend health, host header, TLS/SNI, probe path et access restrictions App Service

APIM ou le client retourne 403
  Vérifier access restrictions, public network access, Private Endpoint et source réelle de l'appel

Aucune ligne AppServiceHTTPLogs pour le correlation ID
  Revenir à DNS, gateway, APIM, WAF ou restrictions d'accès

Logs App Service présents avec 500 ou exception
  Lire traces applicatives, identité managée, Key Vault et dépendances aval

Health check instable après livraison
  Valider route de santé, warmup, slot, dépendances critiques et rollback applicatif

La règle opérationnelle est volontairement stricte : tant que le correlation ID n’apparaît pas côté App Service, on reste sur réseau, entrée privée et restrictions.

Tester depuis le réseau consommateur

Le test doit partir d’un emplacement qui voit le même DNS et le même routage que le consommateur réel : VM de diagnostic, runner de probe, subnet applicatif, environnement APIM interne ou bastion d’exploitation. Un test depuis un poste public ne valide pas le chemin privé.

bash 01-app-service-private-check.sh
HOSTNAME=app.internal.example.com
PATH=/health
CORRELATION_ID="ops-$(date +%Y%m%d%H%M%S)"

nslookup "$HOSTNAME"
dig +short "$HOSTNAME"

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

curl -vk "https://$HOSTNAME$PATH" -H "x-correlation-id: $CORRELATION_ID" -H "x-naxaya-check: private-app-service"

echo "correlation_id=$CORRELATION_ID"

Si DNS ne renvoie pas une adresse privée attendue, corrige la zone ou le forwarding avant d’aller plus loin. Si TLS échoue, regarde SNI, certificat et host header. Si curl retourne 403, vérifie la source réellement vue par App Service ou par le point d’entrée.

Vérifier l’état App Service sans exposer l’application

Les commandes Azure doivent confirmer les dimensions du service sans publier de secret dans le ticket : statut, restrictions, Private Endpoint, health check, identité et paramètres de plateforme utiles.

bash 02-app-service-platform-checks.sh
APP_RG=rg-prod-app
APP_NAME=app-prod-orders

az webapp show -g "$APP_RG" -n "$APP_NAME" --query "{state:state, enabled:enabled, httpsOnly:httpsOnly, hostNames:hostNames, defaultHostName:defaultHostName}" -o jsonc

az webapp config show -g "$APP_RG" -n "$APP_NAME" --query "{alwaysOn:alwaysOn, healthCheckPath:healthCheckPath, publicNetworkAccess:publicNetworkAccess, ftpsState:ftpsState}" -o jsonc

az webapp config access-restriction show -g "$APP_RG" -n "$APP_NAME" -o table

az webapp identity show -g "$APP_RG" -n "$APP_NAME" --query "{type:type, principalId:principalId, tenantId:tenantId}" -o jsonc

az network private-endpoint-connection list --id "$(az webapp show -g "$APP_RG" -n "$APP_NAME" --query id -o tsv)" --query "[].{name:name,status:privateLinkServiceConnectionState.status,description:privateLinkServiceConnectionState.description}" -o table

Cette étape permet de repérer les écarts classiques : Private Endpoint non approuvé, access restriction qui ne couvre pas Application Gateway, health check absent ou route de santé dépendante d’un service aval fragile.

Corréler gateway, WAF et App Service en KQL

Une requête corrélée permet de savoir si l’échec se situe avant App Service, dans App Service, ou après l’entrée dans le code. La requête ci-dessous mélange les logs Application Gateway/WAF et App Service autour d’un même host, d’un chemin et d’un correlation ID.

kusto 03-app-service-private-correlation.kql
let Window = 2h;
let Host = "app.internal.example.com";
let Path = "/health";
let CorrelationId = "ops-20260612080000";
let Gateway =
AzureDiagnostics
| where TimeGenerated > ago(Window)
| where Category in ("ApplicationGatewayAccessLog", "ApplicationGatewayFirewallLog")
| where host_s has Host or requestUri_s has Path or transactionId_g == CorrelationId
| project TimeGenerated, Source=Category, host=host_s, uri=requestUri_s, status=coalesce(httpStatus_d, status_d), ruleId=ruleId_s, action=action_s, transactionId=tostring(transactionId_g);
let AppService =
AppServiceHTTPLogs
| where TimeGenerated > ago(Window)
| where CsHost has Host or CsUriStem has Path or CsUserAgent has CorrelationId
| project TimeGenerated, Source="AppServiceHTTPLogs", host=CsHost, uri=CsUriStem, status=ScStatus, ruleId="", action=CsMethod, transactionId=CorrelationId;
Gateway
| union AppService
| order by TimeGenerated desc

Lecture rapide : logs gateway sans logs App Service orientent vers WAF, backend health, DNS privé, TLS ou restrictions ; logs App Service avec 500 orientent vers code ou dépendance ; absence totale de logs oriente vers DNS, routage ou mauvais point de test.

Choisir le rollback minimal

Le rollback doit restaurer la couche modifiée, pas annuler toute la livraison. Une modification de zone privée, de règle d’accès, de backend pool ou de slot applicatif n’a pas le même retour arrière.

text app-service-private-rollback-matrix.txt
Changement récent
DNS privé ou forwarding
  Rollback: restaurer l'ancien record, lien VNet ou forwarder
  Preuve: nslookup privé puis requête corrélée visible au bon endroit

Access restriction ou public network access
  Rollback: restaurer la règle source précédente
  Preuve: AppServiceHTTPLogs voit le correlation ID

Application Gateway backend ou probe
  Rollback: revenir au backend setting, host header ou path de probe validé
  Preuve: backend health sain et status applicatif cohérent

Slot ou package applicatif
  Rollback: swap retour ou package précédent
  Preuve: même requête réussie avec logs App Service et traces applicatives

Conclusion

Un incident App Service privé se traite comme un incident de chemin, pas comme un incident de code par défaut. DNS, Private Endpoint, access restrictions, Application Gateway, logs App Service et dépendances doivent être isolés avant de toucher au déploiement.

La décision devient plus défendable : si la requête n’atteint pas App Service, on corrige l’entrée privée ; si elle l’atteint et échoue dans les logs, on investigue runtime, identité, dépendances ou code. Cette séparation réduit les ouvertures publiques temporaires, les exceptions WAF trop larges et les rollbacks qui masquent la vraie panne.