What it is
An App Service or Function App with no managed identity assigned (identity.type is None or missing entirely). The app still talks to SQL, Storage, Key Vault, and every other backend — it just does it with connection strings and account keys stored in app settings. A managed identity is a free Entra ID identity Azure runs for the app, and its absence is a reliable signal that credentials are living in configuration instead.
Why it happens
A managed identity is opt-in. New App Services are created without one, every quickstart that pastes a connection string into app settings works on the first try, and the app never breaks in a way that forces the question. So the secret-based wiring that got the first deployment working becomes the permanent architecture.
The trap is that secrets in app settings feel contained but aren't. Anyone with control-plane read access to the site's configuration can list them, they get copied into CI variables and local .env files, and account keys don't expire on their own. Rotation means chasing every copy, so rotation quietly stops happening.
What it costs / blast radius
There is no direct Azure cost here — managed identities are free, and this entry costs you nothing on the bill. The harm is the credential class itself. (Azure behavior; authored assessment.)
A leaked storage connection string or SQL password is full data-plane access from anywhere, with no identity behind it: no conditional access, no MFA, and an audit log that shows the app's key was used, not who used it. Every backend the app touches multiplies the copies in configs, pipelines, and laptops. Assigning a managed identity and switching to Entra ID auth doesn't just harden one connection — it removes the entire category of "secret someone can copy" for that app.
See it
resource app 'Microsoft.Web/sites@2024-04-01' = {
name: 'corp-api'
location: location
// no identity block — the app has no Entra ID identity of its own
properties: {
serverFarmId: plan.id
siteConfig: {
appSettings: [
{
name: 'STORAGE_CONNECTION_STRING'
value: 'DefaultEndpointsProtocol=https;AccountName=corpdata;AccountKey=...'
}
]
}
}
}resource app 'Microsoft.Web/sites@2024-04-01' = {
name: 'corp-api'
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: plan.id
}
}
// Grant the identity data-plane access instead of shipping a key.
// (Storage Blob Data Contributor shown; scope to what the app needs.)
resource blobAccess 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
scope: storage
name: guid(storage.id, app.id, 'blob-data-contributor')
properties: {
principalId: app.identity.principalId
principalType: 'ServicePrincipal'
roleDefinitionId: subscriptionResourceId(
'Microsoft.Authorization/roleDefinitions',
'ba92f5b4-2d11-453d-a403-e96b0029c9fe'
)
}
}How StratoLens helps
StratoLens flags every App Service and Function App running without a managed identity, automatically and continuously, across every subscription — inside your own tenant. The apps still wired up with connection strings stop being something you find one incident at a time.