Back to Checks
azure

Key Vault uses private endpoints

keyvault_private_endpoints
Service: keyvaultSeverity: high
OfficialBuilt-inVerified
Categories:internet-exposedtrust-boundaries
Resource Type:microsoft.keyvault/vaults

Azure Key Vault has private endpoint connections to serve secret and key operations over a private IP within your virtual network via Azure Private Link.

Prowler logoProwlerprowler-provider-azure

Risk

Without private endpoints, the vault relies on a public endpoint, expanding exposure to scanning and misconfigured allowlists. Egress controls are harder to enforce, enabling unauthorized secret retrieval for data exfiltration and potential key misuse, impacting confidentiality and integrity.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler azure --checks keyvault_private_endpoints

Recommendation

Enable Private Endpoints for each Key Vault and disable public network access. Use private DNS so the vault FQDN resolves to the private IP. Apply least privilege with RBAC and managed identities, restrict traffic with NSGs and routing, and monitor access logs as part of defense in depth.

Remediation

CLI

az network private-endpoint create --name <example_resource_name> --resource-group <example_resource_name> --location <LOCATION> --vnet-name <example_resource_name> --subnet <example_resource_name> --private-connection-resource-id <example_resource_id> --group-ids vault --connection-name <example_resource_name>

Terraform

# Create a Private Endpoint for an existing Key Vault
resource "azurerm_private_endpoint" "<example_resource_name>" {
  name                = "<example_resource_name>"
  location            = "<LOCATION>"
  resource_group_name = "<example_resource_name>"
  subnet_id           = "<example_resource_id>" # Critical: subnet resource ID for the private endpoint NIC

  private_service_connection {
    name                           = "<example_resource_name>"
    private_connection_resource_id = "<example_resource_id>" # Critical: Key Vault resource ID to connect
    subresource_names              = ["vault"]               # Critical: targets Key Vault subresource to create the connection
  }
}

NativeIaC

// Create a Private Endpoint for an existing Key Vault
resource pe 'Microsoft.Network/privateEndpoints@2021-08-01' = {
  name: '<example_resource_name>'
  location: '<LOCATION>'
  properties: {
    subnet: {
      id: '<example_resource_id>' // Critical: subnet resource ID where the private endpoint NIC will be placed
    }
    privateLinkServiceConnections: [
      {
        name: '<example_resource_name>'
        properties: {
          privateLinkServiceId: '<example_resource_id>' // Critical: Key Vault resource ID to connect to
          groupIds: [ 'vault' ] // Critical: targets the Key Vault subresource to create the private endpoint connection
        }
      }
    ]
  }
}

Other

1In Azure portal, open your Key Vault
2Go to Networking > Private endpoint connections > + Create
3Basics: select Subscription and Resource group, then Next
4Resource: Service = Microsoft.KeyVault/vaults (your vault is preselected), Subresource = vault, Next
5Configuration: choose Virtual network and Subnet, then Next and Create
6Wait for the connection state to show Approved (auto-approves if you have permission)

Check Code

from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.keyvault.keyvault_client import keyvault_client


class keyvault_private_endpoints(Check):
    def execute(self) -> Check_Report_Azure:
        findings = []
        for subscription, key_vaults in keyvault_client.key_vaults.items():
            subscription_name = keyvault_client.subscriptions.get(
                subscription, subscription
            )
            for keyvault in key_vaults:
                report = Check_Report_Azure(metadata=self.metadata(), resource=keyvault)
                report.subscription = subscription
                report.status = "FAIL"
                report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription_name} ({subscription}) is not using private endpoints."
                if (
                    keyvault.properties
                    and keyvault.properties.private_endpoint_connections
                ):
                    report.status = "PASS"
                    report.status_extended = f"Keyvault {keyvault.name} from subscription {subscription_name} ({subscription}) is using private endpoints."
                findings.append(report)
        return findings