Cloud
APIM interne et Azure Function avec Private Endpoint
Concevoir un flux API privé où API Management reste interne et appelle une Azure Function exposée par Private Endpoint, avec DNS privé, séparation des rôles réseau et validations d’exploitation.
Publier une API interne avec Azure API Management et une Azure Function paraît simple sur un schéma. APIM reçoit l’appel, applique ses politiques, puis relaie la requête vers une Function. Le Private Endpoint ferme l’entrée réseau du backend, et l’ensemble semble privé. En exploitation, ce raccourci produit souvent des architectures difficiles à diagnostiquer, parce que la confidentialité réelle du flux dépend surtout du DNS, du mode réseau d’APIM, du plan d’hébergement de la Function et de l’ordre dans lequel l’accès public est fermé.
Le scénario traité ici est celui d’une API métier consommée depuis un réseau interne. Les clients peuvent se trouver dans un spoke Azure, dans un réseau on premises raccordé par ExpressRoute ou VPN, ou derrière un résolveur DNS d’entreprise. API Management reste le point d’entrée API. La Function HTTP porte la logique applicative. Le Private Endpoint expose le backend par une adresse privée. L’objectif n’est pas seulement que le flux fonctionne, mais qu’il reste explicable quand il casse.
Le flux à obtenir
Le flux attendu doit pouvoir être décrit sans ambiguïté. Le client interne résout le nom APIM vers une adresse privée. APIM reçoit l’appel sur son gateway interne, applique les règles d’authentification, de quota, de transformation ou de journalisation, puis appelle la Function avec son nom DNS normal. Ce nom doit se résoudre vers l’adresse privée du Private Endpoint depuis le chemin réseau d’APIM.
Client interne
Résout api.internal.example.com vers l'adresse privée APIM
Appelle l'API publiée par API Management
API Management interne
Reçoit l'appel sur le gateway privé
Applique les politiques API
Résout func-orders-prod.azurewebsites.net vers une adresse privée
Appelle le backend Function avec le hostname attendu
Azure Function
Reçoit l'appel via Private Endpoint
Vérifie l'identité ou le secret attendu côté applicatif
Refuse l'accès public après validation du chemin privé Cette distinction est importante. APIM dans un VNet ne rend pas automatiquement tous les backends privés. Une Function exposée par Private Endpoint n’est pas automatiquement protégée au niveau applicatif. Le réseau limite les chemins possibles, mais il ne remplace pas une autorisation backend.
Choisir le modèle APIM avant le déploiement
API Management peut être utilisé dans plusieurs modèles réseau. Pour un APIM classique en mode VNet interne, l’instance est injectée dans un subnet dédié et ses endpoints sont accessibles depuis le réseau privé ou depuis les réseaux connectés. Ce modèle est adapté quand APIM doit être un point d’entrée interne et joindre des backends privés dans une architecture hub and spoke.
Le point à éviter est de mélanger les modèles. Un Private Endpoint entrant pour API Management et un APIM injecté en VNet interne ne répondent pas exactement au même besoin. Avant de déployer, il faut décider si l’on veut une instance APIM interne injectée dans un subnet, ou un accès privé au gateway via Private Link dans un autre modèle de service. L’article part volontairement sur un APIM en mode VNet interne, car c’est le cas le plus lisible pour une API strictement interne.
Décision retenue
API Management en mode VNet interne
Gateway exposé uniquement sur le réseau privé
Backend Azure Function joint par son hostname normal
Résolution privée du backend via Private DNS
Décision non retenue dans ce pattern
Backend appelé par adresse IP privée
Function ouverte publiquement pour simplifier les tests
Authentification backend remplacée par le seul Private Endpoint Séparer les subnets pour garder un diagnostic lisible
Le subnet APIM doit rester dédié à APIM. Le subnet Private Endpoint porte les interfaces privées des services PaaS, dont la Function. Si la Function doit elle-même sortir vers SQL, Storage, Key Vault ou une API interne privée, un subnet d’intégration VNet séparé peut être nécessaire. Cette séparation évite de confondre entrée privée et sortie applicative.
export RG_NET=rg-net-prod
export LOCATION=westeurope
export VNET_NAME=vnet-prod-api
export APIM_SUBNET=snet-apim-internal
export PE_SUBNET=snet-private-endpoints
export FUNC_INTEGRATION_SUBNET=snet-function-integration
az group create -n $RG_NET -l $LOCATION
az network vnet create -g $RG_NET -n $VNET_NAME -l $LOCATION --address-prefixes 10.80.0.0/16
az network vnet subnet create -g $RG_NET --vnet-name $VNET_NAME -n $APIM_SUBNET --address-prefixes 10.80.10.0/26
az network vnet subnet create -g $RG_NET --vnet-name $VNET_NAME -n $PE_SUBNET --address-prefixes 10.80.20.0/27
az network vnet subnet create -g $RG_NET --vnet-name $VNET_NAME -n $FUNC_INTEGRATION_SUBNET --address-prefixes 10.80.30.0/27 --delegations Microsoft.Web/serverFarms La délégation du subnet d’intégration Function ne doit pas être appliquée au subnet APIM. Le subnet Private Endpoint ne doit pas être utilisé comme subnet applicatif générique. Ces détails évitent beaucoup de confusion lorsque les routes, les NSG ou les résolutions DNS doivent être comparées.
Rendre le DNS explicite
Le DNS est souvent le vrai point de bascule entre une architecture privée et une architecture seulement partiellement privée. Les clients doivent résoudre le gateway APIM vers son adresse privée. APIM doit résoudre le backend Function vers l’adresse privée du Private Endpoint. Les deux sujets sont séparés et doivent être validés séparément.
Zone interne de l'entreprise
api.internal.example.com A adresse privée APIM
portal.internal.example.com A adresse privée APIM
management.internal.example.com A adresse privée APIM
Zone Azure Private DNS
privatelink.azurewebsites.net liée au VNet utilisé par APIM
func-orders-prod A adresse privée du Private Endpoint
func-orders-prod.scm A adresse privée SCM si le déploiement privé est requis Un test sur adresse IP ne suffit pas. Il faut tester le nom réellement utilisé par les clients et le nom réellement utilisé par APIM pour appeler la Function. Sinon, on ne valide ni le certificat TLS, ni le host header, ni la résolution qui sera utilisée en production.
Créer le Private Endpoint de la Function
La Function doit être hébergée sur un plan compatible avec Private Endpoint. Le Private Endpoint se crée sur le sous-resource sites. Le nom public func-orders-prod.azurewebsites.net continue d’exister, mais il doit résoudre vers privatelink.azurewebsites.net puis vers une adresse privée depuis les réseaux concernés.
export RG_APP=rg-api-prod
export FUNC_NAME=func-orders-prod
export PE_FUNC_NAME=pe-func-orders-prod
export DNS_ZONE_FUNC=privatelink.azurewebsites.net
FUNC_ID=$(az functionapp show -g $RG_APP -n $FUNC_NAME --query id -o tsv)
az network private-dns zone create -g $RG_NET -n $DNS_ZONE_FUNC
az network private-dns link vnet create -g $RG_NET -n link-$VNET_NAME-azurewebsites -z $DNS_ZONE_FUNC -v $VNET_NAME -e false
az network private-endpoint create -g $RG_NET -n $PE_FUNC_NAME -l $LOCATION --vnet-name $VNET_NAME --subnet $PE_SUBNET --private-connection-resource-id $FUNC_ID --group-id sites --connection-name cn-$PE_FUNC_NAME
az network private-endpoint dns-zone-group create -g $RG_NET --endpoint-name $PE_FUNC_NAME -n dzg-$PE_FUNC_NAME --private-dns-zone $DNS_ZONE_FUNC --zone-name $DNS_ZONE_FUNC La validation doit être faite depuis un hôte qui utilise le même DNS que le chemin APIM. Le résultat attendu est une adresse du subnet Private Endpoint. Un simple code HTTP ne suffit pas, car une erreur 401, 403 ou 404 peut être normale selon l’authentification ou la route applicative.
nslookup $FUNC_NAME.azurewebsites.net
nslookup $FUNC_NAME.privatelink.azurewebsites.net
curl -I https://$FUNC_NAME.azurewebsites.net/api/health Configurer APIM sans contourner TLS
APIM doit appeler la Function avec son hostname, pas avec l’adresse IP privée du Private Endpoint. L’adresse IP paraît pratique pendant un test, mais elle casse le modèle TLS et rend la configuration fragile. Le backend APIM doit donc rester de la forme https://func-orders-prod.azurewebsites.net/api.
<policies>
<inbound>
<base />
<set-backend-service base-url="https://func-orders-prod.azurewebsites.net/api" />
<set-header name="x-correlation-id" exists-action="override">
<value>@(context.RequestId.ToString())</value>
</set-header>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies> L’authentification backend doit être explicite. Selon le contexte, APIM peut transmettre une clé Function, présenter un certificat client, obtenir un jeton Entra ID ou injecter un secret depuis Key Vault. Le choix dépend du niveau de sécurité attendu, mais il ne doit pas être remplacé par le seul Private Endpoint.
Fermer l’accès public après preuve du chemin privé
L’accès public de la Function doit être fermé après validation du chemin privé. Fermer trop tôt complique les diagnostics, car il devient difficile de distinguer un problème DNS, un problème de routage, une erreur TLS, une erreur d’authentification et un problème applicatif.
az functionapp update -g $RG_APP -n $FUNC_NAME --set publicNetworkAccess=Disabled
az functionapp show -g $RG_APP -n $FUNC_NAME --query '{name:name, publicNetworkAccess:publicNetworkAccess, defaultHostName:defaultHostName}' Après fermeture, il faut rejouer le même test depuis APIM et depuis un réseau qui ne doit pas accéder au backend. Le premier doit fonctionner. Le second doit échouer. Si les deux fonctionnent encore, le flux public n’a pas réellement été fermé ou un autre chemin existe.
Diagnostiquer les pannes récurrentes
Les erreurs les plus fréquentes sont prévisibles. La zone privatelink.azurewebsites.net existe mais n’est pas liée au bon VNet. APIM appelle encore une URL backend publique. Un DNS on premises ne forwarde pas le suffixe privé vers Azure. Une IP privée a été placée dans l’URL backend et TLS échoue. Le public network access a été désactivé avant que les agents de déploiement aient un chemin vers SCM. Le stockage de la Function reste public alors que l’entrée HTTP a été privatisée.
APIM retourne 500 ou 502
Vérifier la résolution DNS du backend depuis le même chemin que APIM
Vérifier que l'URL backend utilise le hostname attendu
Vérifier l'authentification backend
Lire les logs APIM et Application Insights avec le même correlation ID
La Function répond depuis une VM mais pas depuis APIM
Comparer les résolveurs DNS utilisés
Vérifier les liens de Private DNS Zone
Vérifier les NSG et les routes du subnet APIM
Vérifier que la politique APIM ne réécrit pas le backend
Tout casse après fermeture de l'accès public
Prouver que le flux passait réellement par Private Endpoint avant fermeture
Vérifier SCM et les agents de déploiement
Vérifier les dépendances Storage, Key Vault et identité managée Conclusion
APIM interne et Azure Function avec Private Endpoint forment un pattern fiable quand chaque composant garde son rôle. APIM publie et gouverne l’API. Le Private Endpoint ferme l’entrée réseau vers le backend. La Function vérifie l’appel attendu. Le DNS prouve que le flux passe réellement par le réseau privé.
Le test final doit être opérationnel. Depuis un client interne, il faut résoudre APIM, appeler l’API, suivre la corrélation dans APIM, vérifier que le backend Function est résolu en privé, confirmer l’exécution côté Function, puis rejouer exactement le même scénario après désactivation de l’accès public. Si cette chaîne tient sans hosts file, sans IP codée en dur et sans exception temporaire conservée en production, le design est exploitable.