Skip to content

Private Endpoints

sambetts edited this page Aug 26, 2026 · 10 revisions

This is optional

If you need to ensure that all endpoints are private, you can integrate with a virtual network and restrict access to each resource via the same VNet.

Example network:

The resources in Azure should be accessible only via private IP addresses, accessible optionally via another private, on-premises network.

Automated Setup (Installer)

The installer now supports private VNet configuration out of the box. When the Networking option is enabled in the installer UI, the following is set up automatically:

Networking tab in the installer

What the Installer Creates

  1. Virtual Network (VNet) with two subnets:

    • A default subnet (e.g. default at 10.0.0.0/24) used for the private endpoints of all PaaS resources
    • A dedicated App Service integration subnet (e.g. app-integration at 10.0.2.0/24) delegated to Microsoft.Web/serverFarms for outbound App Service VNet integration

    Both VNet address space and subnet prefixes are configurable in the Networking page of the installer.

  2. Private Endpoints for all PaaS resources (placed on the default subnet):

    • SQL Server (default name pe-{name}-sql, group: sqlServer)
    • App Service (default name pe-{name}-app, group: sites)
    • Redis Cache (default name pe-{name}-redis, group: redisCache)
    • Storage Account — blob only (default name pe-{name}-blob, group: blob)
    • Key Vault (default name pe-{name}-vault, group: vault)
    • Service Bus (default name pe-{name}-sb, group: namespace)
    • Cognitive Services (default name pe-{name}-cognitive, group: account) — if enabled
    • Automation Account (default name pe-{name}-automation, group: DSCAndHybridWorker) — only if Graph usage reports / runbooks are enabled

    Endpoint names can be overridden per resource via the CustomEndpointNames setting in the saved installer config.

  3. Private DNS Zones with VNet links and PE zone groups for automatic DNS resolution:

    • privatelink.database.windows.net (SQL)
    • privatelink.azurewebsites.net (App Service)
    • privatelink.redis.cache.windows.net (Redis)
    • privatelink.blob.core.windows.net (Storage — blob)
    • privatelink.vaultcore.azure.net (Key Vault)
    • privatelink.servicebus.windows.net (Service Bus)
    • privatelink.cognitiveservices.azure.com (Cognitive Services)
    • privatelink.azure-automation.net (Automation Account — only if runbooks are enabled)

    DNS zone deployment is optional — set DeployDnsZones to false in the installer config if you manage DNS yourself (for example with on-premises DNS or Azure DNS Private Resolver). In that case, only private endpoints and VNet integration are created and you must register the private IPs in your own DNS infrastructure.

  4. SKU selection on creation for VNet compatibility (the installer only sets these SKUs when creating the resource — existing resources are not upgraded automatically; see the limitations below):

    • Redis: created at Standard (Basic does not support private endpoints)
    • Service Bus: created at Premium (private endpoints require Premium)
    • SQL Database: created at S2 when networking is enabled
  5. App Service VNet integration — the installer configures the App Service to use the app-integration subnet (VirtualNetworkSubnetId) and enables Route All (IsVnetRouteAllEnabled = true) on the site config so all outbound traffic flows through the VNet.

  6. App Service configuration for private DNS resolution:

    • WEBSITE_VNET_ROUTE_ALL = 1 — routes all outbound traffic through the VNet
    • WEBSITE_DNS_SERVER = 168.63.129.16 — uses Azure DNS for private DNS zone resolution
  7. Hybrid Runbook Worker (optional) — if a VM resource ID is provided in the Networking config, the installer creates a hybrid worker group on the Automation Account, registers the VM, and installs the HybridWorkerForWindows extension. See Hybrid Worker VM Requirements.

What You Still Need to Do Manually After the Installer

The installer does not handle the following steps, which must be completed manually:

  1. Disable public access on individual resources (SQL, Redis, Storage, Key Vault, Service Bus, Cognitive Services, App Service, etc.). The installer creates private endpoints but leaves public network access enabled so that the installer itself (and any current connections) can keep working. Once you have verified private connectivity, lock each resource down via its Networking blade.
  2. Storage Account table endpoint — the installer creates a private endpoint for blob storage only. If your workload accesses Azure Table Storage, you need to create an additional private endpoint for the table sub-resource manually. See Storage Account.
  3. Upgrade existing resources to a supported SKU — the SKU enforcement above only applies to newly created resources. If you re-run the installer against an environment that already has a Basic Redis cache, Standard Service Bus namespace or Basic SQL Database, those will not be upgraded automatically (Service Bus in particular cannot be upgraded in place — see the note below). Plan to recreate or migrate them before enabling networking.
  4. Application Insights & Log Analytics — private link scope configuration for monitoring. See Application Insights and Log Analytics.
  5. Disable call imports — webhook-based call tracking does not work with private endpoints. See Disable Call Imports.
  6. Power BI — if using PBI reports with private SQL. See Power BI Service.

