Cloud
Azure App Service et Functions : VNet Integration n'est pas un Private Endpoint
Concevoir la VNet Integration pour App Service et Azure Functions en séparant sortie applicative, DNS privé, Route All, NSG, UDR, NAT Gateway et accès entrant privé.
La VNet Integration Azure App Service et Azure Functions est souvent ajoutée au bon moment, mais pour une mauvaise raison. Une application doit joindre une base SQL privée, un Key Vault derrière Private Link, une API interne dans un spoke, ou un service on premises via ExpressRoute. L’équipe intègre alors l’application à un subnet, constate un statut vert dans le portail, puis suppose que l’application est maintenant « dans le VNet ».
C’est ce raccourci qui crée les incidents. La VNet Integration donne au runtime un chemin de sortie vers ou à travers un Virtual Network. Elle ne rend pas l’App Service ou la Function joignable en entrée par une adresse privée. L’accès entrant privé relève d’un Private Endpoint, d’un App Service Environment, d’API Management, d’Application Gateway ou d’un autre choix d’exposition.
Le scénario fil rouge est une application app-prod-orders et une Function func-prod-billing qui doivent appeler SQL, Storage, Key Vault et une API interne sans ouvrir ces dépendances publiquement. L’objectif n’est pas seulement que cela fonctionne, mais que DNS, routage, sécurité réseau et rollback restent lisibles en exploitation.
Commencer par la bonne séparation
La phrase de cadrage à écrire dans le design est simple.
VNet Integration
Sert à faire sortir l'application vers un VNet
Permet d'atteindre des ressources privées, des VNets peerés ou un réseau on premises
Se diagnostique avec DNS, routes, NSG, UDR, NAT et dépendances de plateforme
Private Endpoint sur App Service ou Function
Sert à faire entrer les clients vers l'application par Private Link
Ne transporte pas la sortie applicative
Se diagnostique avec DNS d'entrée, accès public, clients, gateway et logs HTTP
NAT Gateway
Sert à stabiliser l'IP publique de sortie quand le trafic sort vers Internet
Ne remplace ni Private Endpoint, ni DNS privé, ni autorisation applicative Cette séparation évite de mélanger trois questions différentes : qui peut appeler l’application, ce que l’application peut appeler, et par quelle IP publique elle sort quand elle doit encore joindre Internet.
Garder les subnets spécialisés
Un design exploitable sépare les rôles réseau. Le subnet d’intégration App Service ou Functions porte la sortie des applications. Les Private Endpoints des services PaaS restent dans un autre subnet. Les appliances, bastions et workloads classiques ne doivent pas être ajoutés dans le subnet d’intégration juste parce qu’il reste des adresses.
export RG_NET=rg-prod-network
export LOCATION=westeurope
export VNET_NAME=vnet-prod-app
export APP_INTEGRATION_SUBNET=snet-appsvc-integration
export FUNC_INTEGRATION_SUBNET=snet-function-integration
export PE_SUBNET=snet-private-endpoints
az group create -n $RG_NET -l $LOCATION
az network vnet create -g $RG_NET -n $VNET_NAME -l $LOCATION --address-prefixes 10.70.0.0/16
az network vnet subnet create -g $RG_NET --vnet-name $VNET_NAME -n $APP_INTEGRATION_SUBNET --address-prefixes 10.70.10.0/27 --delegations Microsoft.Web/serverFarms
az network vnet subnet create -g $RG_NET --vnet-name $VNET_NAME -n $FUNC_INTEGRATION_SUBNET --address-prefixes 10.70.11.0/27 --delegations Microsoft.Web/serverFarms
az network vnet subnet create -g $RG_NET --vnet-name $VNET_NAME -n $PE_SUBNET --address-prefixes 10.70.20.0/27 La séparation ne sert pas l’esthétique du schéma. Elle permet de savoir quelle table de routes, quel NSG et quel lien DNS impactent une panne donnée. Si app-prod-orders ne joint plus SQL, l’équipe doit regarder le subnet d’intégration, pas le subnet Private Endpoint de l’App Service.
Activer la VNet Integration et vérifier l’état réel
L’intégration doit être validée côté ressource, pas seulement dans le portail. Les commandes suivantes gardent l’exemple lisible avec App Service ; la même logique s’applique aux Function Apps sur plans compatibles.
export RG_APP=rg-prod-app
export APP_NAME=app-prod-orders
export FUNC_NAME=func-prod-billing
az webapp vnet-integration add -g $RG_APP -n $APP_NAME --vnet $VNET_NAME --subnet $APP_INTEGRATION_SUBNET
az webapp vnet-integration list -g $RG_APP -n $APP_NAME
az resource show -g $RG_APP -n $APP_NAME --resource-type Microsoft.Web/sites --query '{name:name, integrationSubnet:properties.virtualNetworkSubnetId}' Le point important est de rattacher chaque application au subnet prévu. Une Function trigger qui consomme Service Bus, une API web et un worker batch n’ont pas forcément le même profil de sortie. Le subnet choisi devient un élément du runbook.
Traiter DNS avant de traiter les routes
La plupart des erreurs de VNet Integration ressemblent d’abord à des erreurs réseau. En pratique, beaucoup commencent par DNS. L’application peut avoir un chemin vers le VNet et continuer à résoudre sql-prod-orders.database.windows.net ou kv-prod-orders.vault.azure.net vers une cible publique, ou ne pas résoudre le nom on premises attendu.
Destination appelee par l'application
Azure SQL avec Private Endpoint
Zone attendue: privatelink.database.windows.net
Validation: le FQDN public suit la chaine privatelink et retourne une IP privee
Key Vault avec Private Endpoint
Zone attendue: privatelink.vaultcore.azure.net
Validation: l'identite est autorisee et le nom se resout depuis le runtime
Storage prive
Zone attendue selon le sous-service: blob, file, queue ou table
Validation: le bon sous-resource est prive, pas seulement le compte Storage
API interne dans un spoke
Zone attendue: DNS interne de l'entreprise ou Azure Private DNS
Validation: resolution identique depuis le runtime et depuis un point de test comparable
Systeme on premises
Zone attendue: forwarding DNS vers les resolvers d'entreprise
Validation: ExpressRoute/VPN ne suffit pas si le nom ne se resout pas Un test depuis une VM du VNet aide, mais il ne remplace pas un test depuis le runtime applicatif. Une VM peut utiliser un résolveur différent, ne pas subir les mêmes routes, et donner un faux sentiment de validation.
Décider ce qui doit passer par le VNet
La question suivante est souvent mal formulée. Il ne faut pas seulement demander « l’application est-elle intégrée au VNet ? ». Il faut demander quels flux sortants passent par cette intégration.
Selon le besoin, l’équipe peut router uniquement le trafic applicatif vers les plages privées, ou forcer une part plus large du trafic de configuration et de sortie à travers le VNet. Ce choix a des effets sur les dépendances de plateforme : image de conteneur, content share, backup/restore, acquisition de jeton managed identity et accès à Internet.
APP_ID=$(az webapp show -g $RG_APP -n $APP_NAME --query id -o tsv)
az resource update --ids $APP_ID --set properties.outboundVnetRouting.applicationTraffic=true
az resource update --ids $APP_ID --set properties.outboundVnetRouting.allTraffic=true
az resource show --ids $APP_ID --query '{applicationTraffic:properties.outboundVnetRouting.applicationTraffic, allTraffic:properties.outboundVnetRouting.allTraffic}' allTraffic=true ne doit pas être activé comme réflexe de durcissement. Il faut d’abord savoir où passent les images, le stockage de contenu, les appels d’identité managée, les dépendances externes et les flux de supervision. Sinon, la correction d’un accès SQL privé peut casser un démarrage de conteneur ou un montage de contenu.
Utiliser NSG et UDR comme des contrôles de production
Une fois le trafic applicatif routé par le VNet, les NSG et UDR du subnet d’intégration deviennent des composants actifs du chemin. Ils ne sont pas de simples garde-fous décoratifs.
az network route-table create -g $RG_NET -n rt-appsvc-egress
az network route-table route create -g $RG_NET --route-table-name rt-appsvc-egress -n default-to-firewall --address-prefix 0.0.0.0/0 --next-hop-type VirtualAppliance --next-hop-ip-address 10.70.30.4
az network vnet subnet update -g $RG_NET --vnet-name $VNET_NAME -n $APP_INTEGRATION_SUBNET --route-table rt-appsvc-egress Après ce changement, la validation doit couvrir au minimum quatre flux : DNS, dépendance privée cible, dépendance Internet encore nécessaire, et identité managée. Un test qui ne vérifie que SQL peut laisser une panne latente sur Key Vault, ACR, Storage ou une API de paiement externe.
Ajouter NAT Gateway uniquement pour le besoin d’egress public
NAT Gateway répond à une demande précise : stabiliser les IP publiques de sortie pour des services tiers qui font de l’allow list. Ce n’est pas un mécanisme d’entrée privée, ni un substitut à Private DNS.
az network public-ip create -g $RG_NET -n pip-appsvc-nat --sku Standard
az network nat gateway create -g $RG_NET -n nat-appsvc-egress --public-ip-addresses pip-appsvc-nat
az network vnet subnet update -g $RG_NET --vnet-name $VNET_NAME -n $APP_INTEGRATION_SUBNET --nat-gateway nat-appsvc-egress Le runbook doit documenter pourquoi NAT existe. Si la raison est « IP fixe pour un partenaire externe », la preuve attendue est l’IP vue par ce partenaire. Si la raison est « accès privé à SQL », NAT n’est pas la bonne réponse.
Construire une validation depuis l’application
Le test le plus utile est un diagnostic minimal exécuté depuis le chemin réel de l’application. Il peut prendre la forme d’un endpoint protégé, d’une commande Kudu/console, d’un job temporaire ou d’un worker de validation supprimé après usage.
Validation VNet Integration - app-prod-orders
Horodatage
2026-06-15T20:00:00Z
Depuis le runtime
Resolve sql-prod-orders.database.windows.net
Resolve kv-prod-orders.vault.azure.net
Resolve api-pricing.internal.example.com
Connexions reelles
SQL: ouverture TCP puis requete simple
Key Vault: lecture d'un secret de test avec managed identity
API interne: GET /health avec correlation ID
Internet autorise: appel vers endpoint externe attendu si necessaire
Preuves a joindre au ticket
IP resolues
Codes de retour
Correlation ID
Extrait de logs applicatifs
Etat des routes, NSG, NAT et outboundVnetRouting Cette carte force le diagnostic à rester concret. La question n’est pas « le réseau est-il sécurisé ? », mais « le runtime résout-il et joint-il les dépendances prévues par le chemin prévu ? ».
Les pannes typiques après un statut vert
Les incidents récurrents ne sont pas mystérieux. L’application est bien intégrée au VNet, mais la zone Private DNS n’est pas liée au bon VNet. allTraffic est activé et une UDR envoie tout vers un firewall qui ne connaît pas les flux de plateforme. Le subnet d’intégration est réutilisé pour des ressources qui n’ont rien à y faire. NAT Gateway est ajouté pour une allow list externe, puis l’équipe pense à tort que les dépendances Azure privées sont couvertes. Un Private Endpoint est créé sur l’App Service, mais les appels sortants vers SQL passent toujours par le chemin public.
Le diagnostic doit donc revenir à la séparation initiale : sortie applicative, entrée privée, DNS, routes, sécurité réseau, identité et dépendance réellement appelée.
Décider du rollback minimal
La VNet Integration touche plusieurs couches. Le rollback doit viser la couche changée, pas annuler toute la livraison.
Changement recent
Lien Private DNS ou forwarder
Rollback: restaurer le lien VNet ou la regle de forwarding precedente
Preuve: resolution privee depuis le runtime
outboundVnetRouting ou Route All
Rollback: revenir au routage precedent
Preuve: dependance cible et dependances plateforme revalidees
NSG ou UDR sur subnet d'integration
Rollback: restaurer les regles ou routes precedentes
Preuve: DNS, identite, dependance privee et egress public attendu fonctionnent
NAT Gateway
Rollback: detacher NAT du subnet si l'egress public n'est plus conforme
Preuve: IP de sortie observee et impact partenaire documente
Private Endpoint entrant sur l'application
Rollback: traiter comme un sujet d'exposition entrante, pas comme un probleme de VNet Integration
Preuve: clients internes, DNS d'entree et logs HTTP valides Conclusion
La VNet Integration est un outil d’architecture très utile, mais seulement si son rôle reste clair. Elle donne à App Service ou Azure Functions un chemin de sortie contrôlé vers un VNet. Elle doit être pensée avec DNS, routes, NSG, UDR, NAT Gateway, identité managée et dépendances de plateforme.
Private Endpoint garde sa place pour l’entrée privée ou pour les dépendances PaaS appelées par l’application. Mais il ne doit pas absorber tout le raisonnement réseau. Un design Azure privé exploitable sépare les sens de trafic, documente les décisions de routage, et valide depuis le runtime avant de fermer, forcer ou rediriger les flux.
Références
- Microsoft Learn, Integrate your app with an Azure virtual network
- Microsoft Learn, Enable virtual network integration in Azure App Service
- Microsoft Learn, Manage Azure App Service virtual network integration routing
- Microsoft Learn, Azure Functions networking options
- Microsoft Learn, Configure Azure NAT Gateway Integration
- Microsoft Learn, Use private endpoints for Azure App Service apps