Back to Checks
Container Registry uses a private endpoint (Private Link)
containerregistry_uses_private_link
Service: containerregistrySeverity: high
OfficialBuilt-inVerified
Categories:internet-exposedtrust-boundaries
Resource Type:microsoft.containerregistry/registries
Azure Container Registry access via Private Endpoints (Azure Private Link). Registries with private endpoint connections use private IPs; others rely on the public endpoint.
Risk
Publicly reachable registries expand attack surface for credential stuffing, token abuse, and scanning. A compromise enables unauthorized pull/push, causing image data leakage and supply-chain tampering. Public routing weakens network isolation, impacting the confidentiality and integrity of images and metadata.
Run this check with Prowler
Run in Prowler CloudRun
prowler azure --checks containerregistry_uses_private_linkRecommendation
Use Private Link with private endpoints and set Public network access: Disabled.
- Restrict access to trusted VNets/subnets
- Prefer private endpoints over service endpoints
- Enforce least privilege on registry actions
- Configure private DNS for the registry FQDN
- Monitor access logs for defense in depth
Remediation
CLI
az network private-endpoint create --resource-group <example_resource_name> --name <example_resource_name> --vnet-name <example_resource_name> --subnet <example_resource_name> --private-connection-resource-id <example_resource_id> --group-ids registry --connection-name <example_resource_name>Terraform
resource "azurerm_private_endpoint" "<example_resource_name>" {
name = "<example_resource_name>"
location = "<location>"
resource_group_name = "<example_resource_name>"
subnet_id = "<example_subnet_id>"
private_service_connection {
name = "<example_resource_name>"
private_connection_resource_id = "<example_resource_id>" # Critical: ACR resource ID
subresource_names = ["registry"] # Critical: Target 'registry' subresource to enable Private Link
}
}NativeIaC
// Create a Private Endpoint to ACR
resource privateEndpoint 'Microsoft.Network/privateEndpoints@2025-05-01' = {
name: '<example_resource_name>'
location: resourceGroup().location
properties: {
subnet: {
id: '<example_subnet_id>'
}
privateLinkServiceConnections: [
{
name: '<example_resource_name>'
properties: {
privateLinkServiceId: '<example_resource_id>' // Critical: ACR resource ID to connect
groupIds: ['registry'] // Critical: Target the 'registry' subresource to enable Private Link
}
}
]
}
}Other
1In Azure Portal, go to Container registries > select your registry
2Navigate to Settings > Networking > Private endpoints tab
3Click + Private endpoint, enter a name, select your VNet and Subnet
4Set Resource type to Microsoft.ContainerRegistry/registries and Target subresource to registry
5Click Review + create, then Create
Check Code
from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.containerregistry.containerregistry_client import (
containerregistry_client,
)
class containerregistry_uses_private_link(Check):
def execute(self) -> list[Check_Report_Azure]:
findings = []
for subscription, registries in containerregistry_client.registries.items():
subscription_name = containerregistry_client.subscriptions.get(
subscription, subscription
)
for container_registry_info in registries.values():
report = Check_Report_Azure(
metadata=self.metadata(), resource=container_registry_info
)
report.subscription = subscription
report.status = "FAIL"
report.status_extended = f"Container Registry {container_registry_info.name} from subscription {subscription_name} ({subscription}) does not use a private link."
if container_registry_info.private_endpoint_connections:
report.status = "PASS"
report.status_extended = f"Container Registry {container_registry_info.name} from subscription {subscription_name} ({subscription}) uses a private link."
findings.append(report)
return findings