Hybrid Worker VM Requirements

When VNet is enabled, the installer also configures an Azure Automation Hybrid Worker Group so that automation runbooks can execute within the private network. The installer automatically:

  • Creates a hybrid worker group in the Automation Account
  • Installs the HybridWorkerForWindows VM extension on the specified VM
  • Registers the VM as a hybrid worker with the Automation Account

VM prerequisites for the hybrid worker:

Requirement Details
Operating System Windows Server 2016 or later (64-bit)
PowerShell PowerShell 7.2 or later must be installed on the VM (download)
.NET Framework .NET Framework 4.6.2 or later
Network The VM must be connected to the same VNet (or a peered VNet) used by the private endpoints
Outbound connectivity The VM needs outbound HTTPS (443) access to Azure Automation endpoints and Azure AD for registration

Note: The hybrid worker extension installation is treated as non-fatal by the installer. If it fails (e.g. the VM is unreachable or missing prerequisites), the rest of the installation will continue. You can verify the extension status in the Azure portal under Virtual Machine → Extensions + applications and retry manually if needed.

For full details on hybrid worker requirements, see the Azure Automation Hybrid Runbook Worker documentation.

Limitations

In this mode, the system does have some limitations around data collection and configuration.

  • Due to how calls are tracked with Graph pushing notifications to the app service, this won't be possible with a privately protected endpoint.

The lack of calls can be mitigated if the only app service has a public endpoint, but assuming that too is private, it's impossible to receive webhook notifications from Graph API for calls and therefore we can't log call data.


Manual Setup Guide

The following sections describe how to configure private endpoints manually, either as an alternative to the installer or to complete the steps the installer does not cover.

VNet Configuration

For these steps to work, we need a virtual network (VNet) pre-configured with x2 subnets - a default one and then one for app services.

A screenshot of a phone Description automatically generated

All the dependencies will use the default subnet, and the app service will integrate with a second one.

Private endpoints are created on the VNet and add DNS zones for each resource as needed, so that each service has a private, internal IP address.

Example: for App Insights, when we create the endpoint, we get a new network interface card for it with a private IP address (10.0.0.X) + a DNS "westeurope-5.in.ai.privatelink.monitor.azure.com" (same as the public address).

A blue screen with white text Description automatically generated

In this case, the browser will now route requests to the private address, will pass internally to the App Insights instance and therefore be accepted.

In our example we're using Azure DNS, so resource name registration happens automatically.

A screenshot of a computer Description automatically generated

Your own infrastructure may have different requirements.

Important: if you have your own DNS infrastructure to integrate with, please add verification steps for each Azure service added below.

Configure Services for Private Access Only

In this guide, we assume that you have a working system created by either the installer or the manual configuration method.

Note: If you used the installer with VNet enabled, private endpoints and DNS zones for the services below (SQL, App Service, Redis, blob Storage, Key Vault, Service Bus, Cognitive Services and — if Graph usage reports are enabled — the Automation Account) are already created. You may still need to disable public access on each resource.

App Service

Add a private endpoint so access to it is restricted. In the "networking" blade of the app service:

A screenshot of a computer Description automatically generated

https://learn.microsoft.com/en-us/azure/private-link/private-endpoint-overview

Next, we need to integrate the app service into our VNet so the web-jobs can access private resources. Back in the networking blade click "VNet integration"

A screenshot of a computer Description automatically generated

A screenshot of a computer Description automatically generated

Note: When using the installer with VNet enabled, this outbound VNet integration is configured automatically against a dedicated app-integration subnet (delegated to Microsoft.Web/serverFarms). The WEBSITE_VNET_ROUTE_ALL and WEBSITE_DNS_SERVER app settings are also set automatically. The steps below only apply when configuring an existing environment manually.

VNet Integration Subnet Requirement

App Service VNet integration requires a dedicated subnet delegated to Microsoft.Web/serverFarms. You cannot use the same subnet that contains your private endpoints or VMs. The installer creates this subnet automatically (default name app-integration, default range 10.0.2.0/24). If you are configuring this manually, create one with:

az network vnet subnet create \
  --resource-group <your-rg> \
  --vnet-name <your-vnet> \
  --name app-integration \
  --address-prefixes 10.0.1.0/24 \
  --delegations Microsoft.Web/serverFarms

A /28 is the minimum size, but /24 is recommended. Once created, select this subnet when configuring VNet integration on the App Service.

