Cloud
Internal APIM and Azure Function with Private Endpoint
Design a private API flow where API Management stays internal and calls an Azure Function exposed through Private Endpoint, with private DNS, clear network boundaries and operational checks.
Publishing an internal API with Azure API Management and an Azure Function looks simple on a diagram. APIM receives the call, applies its policies, then forwards the request to a Function. The Private Endpoint closes the network entry path to the backend, and the whole design appears private. In operations, that shortcut often creates architectures that are hard to troubleshoot, because the real privacy of the flow depends on DNS, the APIM network model, the Function hosting plan and the order in which public access is disabled.
The scenario covered here is a business API consumed from an internal network. Clients may sit in an Azure spoke, in an on-premises network connected through ExpressRoute or VPN, or behind an enterprise DNS resolver. API Management remains the API entry point. The HTTP Function hosts the application logic. The Private Endpoint exposes the backend through a private address. The goal is not only to make the flow work, but to keep it explainable when it fails.
The expected flow
The expected flow must be described without ambiguity. The internal client resolves the APIM name to a private address. APIM receives the call on its internal gateway, applies authentication, quota, transformation or logging policies, then calls the Function through its normal DNS name. That name must resolve to the private address of the Private Endpoint from the APIM network path.
Internal client
Resolves api.internal.example.com to the private APIM address
Calls the API published by API Management
Internal API Management
Receives the call on the private gateway
Applies API policies
Resolves func-orders-prod.azurewebsites.net to a private address
Calls the Function backend with the expected hostname
Azure Function
Receives the call through Private Endpoint
Validates the expected identity or application secret
Rejects public access after private path validation This distinction matters. APIM in a VNet does not automatically make every backend private. A Function exposed through Private Endpoint is not automatically protected at the application layer. The network restricts possible paths, but it does not replace backend authorization.
Choose the APIM model before deployment
API Management can be used with several network models. With a classic APIM instance in internal VNet mode, the service is injected into a dedicated subnet and its endpoints are reachable from the private network or connected networks. This model fits when APIM must be an internal entry point and reach private backends in a hub and spoke architecture.
The mistake to avoid is mixing models. An inbound Private Endpoint for API Management and an APIM instance injected in internal VNet mode do not address exactly the same need. Before deployment, the design must decide whether it needs an internal APIM instance injected into a subnet, or private access to the gateway through Private Link in another service model. This article intentionally uses APIM in internal VNet mode, because it is the clearest pattern for a strictly internal API.
Chosen decision
API Management in internal VNet mode
Gateway exposed only on the private network
Azure Function backend reached through its normal hostname
Private backend resolution through Private DNS
Decision not used in this pattern
Backend called by private IP address
Function left public to simplify tests
Backend authentication replaced by Private Endpoint only Separate subnets to keep troubleshooting readable
The APIM subnet must remain dedicated to APIM. The Private Endpoint subnet hosts private interfaces for PaaS services, including the Function. If the Function itself must reach SQL, Storage, Key Vault or an internal private API, a separate VNet integration subnet may be required. This separation avoids confusing private inbound access with application outbound connectivity.
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 The Function VNet integration subnet delegation must not be applied to the APIM subnet. The Private Endpoint subnet should not become a generic application subnet. Those details avoid confusion when routes, NSGs or DNS results have to be compared.
Make DNS explicit
DNS is often the actual boundary between a private architecture and a partially private one. Clients must resolve the APIM gateway to its private address. APIM must resolve the Function backend to the private address of the Private Endpoint. These are separate topics and must be validated separately.
Enterprise internal zone
api.internal.example.com A private APIM address
portal.internal.example.com A private APIM address
management.internal.example.com A private APIM address
Azure Private DNS zone
privatelink.azurewebsites.net linked to the VNet used by APIM
func-orders-prod A Private Endpoint private address
func-orders-prod.scm A private SCM address when private deployment is required A test against the IP address is not enough. The test must use the name that clients really use and the name that APIM really uses to call the Function. Otherwise TLS certificates, host headers and production DNS behavior are not being validated.
Create the Function Private Endpoint
The Function must run on a plan that supports Private Endpoint. The Private Endpoint is created on the sites subresource. The public name func-orders-prod.azurewebsites.net still exists, but from the relevant networks it must resolve through privatelink.azurewebsites.net to a private address.
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 Validation must be performed from a host that uses the same DNS path as APIM. The expected result is an address from the Private Endpoint subnet. An HTTP status code alone is not enough, because a 401, 403 or 404 can be normal depending on authentication or routing.
nslookup $FUNC_NAME.azurewebsites.net
nslookup $FUNC_NAME.privatelink.azurewebsites.net
curl -I https://$FUNC_NAME.azurewebsites.net/api/health Configure APIM without bypassing TLS
APIM must call the Function with its hostname, not with the private IP address of the Private Endpoint. The IP address may look convenient during testing, but it breaks the TLS model and makes the configuration fragile. The APIM backend should remain in the form 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> Backend authentication must be explicit. Depending on the context, APIM can pass a Function key, present a client certificate, obtain a Microsoft Entra ID token or inject a secret from Key Vault. The right choice depends on the expected security model, but it must not be replaced by the Private Endpoint alone.
Disable public access after proving the private path
Public access to the Function should be disabled after the private path has been validated. Disabling it too early makes troubleshooting harder, because DNS, routing, TLS, authentication and application errors become harder to separate.
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}' After disabling public access, the same test must be replayed from APIM and from a network that should not reach the backend. The first one must work. The second one must fail. If both still work, public access was not really closed or another path still exists.
Troubleshoot recurring failures
The most frequent errors are predictable. The privatelink.azurewebsites.net zone exists but is not linked to the right VNet. APIM still calls a public backend URL. An on-premises DNS server does not forward the private suffix back to Azure. A private IP address was placed in the backend URL and TLS fails. Public network access was disabled before deployment agents had a path to SCM. The Function storage account remains public even though the HTTP entry point has been privatized.
APIM returns 500 or 502
Check backend DNS resolution from the same path as APIM
Check that the backend URL uses the expected hostname
Check backend authentication
Read APIM logs and Application Insights with the same correlation ID
The Function works from a VM but not from APIM
Compare the DNS resolvers being used
Check Private DNS Zone links
Check NSGs and routes on the APIM subnet
Check that the APIM policy does not rewrite the backend
Everything breaks after public access is disabled
Prove that the flow was really using Private Endpoint before closure
Check SCM and deployment agents
Check Storage, Key Vault and managed identity dependencies Conclusion
Internal APIM and Azure Function with Private Endpoint form a reliable pattern when each component keeps its role. APIM publishes and governs the API. The Private Endpoint closes the network entry path to the backend. The Function validates the expected call. DNS proves that the flow really uses the private network.
The final test must be operational. From an internal client, resolve APIM, call the API, follow correlation in APIM, check that the Function backend resolves privately, confirm Function execution, then replay the same scenario after public access has been disabled. If that chain works without a hosts file, without a hardcoded IP address and without a temporary exception kept in production, the design is usable.