Skip to main content
emnode
Compliance Medium severity MCSB DP-6

Microsoft Defender for Cloud · Azure API Management

API Management secret named values should be stored in Azure Key Vault

Written and reviewed by Emnode · Last reviewed

What does the recommendation "API Management secret named values should be stored in Azure Key Vault" check?

Flags any API Management instance that holds a 'secret' type named value inline rather than as a reference to an Azure Key Vault secret. Named values are the reusable key-value pairs APIM injects into policies, and they come in three flavours: plain, secret (encrypted at rest inside APIM), and Key Vault reference. The control only objects to the secret flavour: a credential encrypted in APIM's own store instead of pointed at a vault. It does not inspect plain named values, the contents of the secret, or whether the referenced vault is itself hardened. It also does not cover secrets passed through other channels such as backend credentials or certificate stores.

Why does "API Management secret named values should be stored in Azure Key Vault" matter?

A secret named value kept inside APIM lives only in that instance: there is no central rotation, no per-secret access policy, and no audit trail of who read it. When the credential changes you must hunt down and re-enter it by hand, so stale or shared secrets linger and a leak from one team's policy exposes a value nobody else can see being used. Routing the named value through Key Vault gives you one governed copy: granular access control, logged reads, and automatic refresh in APIM within four hours of a rotation in the vault. That turns secret rotation from a manual, easily-skipped chore into a property of the platform, which is exactly what an auditor expects to see for any system handling production API credentials.

How do I fix "API Management secret named values should be stored in Azure Key Vault"?

  1. Enable a managed identity on the API Management instance and grant it read access to the vault: 'az apim update -n <apim> -g <rg> --enable-managed-identity true', then give that identity the Get and List secret permissions, for example 'az keyvault set-policy -n <vault> --object-id <apim-identity-objectId> --secret-permissions get list' (or assign the Key Vault Secrets User role if the vault uses RBAC).
  2. Recreate each secret named value as a Key Vault reference. In the portal set the named value's Type to 'Key vault' and paste the secret identifier without a version so rotation is automatic; the Azure CLI cannot create vault-backed named values, so use Bicep, ARM, or the REST API, e.g. a Microsoft.ApiManagement/service/namedValues resource with keyVault.secretIdentifier set to 'https://<vault>.vault.azure.net/secrets/<name>'.
  3. Assign the built-in policy 'API Management secret named values should be stored in Azure Key Vault' to keep the estate compliant: pid=$(az policy definition list --query "[?displayName=='API Management secret named values should be stored in Azure Key Vault'].name" -o tsv); az policy assignment create --name apim-nv-keyvault --policy "$pid" --scope <scope>. It defaults to Audit and supports Deny if you want to block new inline secrets outright.

Remediation script · bash

# 1. Enable the Defender for APIs plan on the subscription so onboarded APIs are inspected.
az security pricing create --name Api --tier Standard

# 2. Disable the deprecated direct management endpoint (retired 15 March 2025).
#    'customProperties' on the service controls this gateway behaviour.
az apim update --name apim-prod --resource-group rg-platform \
  --set 'properties.customProperties."Microsoft.WindowsAzure.ApiManagement.Gateway.ManagementEndpoint"=false'

# 3. Re-enable backend certificate chain and name validation on a backend that
#    had it switched off. There is no native 'az apim backend' TLS flag, so PUT
#    the documented 'tls' block via the management API (api-version 2024-05-01).
sub=$(az account show --query id -o tsv)
az rest --method put \
  --uri "https://management.azure.com/subscriptions/$sub/resourceGroups/rg-platform/providers/Microsoft.ApiManagement/service/apim-prod/backends/payments-backend?api-version=2024-05-01" \
  --body '{"properties":{"url":"https://payments.internal/","protocol":"http","tls":{"validateCertificateChain":true,"validateCertificateName":true}}}'

# 4. Ratchet it shut: audit any instance whose management endpoint stays enabled.
#    Look the built-in policy up by display name; never hardcode a definition GUID.
pid=$(az policy definition list \
  --query "[?displayName=='API Management direct management endpoint should not be enabled'].name" -o tsv)
az policy assignment create \
  --name audit-apim-mgmt-endpoint \
  --policy "$pid" \
  --scope "/subscriptions/$sub"

Full walkthrough (console steps, edge cases and verification) in the lesson Harden Azure API Management.

Is "API Management secret named values should be stored in Azure Key Vault" a false positive?

A throwaway named value in a sandbox or proof-of-concept instance, where the secret is a dummy token with no production reach, can stay inline without real risk. The control still flags it because it judges the storage mechanism, not the sensitivity of the value, so set the policy assignment to audit-only or scope an exemption to that resource group rather than standing up a vault and managed identity just to satisfy the check.