Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This article walks you through the prerequisites for network hardening and how to create private endpoints for Microsoft Discovery workspaces and bookshelves. Network hardening is enabled by default - the Discovery control plane automatically deploys Network Security Perimeters, private endpoints, and virtual network injection for managed resources. For an overview of what these features are and why they matter, see Network security for Microsoft Discovery.
Prerequisites
- An Azure subscription with the Microsoft.Discovery resource provider registered.
- Azure CLI 2.50+ or Azure PowerShell 10.0+.
- Owner or Contributor role on the subscription (required for custom role and role assignment creation).
- A virtual network with dedicated subnets for:
- Agent workloads
- Private endpoints
- Workspace services
Important
Each Discovery resource (workspace, bookshelf, supercomputer) requires its own unique, non-overlapping subnets. Subnets can't be shared across different Discovery resource instances. Plan your virtual network address space accordingly when deploying multiple resources.
Assign the NSP Perimeter Joiner role
The Discovery control plane needs permission on your subscription to create NSP inbound access rules. Create a custom role and assign it to the Discovery control-plane service App service principal.
Verify the service principal
The Discovery first-party app (Discovery control-plane service App) has the following identity:
| Property | Value |
|---|---|
| Application (client) ID | 92c174ac-8e41-4815-a1b7-d81b19ab03ce |
| Display name | Discovery control-plane service App |
Verify the service principal exists in your tenant:
az ad sp show --id 92c174ac-8e41-4815-a1b7-d81b19ab03ce \
--query "{displayName:displayName, objectId:id, appId:appId}"
Tip
If the service principal doesn't exist in your tenant, create it:
az ad sp create --id 92c174ac-8e41-4815-a1b7-d81b19ab03ce
Create the custom role definition
Create a file named nsp-perimeter-joiner-role.json. Replace <your-subscription-id> with your Azure subscription ID.
{
"Name": "Discovery NSP Perimeter Joiner",
"Description": "Allows the Microsoft Discovery control plane to create NSP inbound access rules for network-hardened workspaces.",
"Actions": [
"Microsoft.Network/networkSecurityPerimeters/joinPerimeterRule/action",
"Microsoft.Network/locations/networkSecurityPerimeterOperationStatuses/read"
],
"NotActions": [],
"DataActions": [],
"NotDataActions": [],
"AssignableScopes": [
"/subscriptions/<your-subscription-id>"
]
}
Tip
Azure subscriptions have a limit on the number of custom roles. If you've reached the limit, delete any unused custom roles before creating the Discovery NSP Perimeter Joiner role. Check existing custom roles with az role definition list --custom-role-only.
az role definition create --role-definition nsp-perimeter-joiner-role.json
Note
If role definition creation fails with the error "A custom role with the same name already exists in this directory," it means someone in your tenant has already created this role. Work with them to add your subscription to the role's assignable scopes by appending /subscriptions/<your-subscription-id> (replace with your subscription ID) to the AssignableScopes of the existing custom role.
Assign the role to the Discovery Control Plane
SUBSCRIPTION_ID=$(az account show --query id -o tsv)
az role assignment create \
--assignee "92c174ac-8e41-4815-a1b7-d81b19ab03ce" \
--role "Discovery NSP Perimeter Joiner" \
--scope "/subscriptions/$SUBSCRIPTION_ID"
Verify the role assignment
az role assignment list \
--assignee "92c174ac-8e41-4815-a1b7-d81b19ab03ce" \
--scope "/subscriptions/$SUBSCRIPTION_ID" \
--query "[].{role:roleDefinitionName, scope:scope}" \
-o table
Expected output:
Role Scope
--------------------------------- ------------------------------------------
Discovery NSP Perimeter Joiner /subscriptions/<your-subscription-id>
Assign Reader to the Discovery service principal
The Discovery data-plane service app also requires Reader access at subscription level to enumerate resources and validate network configurations:
az role assignment create \
--assignee "92c174ac-8e41-4815-a1b7-d81b19ab03ce" \
--role "Reader" \
--scope "/subscriptions/$SUBSCRIPTION_ID"
Subnet requirements for workspaces and bookshelves
Workspaces and bookshelves require dedicated subnets for their managed resources. For a complete end-to-end deployment including all resources, see End-to-end network-hardened deployment.
| Resource | Required subnets | Subnet delegation |
|---|---|---|
| Workspace | workspaceSubnet, agentSubnet, privateEndpointSubnet |
Microsoft.App/environments on workspace and agent subnets |
| Bookshelf | searchSubnet, privateEndpointSubnet |
Microsoft.App/environments on search subnet |
Important
Subnets can't be reused across workspaces or bookshelves. Each workspace and each bookshelf requires its own unique, non-overlapping subnets. This is an Azure Container Apps (ACA) restriction - each delegated subnet can only be associated with a single Container Apps Environment. Plan your virtual network address space accordingly when deploying multiple resources.
Create private endpoints for data-plane access
Private endpoints route data-plane API traffic through the Azure backbone instead of the public internet. For supported resource types and how private endpoints work, see Network security for Microsoft Discovery.
Prerequisites
- A provisioned Microsoft Discovery workspace or bookshelf resource.
- A virtual network with a dedicated subnet for private endpoints.
- The Contributor or Microsoft Discovery Platform Administrator (Preview) role on the resource.
Create the private endpoint
Workspace private endpoint
az network private-endpoint create \
--name pe-my-workspace \
--resource-group myResourceGroup \
--vnet-name myVNet \
--subnet pe-subnet \
--private-connection-resource-id "/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Discovery/workspaces/{workspaceName}" \
--group-id workspace \
--connection-name my-workspace-connection
| Parameter | Required | Description |
|---|---|---|
--name |
Yes | Name of the private endpoint resource. |
--resource-group |
Yes | Name of the resource group where the private endpoint is created. |
--vnet-name |
Yes | The virtual network associated with the subnet. Omit if supplying a subnet ID. |
--subnet |
Yes | Name or ID of the subnet. If the subnet is in a different resource group or subscription, provide the full subnet resource ID instead of the name. |
--private-connection-resource-id |
Yes | The full Azure Resource Manager resource ID of the Discovery resource to connect to (workspace or bookshelf). |
--group-id |
Yes | The sub-resource group ID. Use workspace for workspaces or bookshelf for bookshelves. You can use az network private-link-resource list to get supported group IDs. |
--connection-name |
Yes | A descriptive name for the private link service connection. |
--location |
No | Azure region. Defaults to the resource group location. |
Configure private DNS
Create a private DNS zone and link it to your virtual network so that DNS queries resolve to the private endpoint IP address:
# Create the private DNS zone
az network private-dns zone create \
--resource-group myResourceGroup \
--name "privatelink.workspace.discovery.azure.com"
# Link the DNS zone to your virtual network
az network private-dns link vnet create \
--resource-group myResourceGroup \
--zone-name "privatelink.workspace.discovery.azure.com" \
--name link-my-vnet \
--virtual-network myVNet \
--registration-enabled false
# Create DNS zone group on the private endpoint (auto-creates A records)
az network private-endpoint dns-zone-group create \
--resource-group myResourceGroup \
--endpoint-name pe-my-workspace \
--name default \
--private-dns-zone "privatelink.workspace.discovery.azure.com" \
--zone-name workspace
Important
If you don't create the private DNS zone and link it to your virtual network, clients continue to use the public path even when a private endpoint exists. DNS resolution determines the traffic path.
Bookshelf private endpoint
To create a private endpoint for a bookshelf, use the same steps with the bookshelf resource ID, group ID bookshelf, and DNS zone privatelink.bookshelf.discovery.azure.com:
# Create the private endpoint
az network private-endpoint create \
--name pe-my-bookshelf \
--resource-group myResourceGroup \
--vnet-name myVNet \
--subnet pe-subnet \
--private-connection-resource-id "/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Discovery/bookshelves/{bookshelfName}" \
--group-id bookshelf \
--connection-name my-bookshelf-connection
# Create private DNS zone
az network private-dns zone create \
--resource-group myResourceGroup \
--name "privatelink.bookshelf.discovery.azure.com"
# Link DNS zone to virtual network
az network private-dns link vnet create \
--resource-group myResourceGroup \
--zone-name "privatelink.bookshelf.discovery.azure.com" \
--name link-my-vnet \
--virtual-network myVNet \
--registration-enabled false
# Create DNS zone group on the private endpoint
az network private-endpoint dns-zone-group create \
--resource-group myResourceGroup \
--endpoint-name pe-my-bookshelf \
--name default \
--private-dns-zone "privatelink.bookshelf.discovery.azure.com" \
--zone-name bookshelf
Supported resource types summary
| Resource type | Group ID | Private DNS zone |
|---|---|---|
Microsoft.Discovery/workspaces |
workspace |
privatelink.workspace.discovery.azure.com |
Microsoft.Discovery/bookshelves |
bookshelf |
privatelink.bookshelf.discovery.azure.com |
Verify connectivity
Check the private endpoint connection status:
az rest --method GET \
--url "https://management.azure.com/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Discovery/workspaces/{workspaceName}/privateEndpointConnections?api-version=2026-02-01-preview"
The connection should show status: Approved.
From a VM or compute resource within the same virtual network, verify DNS resolution and API connectivity:
# Verify DNS resolves to a private IP (10.x.x.x)
nslookup {workspaceName}.workspace.discovery.azure.com
# Test API connectivity
TOKEN=$(az account get-access-token --resource "https://discovery.azure.com/" --query accessToken -o tsv)
curl -sS -H "Authorization: Bearer $TOKEN" \
"https://{workspaceName}.workspace.discovery.azure.com/projects/{projectName}/investigations?api-version=2026-02-01-preview"
Disable public network access (optional)
To enforce private-endpoint-only access and block all public traffic to your workspace data-plane:
az rest --method PATCH \
--url "https://management.azure.com/subscriptions/{subId}/resourceGroups/{rg}/providers/Microsoft.Discovery/workspaces/{workspaceName}?api-version=2026-02-01-preview" \
--body '{"properties":{"publicNetworkAccess":"Disabled"}}'
Note
When publicNetworkAccess is set to Disabled, only traffic through private endpoints is allowed. Public internet requests receive a 403 Forbidden response. See Network security concepts for the full access matrix.
Approve or reject private endpoint connections
Discovery resources support autoapproval for private endpoints created within the same tenant. For cross-tenant connections, resource owners must manually approve:
# Approve a connection
az rest --method PATCH \
--url "https://management.azure.com/{privateEndpointConnectionId}?api-version=2026-02-01-preview" \
--body '{"properties":{"privateLinkServiceConnectionState":{"status":"Approved","description":"Approved by admin"}}}'
# Reject a connection
az rest --method PATCH \
--url "https://management.azure.com/{privateEndpointConnectionId}?api-version=2026-02-01-preview" \
--body '{"properties":{"privateLinkServiceConnectionState":{"status":"Rejected","description":"Not authorized"}}}'
Troubleshooting
"doesn't have permission to perform action 'joinPerimeterRule/action'"
The custom role assignment is missing or hasn't propagated.
- Verify the role assignment exists using the command in Assign the NSP Perimeter Joiner role.
- Wait up to 5 minutes for Azure RBAC propagation.
- Ensure the role is assigned at subscription scope, not resource group scope.
- Retry workspace creation - the operation is idempotent and safe to retry.
"Service principal not found"
The Discovery Control Plane service principal doesn't exist in your tenant yet:
az ad sp create --id 92c174ac-8e41-4815-a1b7-d81b19ab03ce
Then retry the role assignment.
Private endpoint approved but API returns errors
| Error | Likely cause | Resolution |
|---|---|---|
| 504 Gateway Timeout | Backend temporarily unavailable | Check if the public path also fails. If both fail, the service may be temporarily unavailable. |
| 401 Unauthorized | Token audience mismatch or missing RBAC | Verify the token is for https://discovery.azure.com/ and you have the required role on the resource. |
| DNS resolves to public IP | Private DNS zone not linked to virtual network | Create the DNS zone and virtual network link as described in Configure private DNS. |
Verify network hardening
After workspace provisioning completes, verify that network hardening is active:
# List NSP resources in the managed resource group
az rest --method GET \
--url "https://management.azure.com/subscriptions/{subId}/resourceGroups/{mrg}/providers/Microsoft.Network/networkSecurityPerimeters?api-version=2023-08-01-preview" \
| jq '.value[] | {name, location, properties}'
# List private endpoints in the managed resource group
az network private-endpoint list \
--resource-group {mrg} \
--query "[].{name:name, status:privateLinkServiceConnections[0].privateLinkServiceConnectionState.status}" \
-o table
You should see NSP resources in Enforced mode and private endpoints with Approved status.
DNS resolves to public IP despite private endpoint
If DNS queries return a public IP instead of your private endpoint IP:
- Verify the private DNS zone exists:
privatelink.workspace.discovery.azure.com - Verify the DNS zone is linked to your virtual network.
- Verify the DNS zone group is configured on the private endpoint.
- If using custom DNS servers, ensure they forward to Azure DNS (
168.63.129.16).
Next steps
- Network security for Microsoft Discovery - Understand the architecture, supported resource types, and limitations.
- End-to-end network-hardened deployment
- What is Azure Private Link?