Troubleshooting: If you disable public access on Service Bus (or other resources) and the App Service returns 401 - IP has been prevented to connect to the endpoint, this means the App Service is still routing traffic via its public IP. Verify:

  1. VNet integration is configured with the dedicated subnet above
  2. Route All is enabled (WEBSITE_VNET_ROUTE_ALL = 1)
  3. The privatelink.servicebus.windows.net (or relevant) private DNS zone is linked to the VNet used by the App Service integration

You can confirm DNS resolution from the App Service using Kudu console: nameresolvercli <namespace>.servicebus.windows.net — it should return the private IP (e.g. 10.0.0.x), not a public IP.

Now, any HTTP calls from outside the private network will not arrive at the app service.

SQL Server

Restrict public access and enable a private endpoint.

A screenshot of a computer Description automatically generated

A screenshot of a computer Description automatically generated

This will create a network interface for the private endpoint:

A screenshot of a computer Description automatically generated

Select the same VNet.

A screenshot of a computer Description automatically generated

You may wish to create a specific IP address. We're going for automatic configuration.

A screenshot of a computer Description automatically generated

Now, apps need to use this internal address to connect to any database on this server.

Redis Cache

A similar setup with Redis is needed.

Note: Redis requires at least Standard SKU for private endpoint support. The installer creates new caches at Standard when networking is enabled, but does not upgrade an existing Basic cache — you need to recreate it (or upgrade it manually in the Azure portal) before the private endpoint can be added.

https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-private-link

A screenshot of a computer Description automatically generated

A screenshot of a computer Description automatically generated

A screenshot of a computer Description automatically generated

Service Bus

Private endpoints and network isolation require a Premium tier service-bus.

Note: The installer creates new Service Bus namespaces at Premium tier when VNet is enabled. However, existing non-Premium namespaces cannot be upgraded in-place - Azure does not support this. The installer will log an error with a link to the migration documentation. You will need to create a new Premium namespace and migrate manually.

Teams calls import needs Service Bus on Premium in a private deployment

Service Bus is used by one thing: the Teams calls import. It's the queue (graphcalls) that call-record notifications land in.

Because a private endpoint requires Premium, a private deployment has only three valid combinations. If a Standard namespace has public network access disabled, it can be reached neither publicly nor privately, and the calls import fails at runtime with a message that looks like an authentication problem but isn't:

Put token failed. status-code: 401, status-description: Ip has been prevented to connect to the endpoint.
   ... Virtual Network service endpoints / IP Filters ...

That's a network-layer rejection — the connection is blocked before the token is even checked — so no amount of RBAC/permission fixing will help.

Option What to do Result
(a) Premium + private endpoint (recommended) Migrate the namespace to Premium and re-run the installer Fully private, Teams calls import works
(b) Keep Service Bus public Leave public network access enabled on the namespace only Teams calls import works; the namespace is the one resource still reachable publicly
(c) Turn the feature off Untick Service Bus in the installer (ServiceBusEnabled) and disable the Teams calls import No Service Bus at all, no calls data

What the installer does about it: if you choose a private deployment while the Teams calls import is on, the installer shows a warning dialog before the install starts. If it then finds the existing namespace is not Premium, it deliberately leaves public network access enabled on that namespace (option b) rather than disabling it and leaving the queue unreachable, logs a prominent warning, and repeats it in the install summary with a suggested next step. It also skips creating the Service Bus private endpoint and its privatelink.servicebus.windows.net DNS zone, since a VNet-linked zone with no endpoint behind it would break resolution of the public endpoint too.

The web portal's Administration → Service health page also flags this: if the Teams calls queue can't be read and the error looks like an IP/VNet block, the Service Bus component shows a warning that names the Premium requirement.

A screenshot of a computer Description automatically generated

The service bus created by default (without VNet) is a basic tier one, so we need to migrate through the standard tier too:

Screens screenshot of a screenshot of a screenshot Description automatically generated

...meaning we need to create a standard tier namespace, and also a premium one.

A yellow and purple text Description automatically generated

A screenshot of a computer Description automatically generated

Once your options are configured, you can start the migration from basic to premium.

A screenshot of a computer screen Description automatically generated

Once done we can create private endpoints as before:

A screenshot of a computer Description automatically generated

As before this will create a network interface in the selected VNet + register with DNS if managed by Azure.

Storage Account

For storage, we need to configure private endpoints for table + blob services.

Note: The installer creates a private endpoint for blob storage only. If your workload uses Azure Table Storage, you need to create an additional private endpoint for the table sub-resource manually.

A screenshot of a computer Description automatically generated

Enable private endpoints for blob & table storage.

A screenshot of a computer Description automatically generated

Ensure the right sub-resource is selected.

A screenshot of a computer Description automatically generated

DNS configuration is done if managed by Azure. Manual configuration will be needed if DNS is handled by your own infrastructure.

A screenshot of a computer Description automatically generated

Repeat the same for blob storage.

Key Vault

