This check flags Azure API Management instances that run without a managed identity, which forces you to store credentials in policies or configuration to reach backends and Key Vault. Turn on a system-assigned identity and grant it least-privilege access so APIM can authenticate to other Azure services without secrets.
API Management (APIM) sits at the front door of your APIs. It fronts backend services, pulls certificates and secrets from Key Vault, signs requests to downstream systems, and often integrates with storage, Service Bus, or event sources. Every one of those connections needs to authenticate somehow. Without a managed identity, that "somehow" usually ends up being a hardcoded key, a connection string, or a client secret baked into a named value or policy.
This Lensix check, apimgmt_nomanagedidentity, looks at each APIM service in your subscription and reports any that have no managed identity configured at all.
What this check detects
The check inspects the identity block of every API Management service. An APIM instance can have:
- A system-assigned identity tied to the lifecycle of the APIM resource itself
- One or more user-assigned identities that you create and attach independently
- Both
- None — which is what this check flags
If the identity type comes back as None, the service has no Azure AD identity it can present to other services. Any authentication to Key Vault, backends, or other Azure resources then depends on long-lived secrets you have to manage yourself.
Note: A managed identity is a service principal in Microsoft Entra ID (formerly Azure AD) that Azure manages for you. There is no password or certificate to rotate, and the credential never appears in your code or configuration. Azure handles issuing and rotating the underlying credentials automatically.
Why it matters
The absence of a managed identity is rarely a vulnerability on its own. It is a symptom that almost always leads to one. When APIM cannot authenticate using its own identity, teams reach for the path of least resistance, and that path involves secrets sitting in places they should not be.
Secrets end up in named values and policies
To call a secured backend or read from Key Vault, an APIM instance without an identity needs a key or connection string. Those typically land in APIM named values or directly in inbound policy XML. Named values can be marked secret, but they are still secrets you own, rotate, and risk leaking. Policy XML often ends up in source control or ARM templates, and a connection string committed to a repo is a breach waiting to happen.
Key Vault integration breaks or gets bypassed
APIM can reference certificates and secrets directly from Key Vault, but that integration requires a managed identity with access to the vault. Without an identity, teams either upload certificates straight into APIM (losing central rotation) or skip Key Vault entirely. Both outcomes weaken your secret hygiene.
Warning: Custom domain certificates referenced from Key Vault rely on the managed identity to fetch updates. If the identity is missing or loses access, APIM keeps serving the cached certificate until it expires, then fails. Expired gateway certificates cause outages that are painful to diagnose under pressure.
Wider blast radius if a secret leaks
A leaked managed identity token is short-lived and scoped. A leaked connection string or account key often grants broad, standing access and stays valid until someone notices and rotates it. In an incident, the difference between a token that expires in an hour and a key that has been valid for two years is enormous.
How to fix it
The fix has two parts: enable an identity on the APIM service, then grant that identity least-privilege access to whatever it needs to reach.
Step 1: Enable a system-assigned identity
For most setups, a system-assigned identity is the simplest choice because it is created and destroyed with the APIM service. Enable it with the CLI:
az apim update \
--name my-apim-instance \
--resource-group my-rg \
--set identity.type=SystemAssigned
Confirm the identity was created and grab its principal ID:
az apim show \
--name my-apim-instance \
--resource-group my-rg \
--query identity
You should see output similar to this:
{
"principalId": "11111111-2222-3333-4444-555555555555",
"tenantId": "66666666-7777-8888-9999-000000000000",
"type": "SystemAssigned"
}
Step 2: Grant least-privilege access
An identity with no permissions does nothing useful. Grant it exactly what it needs. For Key Vault access using RBAC, assign the Key Vault Secrets User role scoped to the specific vault:
PRINCIPAL_ID=$(az apim show \
--name my-apim-instance \
--resource-group my-rg \
--query identity.principalId -o tsv)
az role assignment create \
--assignee "$PRINCIPAL_ID" \
--role "Key Vault Secrets User" \
--scope "/subscriptions//resourceGroups/my-rg/providers/Microsoft.KeyVault/vaults/my-keyvault"
Note: If your Key Vault still uses access policies instead of RBAC, grant the identity get and list permissions on secrets and certificates with az keyvault set-policy --object-id $PRINCIPAL_ID instead of a role assignment.
Step 3: Use the identity in policies
Once the identity exists and has access, reference it in policy instead of carrying a key. For example, to authenticate an outbound call to a backend using the managed identity:
<inbound>
<authentication-managed-identity resource="https://my-backend.azurewebsites.net" />
</inbound>
Then go back and delete the named values and connection strings you no longer need.
Danger: Before deleting any named value or key that a live policy depends on, confirm every consuming policy has been switched to the managed identity. Removing a secret that production traffic still relies on will start failing requests immediately, with no gradual rollout.
Fixing it with Bicep or ARM
If you provision APIM through infrastructure as code, set the identity in the template so the fix is durable. In Bicep:
resource apim 'Microsoft.ApiManagement/service@2023-05-01-preview' = {
name: 'my-apim-instance'
location: location
sku: {
name: 'Developer'
capacity: 1
}
identity: {
type: 'SystemAssigned'
}
properties: {
publisherEmail: '[email protected]'
publisherName: 'Example Ops'
}
}
For Terraform, add an identity block to the azurerm_api_management resource:
resource "azurerm_api_management" "main" {
name = "my-apim-instance"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
publisher_name = "Example Ops"
publisher_email = "[email protected]"
sku_name = "Developer_1"
identity {
type = "SystemAssigned"
}
}
Tip: If you need the same identity to persist across redeployments or be shared by several services, use a user-assigned identity instead. Create it once, attach it everywhere, and your role assignments survive even if you tear down and recreate the APIM instance.
How to prevent it from happening again
Fixing one instance by hand is fine. Stopping the next dozen from drifting back requires a gate that runs before resources reach production.
Enforce with Azure Policy
Azure Policy can audit or deny APIM services that lack an identity. A deny effect blocks non-compliant deployments outright. Here is a policy rule that flags any APIM service with no identity configured:
{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.ApiManagement/service"
},
{
"anyOf": [
{
"field": "identity.type",
"exists": false
},
{
"field": "identity.type",
"equals": "None"
}
]
}
]
},
"then": {
"effect": "audit"
}
}
Start with audit to measure your fleet, then switch the effect to deny once you have remediated the existing instances and confirmed your pipelines set identities by default.
Gate it in CI/CD
Catch the problem before it ever reaches Azure by scanning IaC in the pipeline. Tools like Checkov and tfsec inspect Terraform and Bicep for a missing identity block. A simple pipeline step fails the build when an APIM resource ships without one:
checkov -d ./infra --framework terraform
Tip: Run Lensix continuously against your live subscriptions so that drift gets caught even when changes bypass your pipeline. Console clicks and emergency hotfixes are exactly how a manually disabled identity slips back in unnoticed.
Best practices
- Default to managed identities everywhere. Treat any backend, Key Vault, or storage connection that uses a key as a temporary measure to be replaced, not a permanent design.
- Prefer user-assigned identities for shared or long-lived setups. They decouple the identity from the resource lifecycle and let you reuse one principal across multiple services, which simplifies role management.
- Scope permissions tightly. Assign roles at the individual resource scope, not the resource group or subscription. APIM should reach only the vaults and backends it actually uses.
- Reference Key Vault for all certificates and secrets. Combined with a managed identity, this gives you central rotation and removes secrets from APIM configuration entirely.
- Audit named values regularly. Periodically review named values for secrets that could be replaced by an identity-based call. Every key you remove is one fewer thing to rotate and one fewer thing to leak.
- Monitor identity health. Alert on certificate fetch failures and authentication errors so a broken identity surfaces before it becomes an outage.
A managed identity is one of the cheapest security wins available in Azure. It costs nothing, removes secrets from your configuration, and shrinks the blast radius of a leak. If an APIM instance shows up on this check, enabling an identity and wiring it into your backend and Key Vault connections is almost always the right move.

