Managed Identity & Least-Privilege Access
The best secret is the one that does not exist. Managed identities let services authenticate to each other and to the platform with no stored credential at all. Least privilege makes sure that whatever an identity can do is the minimum it needs. Together they remove both the secret to steal and the damage stealing it would cause.
Every credential you store is one you can leak, must rotate, and have to protect. Managed identities remove that risk for service-to-service and service-to-platform access. The platform issues short-lived tokens to the workload's own identity, so there is no connection string or API key sitting anywhere to be exposed. Where a managed identity is not possible, use a vault-held, rotated secret instead. Never use a static credential in config.
Least privilege is the other half. Each identity (human, service, or pipeline) should hold the narrowest role, on the narrowest scope, for the shortest time that lets it work. The Finperiti pattern of secrets in plain config is exactly what managed identity removes. And broad standing access is exactly what least privilege stops from becoming a disaster.
Authenticate without stored secrets
- DoUse managed identities for service-to-service and service-to-platform access (database, Key Vault, storage, messaging) so no credential is stored at all.
- DoGrant the managed identity direct, scoped access to the specific resources it needs (for example, this Key Vault, this database), not a broad role.
- DoWhere managed identity is not available, use a vault-held, automatically-rotated secret. Never use a static credential in config.
- ConsiderWorkload identity federation for pipelines and external workloads, so even CI/CD authenticates without long-lived secrets.
- NeverUse a stored connection string, account key, or API key where a managed identity would work, or commit such a credential to config or code.
Grant the least that works
- AlwaysAssign the narrowest built-in or custom role, on the narrowest scope (the resource, not the subscription), that the identity actually needs.
- DoSeparate identities by purpose and environment. Use distinct identities for distinct services and for dev, test, and prod, so the blast radius stays contained.
- DoMake privileged human access just-in-time and time-bound (PIM), not standing, and review role assignments regularly.
- ConsiderRegular access recertification and automated detection of unused or over-broad permissions, then trim them back.
- Do notReach for Owner, Contributor, or wildcard permissions because it is quicker than working out the specific role needed.
- NeverGrant standing, broad, or production admin access "to be efficient". Access is least-privilege, scoped, time-bound, and logged.
// connection string with an account key, in config
"Storage": "...;AccountKey=base64key=="
// identity granted: Contributor on the whole subscription
A long-lived key that can leak, plus a role that can change anything in the subscription. One exposure compromises everything, not just the one storage account.
// no secret anywhere; the app's managed identity authenticates
blobClient = new BlobServiceClient(uri, new DefaultAzureCredential());
// role assignment: 'Storage Blob Data Contributor' on THIS account only
Nothing to steal. Even if the workload is compromised, the identity can only touch the one storage account it was scoped to.
Self-review checklist
- AskCould this use a managed identity instead of a stored credential? If not, is the secret vault-held and rotated?
- AskIs the role the narrowest one that works, on the narrowest scope?
- AskIf this identity were compromised, how much could it reach, and is that the minimum?
- AskIs any access here standing and broad when it could be scoped and time-bound?