The installer creates a private endpoint for Key Vault automatically. To disable public access, go to the Key Vault networking blade and set "Allow access from" to "Private endpoint only".

Note: If public access is disabled before the installer finishes adding secrets, the installer will log an error (HTTP 403) and continue. You can add secrets manually afterwards from within the VNet.

Optional: Language Service

Language service is optionally used for Teams channel sentiment analysis and other areas of Microsoft 365. If your configuration doesn't include this, you don't need to follow this step.

A screenshot of a computer Description automatically generated

Disable public access and save changes.

A screenshot of a computer Description automatically generated

There's only one sub-resource:

A screenshot of a computer Description automatically generated

Configure how you want the endpoint to appear on the VNet:

A screenshot of a computer Description automatically generated

Specify DNS

A screenshot of a computer Description automatically generated

No changes should be needed for configuration thanks to the CNAME above mapping the public DNS to the private DNS.

Application Insights

Note: Application Insights private link scope is not configured by the installer and must be set up manually.

Access to App Insights ingestion and tracking is limited via "Azure Monitor Private Link Scopes" on the "Network Isolation" blade.

A screenshot of a web page Description automatically generated

Create new:

A screenshot of a computer Description automatically generated

Add a network interface for private endpoint scope: A screenshot of a computer Description automatically generated

A screenshot of a computer Description automatically generated

Configure DNS. There are a few services that App Insights need to have DNS for:

A screenshot of a computer Description automatically generated

One the scope & endpoint are added, you can configure Application Insights to use them.

A screenshot of a computer Description automatically generated

With public-network ingestion disabled, any attempts to log data will be denied. Here's an example response:

A computer screen shot of a program code Description automatically generated

Equally with reading the data:

A close-up of a document Description automatically generated

You can only now read/write telemetry data from a device on the same VNet.

Log Analytics

Configure the workspace in the same way as Application Insights.

A screenshot of a computer Description automatically generated

Important: if you don't configure log analytics with the same Azure Monitor Private Link Scope, no telemetry data will be readable.

Configure App Services

Once components have been configured, the app service configuration will need to be updated.

Note: If you used the installer with VNet enabled, the app settings WEBSITE_VNET_ROUTE_ALL and WEBSITE_DNS_SERVER are already configured. The connection strings (SQL, Redis, Storage, Service Bus) use the standard public DNS names which automatically resolve to private IPs via the private DNS zones. No manual connection string changes are needed in that case.

Disable Call Imports

As public endpoints are needed for webhooks and this is precisely what we've disabled, we should stop the solution from even trying to setup the webhook as it will fail and generate errors.

In the app-services configuration, disable the calls import:

A screenshot of a computer Description automatically generated

Save changes.

App Service Settings for VNet DNS Resolution

When using private endpoints, the app service must route outbound traffic through the VNet so that private DNS zones resolve correctly. The installer sets these automatically, but if configuring manually, add the following app settings:

Setting Value Purpose
WEBSITE_VNET_ROUTE_ALL 1 Routes all outbound traffic through the VNet (not just RFC1918)
WEBSITE_DNS_SERVER 168.63.129.16 Uses Azure-provided DNS which resolves private DNS zones

These settings require the app service to have outbound VNet integration configured (see App Service above).

Change SQL Connection

Note: If the installer created the environment with VNet enabled, the SQL connection string already uses the standard FQDN (e.g., myserver.database.windows.net) which resolves to the private IP via the privatelink.database.windows.net DNS zone. No manual change is needed — skip to the next section.

The following applies only when converting an existing (non-VNet) deployment to use private endpoints. Once you disable public network access on the SQL server, the web-jobs will crash with this error:

SqlException: Reason: An instance-specific error occurred while establishing a connection to SQL Server. Connection was denied since Deny Public Network Access is set to Yes. To connect to this server, use the Private Endpoint from inside your virtual network.

In the app services configuration, change the SQL connection DNS:

A screenshot of a computer Description automatically generated

Check app-service web job logs from a virtual machine on same VNet:

A screenshot of a computer Description automatically generated

Verify web-jobs are running:

A screenshot of a web jobs application Description automatically generated

Both web-jobs should be in the "running" state, without restarts.

Redis

Redis doesn't require a connection string change as a CNAME record is added so, in my example, "advanalyticsdev.redis.cache.windows.net" points to "advanalyticsdev.privatelink.redis.cache.windows.net", which is pointed at the local VNet IP address.

This means that no changes should be needed for the app-service to work with the old, public DNS.

Service Bus

Equally the service-bus DNS should still work for the same reasons.

Power BI Service (Optional)

The Power BI service will need to access the private endpoint for SQL if you're using PBI reports - https://learn.microsoft.com/en-us/power-bi/enterprise/service-security-private-links

Clone this wiki locally