agentleFS
lukemurraynzlukemurraynz/hve-agent-skills/skills/identity-managed-identity/SKILL.md

identity-managed-identity

Skill2 starsChanged 3 months agoMITView on GitHub

Azure service-to-service (workload) identity: managed identity, user-assigned identity, Azure RBAC, passwordless Azure SDK connections, AKS workload identity, Azure DevOps Workload Identity Federation, GitHub Actions OIDC to Azure, and federated credential troubleshooting. Use when the user says "use managed identity", "passwordless Azure auth", "remove connection strings or keys", "federated credential", "workload identity federation", "GitHub Actions OIDC to Azure", "AKS workload identity", or "DefaultAzureCredential". Do NOT use for human sign-in, MFA, Conditional Access, or B2C / External ID consumer login ; use a human-identity (Entra) skill instead.

The file

Show its rules and text

We split this skill into the rules it gives an agent

28 rules. About 0 are common, 13 are distinctive, and 15 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈13

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 15

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Before writing any managed identity assignment, federated credential subject, Azure.Identity credential type, or workload identity service …

    line 97
  2. Very specific:

    Do not write federated credential subject from memory.

    line 107
  3. Distinctive:

    Do not assume the same federated credential works across GitHub branches.

    line 109
  4. Very specific:

    Do not write AKS workload identity without enabling the AKS feature (--enable-workload-identity --enable-oidc-issuer).

    line 110
  5. Very specific:

    Do not write client_id of a user-assigned MI from memory.

    line 111
  6. Very specific:

    If you cannot read AKS OIDC issuer URL, check Azure.Identity installed version, or run az role assignment create, do not produce …

    line 123
  7. Very specific:

    Do not produce speculative managed identity config under blocked verification.

    line 132
  8. Distinctive:

    Before producing code, role assignments, or remediation steps, determine and state:

    line 156
  9. Distinctive:

    If any item is unknown, make a safe assumption, label it, and continue with a reversible pattern.

    line 165
  10. Very specific:

    Use deterministic credentials in production.

    line 185
  11. Very specific:

    If AZURE_CLIENT_ID is set, treat the workload as intentionally bound to a user-assigned managed identity or federated workload identity.

    line 211
  12. Distinctive:

    If no user-assigned identity is configured, treat the workload as system-assigned.

    line 212
  13. Very specific:

    When infrastructure-as-code needs to grant the person or service principal running azd up (or terraform apply) access to a provisioned …

    line 322
  14. Distinctive:

    When this skill is used, produce outputs in this order:

    line 365
  15. Very specific:

    Never recommend Owner, Contributor, or management-plane roles for application data access.

    line 375
  16. Distinctive:

    Never assign data-plane roles at subscription scope for application workloads.

    line 376
  17. Very specific:

    Never grant User Access Administrator, Role Based Access Control Administrator, or role-assignment permissions to application identities …

    line 377
  18. Very specific:

    Never use listKeys, regenerateKey, connection-string outputs, SAS generation, or publish profiles in app paths for new projects.

    line 378
  19. Distinctive:

    Prefer separate identities per workload and environment.

    line 379
  20. Distinctive:

    Document every temporary secret exception with owner, named approver, expiry, compensating controls, a review cadence at expiry, and a …

    line 388
  21. Distinctive:

    Treat blast radius explicitly: a shared, or subscription/resource-group-scoped, data-plane identity means every workload using it is …

    line 389
  22. Distinctive:

    Use these scripts when reviewing repositories or generated IaC:

    line 395
  23. Distinctive:

    Do not mark this engagement complete until:

    line 431
  24. Distinctive:

    Use standards/checklist.md before considering the change complete.

    line 439
  25. Very specific:

    Verify Azure API versions before final IaC: az provider show --namespace <namespace> --query …

    line 482
  26. Very specific:

    Verify Azure.Identity package behaviour against the version used by the repo, especially when constraining DefaultAzureCredential.

    line 483
  27. Distinctive:

    Prefer Microsoft Learn, GitHub Docs, SDK docs, and provider schemas over blog posts.

    line 484
  28. Very specific:

    Create the service connection FIRST, read back authorization.parameters.workloadIdentityFederationIssuer / ...Subject, then create the …

    line 495

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Identity & Managed Identity Skill

Use When

ConditionDetail
Should triggerUser needs Azure service-to-service authentication with managed identity, workload identity federation, Azure RBAC, or passwordless Azure SDK access.
Should NOT triggerUser is designing human sign-in, MFA, Conditional Access, delegated Graph permissions, or app-layer authorization without an Azure workload identity problem.
Nearby skill collisionUse entra-id-cac, entra-external-id, or api-security-review when the main task is human identity, client auth, or API auth design rather than Azure workload identity.

Anti-Hallucination Rule (MANDATORY before writing managed identity or federated credential config)

Azure managed identity spans system-assigned vs user-assigned MI, AKS workload identity (federated credential with OIDC issuer), GitHub Actions OIDC, Azure DevOps Workload Identity Federation, Azure.Identity credential types per SDK language (.NET DefaultAzureCredential vs WorkloadIdentityCredential vs ManagedIdentityCredential; Python DefaultAzureCredential vs WorkloadIdentityCredential), and federated credential subject string formats (one format for GitHub Actions repo:org/repo:ref:refs/heads/main vs AKS system:serviceaccount:<ns>:<sa> vs Azure DevOps sc://<org>/<project>/<service-connection>). Wrong federated credential subject silently rejects tokens with confusing errors.

Common LLM hallucination traps (community-verified)

These are patterns that LLMs frequently get wrong when generating identity code.

LLM trap: Custom token caching

# WRONG - LLMs create manual token caching
import time
token_cache = {}
def get_token():
    if "token" in token_cache and token_cache["expires"] > time.time():
        return token_cache["token"]
    token = fetch_token_from_api()
    token_cache["token"] = token
    token_cache["expires"] = time.time() + 3600
    return token

# CORRECT - use DefaultAzureCredential (handles caching automatically)
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()
token = credential.get_token("https://management.azure.com/.default")

LLM trap: Connection string auth

# WRONG - using connection strings instead of managed identity
connection_string = "DefaultEndpointsProtocol=https;AccountName=..."

# CORRECT - use managed identity
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient

client = BlobServiceClient(
    account_url=f"https://{account_name}.blob.core.windows.net",
    credential=DefaultAzureCredential()
)

LLM trap: Custom credential chains

# WRONG - building custom auth chains
def get_credential():
    if os.getenv("AZURE_CLIENT_ID"):
        return ServicePrincipalCredential(...)
    elif os.getenv("MSI_ENDPOINT"):
        return ManagedIdentityCredential(...)
    else:
        return AzureCliCredential()

# CORRECT - use DefaultAzureCredential (handles all cases)
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()

LLM trap: Federated credential subject format

# WRONG - using wrong subject format for GitHub Actions
subject = "github-actions"  # Too vague

# CORRECT - use the exact subject format
subject = f"repo:{org}/{repo}:ref:refs/heads/{branch}"
# For AKS: subject = f"system:serviceaccount:{namespace}:{serviceAccount}"
# For Azure DevOps: subject = f"sc://{org}/{project}/{serviceConnection}"

Before writing any managed identity assignment, federated credential subject, Azure.Identity credential type, or workload identity service account annotation, ground each identifier using one of these methods:

  1. Federated credential subject format: GitHub Actions repo:<org>/<repo>:ref:refs/heads/<branch> or repo:<org>/<repo>:pull_request or repo:<org>/<repo>:environment:<env>. AKS workload identity: system:serviceaccount:<namespace>:<service-account-name>. Azure DevOps: sc://<org>/<project>/<service-connection-name>. Verify each format against the issuer's docs.
  2. OIDC issuer: GitHub https://token.actions.githubusercontent.com; Azure DevOps legacy issuer https://vstoken.dev.azure.com/<organization-id> (the path segment is the organization ID, not the tenant ID), newer service connections instead use the Entra issuer https://login.microsoftonline.com/<tenant-id>/v2.0 with subject <entra-prefix>/sc/<org-id>/<service-connection-id>; AKS cluster az aks show --query oidcIssuerProfile.issuerUrl. Issuer URL must match exactly. Read the actual value from the service connection / federated credential rather than assuming the shape.
  3. Azure.Identity credential type: DefaultAzureCredential is convenient but probes many sources; use specific credential types in production (WorkloadIdentityCredential, ManagedIdentityCredential with explicit clientId).
  4. RBAC role assignment: az role assignment create --assignee <principal-id> --role "<role-name>" --scope <resource-id> against the live target; verify role display name resolves to a definition.
  5. Propagation delay (two separate clocks): a newly created managed identity (its service principal becoming visible in Microsoft Entra) and a newly created role assignment becoming effective on the resource data plane are distinct delays. Role assignments are usually effective within ~5 minutes and can take up to ~30 minutes in the worst case. Do not run smoke tests immediately after deploy; gate first access behind bounded retry (see references/troubleshooting.md).

Forbidden shortcuts:

  • Do not write federated credential subject from memory; format is issuer-specific and exact-match.
  • Do not assume DefaultAzureCredential chain order or composition; the chain has expanded over time. The .NET chain now contains ten credentials including a Broker credential (the VS Code credential requires the Azure.Identity.Broker package) and AzureDeveloperCliCredential; Python azure-identity >= 1.14.0 no longer halts the chain when a developer credential fails to get a token. Pin Azure.Identity / azure-identity version before reasoning about chain order, and use WorkloadIdentityCredential explicitly in pod-identity scenarios.
  • Do not assume the same federated credential works across GitHub branches; subject must match exactly (or use environments / pull_request patterns deliberately).
  • Do not write AKS workload identity without enabling the AKS feature (--enable-workload-identity --enable-oidc-issuer). It is enabled at cluster creation, or in place on an existing cluster with az aks update --enable-oidc-issuer --enable-workload-identity - recreation is not required. Existing pods must be restarted to pick up the injected token after enablement.
  • Do not write client_id of a user-assigned MI from memory; resolve at deploy time.

Known asymmetry traps (illustrative, verify each):

  • Federated credential audience is api://AzureADTokenExchange (default), but some scenarios require a specific audience.
  • AKS workload identity requires service account annotation azure.workload.identity/client-id: <client-id> AND pod label azure.workload.identity/use: "true" - missing either silently falls back to AKS kubelet identity.
  • GitHub Actions subject for branch main is repo:org/repo:ref:refs/heads/main but for tag is repo:org/repo:ref:refs/tags/v1 - different ref types.
  • Azure.Identity DefaultAzureCredential in production may fall back to Azure CLI credential if managed identity probe fails, silently authenticating as the deployer.
  • User-assigned MI vs system-assigned MI: system-assigned dies with the resource; user-assigned outlives it. Cannot convert one to the other.

Safe degraded output when verification is blocked

If you cannot read AKS OIDC issuer URL, check Azure.Identity installed version, or run az role assignment create, do not produce production-shaped managed identity / federated credential config from memory. Federated credential subject format mismatch is the most common silent failure.

Instead, return:

  1. A labelled skeleton with [VERIFY] markers on federated credential subject formats, OIDC issuer URLs, Azure.Identity credential type, role display names, AKS workload identity annotations/labels.
  2. Verification commands: GitHub OIDC subject docs URL, az aks show --query oidcIssuerProfile.issuerUrl, Azure DevOps subject format docs URL, Azure.Identity installed package version.
  3. Identifier guess list grouped by failure mode (federated credential subject mismatch / wrong OIDC issuer / DefaultAzureCredential falls back to deployer identity / AKS workload identity not enabled / system vs user-assigned MI confusion).
  4. A design-level artifact offer: identity inventory (which workload needs which credential type), federated credential subject inventory per workflow/environment, role assignment matrix, OIDC issuer plan, propagation/test plan.

Do not produce speculative managed identity config under blocked verification. Subject-format mismatches and DefaultAzureCredential silent fallback to wrong identity are dominant pains.

Non-negotiable rule

For new Azure projects, use managed identity or workload identity federation for service-to-service authentication. Do not introduce application secrets, shared keys, SAS tokens, publish profiles, certificate passwords, or connection strings with embedded credentials unless the target service has no supported identity-based alternative and the exception is explicitly documented with an owner, expiry date, and migration path.

Use this skill when

  • Replacing secrets, storage keys, SAS tokens, connection strings, or service principal secrets with Azure managed identity or federated identity.
  • Configuring Azure compute to access Azure resources using ManagedIdentityCredential, WorkloadIdentityCredential, or a constrained credential chain.
  • Assigning Azure RBAC or service-native data-plane permissions for application identities.
  • Configuring AKS workload identity, Azure DevOps Workload Identity Federation, or GitHub Actions OIDC to Azure.
  • Troubleshooting identity, role assignment, token exchange, or federated credential failures.
  • Granting the deploying user or service principal access to provisioned resources (AKS cluster admin, PostgreSQL admin, Key Vault access policy) before those resources are needed.
  • Capturing the deploying identity in pre-provision hooks for use in Bicep/Terraform role assignments.

When NOT to Use

  • Designing human sign-in, Microsoft Entra External ID/B2C, MFA, Conditional Access, consent, delegated Graph permissions, or UI login flows. For human identity, use entra-id-cac or entra-external-id instead.
  • Designing business/application authorization models such as personas, entitlements, row-level security, or app roles, unless the implementation also requires Azure workload identity. For API authorization design, use api-security-review instead.
  • Solving non-Azure identity federation unless Azure is the relying party or target resource.

First response behaviour

Before producing code, role assignments, or remediation steps, determine and state:

  1. Runtime: App Service, Function App, Container Apps, VM, AKS, Azure DevOps, GitHub Actions, local dev, or other.
  2. Effective identity: system-assigned managed identity, user-assigned managed identity, workload identity, service connection identity, or app registration.
  3. Target resource and operation: for example, read secret, send message, receive event, read blob, write blob, connect to SQL, deploy infrastructure.
  4. Permission model: Azure RBAC, service-native RBAC, SQL contained database user, or a combination.
  5. Local auth posture: whether shared-key/SAS/local auth can be disabled at creation time.
  6. Verification plan: commands, tests, logs, and expected success/failure signals.

If any item is unknown, make a safe assumption, label it, and continue with a reversible pattern.

Default decisions for new projects

Decision areaDefault
Workload on one Azure resourceSystem-assigned managed identity
Multiple resources share the same access or blue/green slots need stable identityUser-assigned managed identity
AKS pod access to Azure resourcesMicrosoft Entra Workload ID with a user-assigned managed identity
Azure Bot Service for a Teams / M365 agent (incl. published Foundry agents)User-assigned managed identity (single-tenant) instead of an App Registration where supported - avoids creating an app registration when org policy blocks it
CI/CD to AzureWorkload Identity Federation/OIDC; no client secrets
Local developmentDeveloper tool credential chain only; never production secrets
Production Azure SDK credentialSpecific credential: ManagedIdentityCredential or WorkloadIdentityCredential
DefaultAzureCredential in productionOnly when intentionally constrained and documented
PermissionsNarrowest data-plane permission at the narrowest practical scope
Local authenticationDisabled at resource creation where supported
IaCBicep/Terraform first; CLI for verification or one-off remediation only

Credential selection

Use deterministic credentials in production. Unrestricted DefaultAzureCredential is acceptable for local development because it improves developer experience, but it can hide which credential is actually used in production and may fall through to unexpected credential sources.

EnvironmentPreferred credential
Local developmentChainedTokenCredential containing only approved developer credentials, or DefaultAzureCredential with excludes if needed
App Service, Functions, Container Apps, VM, VMSSManagedIdentityCredential
User-assigned managed identityManagedIdentityCredential(ManagedIdentityId.FromUserAssignedClientId(clientId)) or equivalent language option
AKS workload identityWorkloadIdentityCredential, or a constrained chain that only allows workload identity
Azure DevOps pipeline code using Azure SDKService connection + AzurePipelinesCredential or task-native Azure login, depending on SDK/task support
GitHub Actions to AzureGitHub OIDC + federated credential + azure/login; no AZURE_CLIENT_SECRET
Multi-language app implementationUse references/language-patterns.md for SDK-specific examples

Choosing between DefaultAzureCredential, ManagedIdentityCredential, and WorkloadIdentityCredential

The three differ by how the token is obtained, not just by environment. Pick by mechanism:

CredentialHow it gets a tokenUse whenDo not use when
ManagedIdentityCredentialCalls the Azure Instance Metadata Service (IMDS) token endpoint of the Azure-hosted computeWorkload runs on App Service, Functions, Container Apps, VM/VMSS, or other compute with a directly assigned system- or user-assigned managed identityThe token comes from a projected federated OIDC file (AKS), or the workload is not Azure-hosted compute
WorkloadIdentityCredentialExchanges a projected OIDC token (AZURE_FEDERATED_TOKEN_FILE) for a Microsoft Entra token via a federated credentialAKS pods with Microsoft Entra Workload ID, or any federated / projected-token scenarioPlain Azure-hosted compute with a directly assigned managed identity (use ManagedIdentityCredential instead)
DefaultAzureCredentialProbes an ordered chain of credentials until one returns a token (env, managed identity, workload identity, developer tools, …)Local development convenience, where the same code should authenticate via whatever the developer is signed in withProduction - it can silently fall through to the deployer's developer identity (see the Quality Gate). Use a specific credential, or a constrained, documented chain

Rule of thumb: in production, use the specific credential for the runtime (ManagedIdentityCredential for managed-identity compute, WorkloadIdentityCredential for federated/AKS). Reserve DefaultAzureCredential for local development or an intentionally narrowed, documented chain. For a self-selecting chain that works in both AKS and local dev without an environment check, see references/language-patterns.md.

Runtime binding rules

  • If AZURE_CLIENT_ID is set, treat the workload as intentionally bound to a user-assigned managed identity or federated workload identity.
  • If no user-assigned identity is configured, treat the workload as system-assigned.
  • If two or more user-assigned identities (or a user-assigned plus a system-assigned identity) are attached and AZURE_CLIENT_ID is not set, the identity is ambiguous - IMDS cannot disambiguate and may fail or return a token for the wrong identity. Treat this as a configuration error: bind explicitly with the client ID, do not assume it falls back to system-assigned.
  • Assign roles to the effective runtime principal, not to a similarly named app registration or another identity.
  • Reuse credential instances. Register one credential instance in dependency injection or as a long-lived singleton; do not instantiate credentials per request.
  • For direct token use outside Azure SDK clients, handle token lifetime and refresh. Prefer SDK clients that refresh tokens automatically.
using Azure.Core;
using Azure.Identity;
using Azure.Storage.Blobs;

// App Service / Container Apps / VM — system- or user-assigned managed identity.
TokenCredential credential = builder.Environment.IsDevelopment()
    ? new ChainedTokenCredential(
        new AzureDeveloperCliCredential(),  // azd auth login
        new VisualStudioCredential(),
        new AzureCliCredential(),
        new AzurePowerShellCredential())
    : new ManagedIdentityCredential();

builder.Services.AddSingleton(credential);
builder.Services.AddSingleton(_ => new BlobServiceClient(
    new Uri($"https://{storageAccountName}.blob.core.windows.net"),
    credential));

For AKS workload identity, use a self-selecting chain that does not require an environment check - see references/language-patterns.md for the full pattern.

Permission model selection

TargetPermission modelReference
Storage BlobAzure RBAC data-plane rolesstandards/rbac-patterns.md
Key VaultAzure RBAC permission model + data-plane rolesstandards/rbac-patterns.md
Service BusAzure RBAC data-plane roles + local auth disabledreferences/messaging.md
Event HubsAzure RBAC data-plane roles + local auth disabledreferences/messaging.md
Cosmos DB for NoSQLCosmos DB native data-plane RBAC; local auth disabledreferences/cosmos-db.md
Azure SQLMicrosoft Entra authentication + contained database user + database rolesreferences/azure-sql.md
AKS podsMicrosoft Entra Workload IDreferences/aks-workload-identity.md
Azure DevOps pipelinesAzure Resource Manager service connection with Workload Identity Federationreferences/azure-devops-wif.md
GitHub ActionsGitHub OIDC federated credential + azure/loginreferences/github-actions-oidc.md
Federated credential errorsIssuer, subject, audience, tenant, and identity checksreferences/troubleshooting.md
Terraform implementationIdentities, RBAC, and federated credentialsreferences/terraform-patterns.md
Landing-zone guardrailsAzure Policy and Resource Graph checksreferences/policy-guardrails.md

IaC-first patterns

System-assigned identity plus RBAC

param location string = resourceGroup().location
param app_name string
param key_vault_name string

var key_vault_secrets_user = '4633458b-17de-408a-b874-0445c86b69e6'

resource app 'Microsoft.Web/sites@2024-04-01' = {
  name: app_name
  location: location
  identity: {
    type: 'SystemAssigned'
  }
}

resource key_vault 'Microsoft.KeyVault/vaults@2026-02-01' existing = {
  name: key_vault_name
}

resource key_vault_role_assignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(key_vault.id, app.identity.principalId, key_vault_secrets_user)
  scope: key_vault
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', key_vault_secrets_user)
    principalId: app.identity.principalId
    principalType: 'ServicePrincipal'
  }
}

User-assigned identity plus RBAC

param location string = resourceGroup().location
param service_name string
param storage_account_name string

var storage_blob_data_contributor = 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'

resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2024-11-30' = {
  name: 'id-${service_name}'
  location: location
}

resource storage 'Microsoft.Storage/storageAccounts@2024-01-01' existing = {
  name: storage_account_name
}

resource blob_role_assignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(storage.id, identity.properties.principalId, storage_blob_data_contributor)
  scope: storage
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', storage_blob_data_contributor)
    principalId: identity.properties.principalId
    principalType: 'ServicePrincipal'
  }
}

Deploying identity pattern

When infrastructure-as-code needs to grant the person or service principal running azd up (or terraform apply) access to a provisioned resource, capture the deploying identity before infrastructure creates the resource.

Pre-provision hook (powershell)

$principalId = az ad signed-in-user show --query id --output tsv
$accountType = az account show --query user.type --output tsv
$principalType = if ($accountType -eq 'servicePrincipal') { 'ServicePrincipal' } else { 'User' }
azd env set DEPLOYING_PRINCIPAL_ID $principalId
azd env set DEPLOYING_PRINCIPAL_TYPE $principalType

Bicep consumption

The captured values flow through main.parameters.json using ${AZURE_DEPLOYING_PRINCIPAL_ID} and ${AZURE_DEPLOYING_PRINCIPAL_TYPE} environment-var substitution, then into a role assignment:

param deployingPrincipalId string
param deployingPrincipalType string

var aks_cluster_admin_role = 'b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b'

resource aks_admin_role_assignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(aksCluster.id, deployingPrincipalId, aks_cluster_admin_role)
  scope: aksCluster
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', aks_cluster_admin_role)
    principalId: deployingPrincipalId
    principalType: deployingPrincipalType
  }
}

Common resources that need this pattern

ResourceTypical roleNotes
AKS clusterAzure Kubernetes Service RBAC Cluster AdminRequired when disableLocalAccounts: true
PostgreSQL Flexible ServerAzure Database for PostgreSQL Flexible Server AdministratorUsed for Entra admin bootstrap
Key VaultKey Vault Secrets User + Key Vault Certificate UserFor initial secret/cert management

Output requirements

When this skill is used, produce outputs in this order:

  1. Decision summary: chosen identity type, credential, permission model, and scope.
  2. Implementation: Bicep/Terraform first, then app code, then CLI verification commands.
  3. Validation: how to prove the identity is used, role assignments exist, local auth is disabled, and secret paths fail.
  4. Rollback: safe rollback that does not reintroduce secrets unless approved as a temporary exception.
  5. Risks and assumptions: RBAC propagation delay, tenant restrictions, unsupported SDKs, or local-auth limitations.

Guardrails

  • Never recommend Owner, Contributor, or management-plane roles for application data access.
  • Never assign data-plane roles at subscription scope for application workloads.
  • Never grant User Access Administrator, Role Based Access Control Administrator, or role-assignment permissions to application identities unless that is the application’s explicit purpose and a security review exists.
  • Never use listKeys, regenerateKey, connection-string outputs, SAS generation, or publish profiles in app paths for new projects.
  • Prefer separate identities per workload and environment. Do not share one deployment identity across unrelated apps or tenants.
  • Pin federated credential subjects tightly to the expected Azure DevOps service connection, GitHub repository/environment/branch, or Kubernetes service account.
  • For GitHub Actions, use environments and environment protection rules for production deployments.
  • For Azure DevOps, do not grant service connections to all pipelines by default; authorize only the pipelines that need the connection.
  • Confirm before disabling local authentication on an existing resource: verify no active consumer still depends on the key/SAS path, because the change takes effect immediately.

Ownership, approval, and blast radius

  • Name an owner for every role assignment and scope. Granting roles is itself a privileged action (User Access Administrator / Role Based Access Control Administrator) and needs an approver, least privilege must not quietly become "whoever ran the pipeline".
  • Document every temporary secret exception with owner, named approver, expiry, compensating controls, a review cadence at expiry, and a migration issue. A "temporary" secret with no approver and no review becomes permanent.
  • Treat blast radius explicitly: a shared, or subscription/resource-group-scoped, data-plane identity means every workload using it is compromised together. Rollback must be able to revoke one workload without breaking others.
  • Revoking a role does not invalidate already-issued access tokens. Expect up to ~24 hours (or until the app restarts and re-authenticates) before access actually stops, plan incident response and rollback around that lag.
  • For greenfield platforms, add Azure Policy or equivalent guardrails so insecure local-auth defaults cannot be recreated silently.

Validation helpers

Use these scripts when reviewing repositories or generated IaC:

  • scripts/scan-secrets.sh - scans files for obvious Azure secret and connection string patterns.
  • scripts/validate-identity-config.sh - checks common Azure resources for local-auth and managed-identity posture.
  • scripts/list-identity-rbac.sh - lists Azure RBAC assignments for a principal.

Common failure diagnostics

SymptomFirst checks
403 Forbidden from target resourceCorrect principal, correct scope, correct data-plane role, RBAC propagation delay
Azure SQL Login failed for user '<token-identified principal>'Missing contained database user or database role
Cosmos DB Forbidden with Entra authMissing Cosmos native data-plane role assignment; Azure RBAC alone is insufficient for data access
Federated credential not foundIssuer, subject, audience, tenant, identity client ID, renamed repo/project/service connection
Wrong identity usedAZURE_CLIENT_ID, app settings, pod annotations, service connection, or credential chain fallback
Works locally but not in AzureDeveloper identity has permissions that workload identity lacks
Secret path still worksLocal auth/shared key not disabled or legacy secret still present

Resource Directories

Load these directories only when the selected workflow needs deeper examples, prompts, or reference material:

  • references/ - service- and platform-specific implementation patterns (SQL, Cosmos, messaging, AKS, GitHub Actions, Azure DevOps, Terraform, language SDKs, policy, troubleshooting).
  • standards/ - identity selection, RBAC patterns, and the review checklist.
  • actions/ - the step-by-step "configure identity" runbook.

Final Output Contract

Every engagement produces:

  • A clear identity decision summary covering runtime, identity type, credential choice, and permission model.
  • Concrete implementation guidance in the right order: IaC, app/runtime configuration, and verification commands.
  • A permission and scope plan showing which principal gets which access and why.
  • Validation, rollback, and risk notes that avoid reintroducing secrets as the default escape hatch.

Quality Gate

Do not mark this engagement complete until:

  • The chosen identity, target resource, and permission model are all explicit.
  • The guidance includes both implementation steps and verification steps.
  • Any issuer URLs, subject formats, role names, or SDK credential assumptions are verified or marked [VERIFY].
  • Production code uses a deterministic credential (ManagedIdentityCredential / WorkloadIdentityCredential), not an unconstrained DefaultAzureCredential. A startup check logs the resolved credential type and fails fast if it is not the expected managed identity (prevents silent fallback to the deployer's developer identity).

Review checklist

Use standards/checklist.md before considering the change complete.

References

  • references/azure-sql.md
  • references/cosmos-db.md
  • references/github-actions-oidc.md
  • references/azure-devops-wif.md
  • references/aks-workload-identity.md
  • references/messaging.md
  • standards/rbac-patterns.md
  • references/troubleshooting.md
  • references/language-patterns.md
  • references/terraform-patterns.md
  • references/policy-guardrails.md
  • actions/configure-identity.md

Hidden API Surface Properties

The Microsoft.ManagedIdentity/userAssignedIdentities resource schema exposes properties absent from overview docs:

ResourceSchema PropertyImpact
userAssignedIdentities/federatedIdentityCredentialsproperties.claimsMatchingExpressionFlexible federated credential with wildcard subject matching (languageVersion + value) — available from 2025-01-31-preview — alternatives to fixed subject
userAssignedIdentities/federatedIdentityCredentialsproperties.audiencesMust include api://AzureADTokenExchange — often forgotten
userAssignedIdentities/federatedIdentityCredentialsName constraint: 3-120 chars, ^[a-zA-Z0-9][a-zA-Z0-9-_]{2,119}$Naming rule for federated credential resources
userAssignedIdentitiesproperties.principalId (read-only)The AAD object ID — needed for RBAC role assignments referencing the identity
userAssignedIdentitiesproperties.clientId (read-only)The AAD application ID — needed for SDK ManagedIdentityCredential
userAssignedIdentitiesproperties.tenantId (read-only)The home tenant ID — important for cross-tenant scenarios
System-assigned identityidentity.type: 'SystemAssigned' | 'UserAssigned' | 'SystemAssigned,UserAssigned'The Bicep identity block shape for enabling system-assigned managed identity on Azure resources
Federated credential subject formatsubject: 'system:serviceaccount:<ns>:<sa>' (AKS) or repo:<owner>:<repo>:ref:refs/heads/<branch> (GitHub)Required subject format varies by issuer type

Flexible federated credentials (Preview) — when a fixed subject is too rigid (for example, trusting all branches of one repo), use a claimsMatchingExpression instead. Constraints (per Entra docs, checked 2026-08-25): Preview; supported only for federated credentials on app registrations (not managed identities); supported issuers are GitHub, GitLab, and Terraform Cloud; operators are matches (wildcards */?), eq, and; GitHub expressions must match sub and at least one immutable claim (repository_id / repository_owner_id). Azure CLI/PowerShell/Terraform do not yet support creating them — use Microsoft Graph via az rest:

az rest --method post \
  --url "https://graph.microsoft.com/beta/applications/<app-object-id>/federatedIdentityCredentials" \
  --body "{'name': 'fic-flexible', 'issuer': 'https://token.actions.githubusercontent.com', 'audiences': ['api://AzureADTokenExchange'], 'claimsMatchingExpression': {'value': \"claims['sub'] matches 'repo:contoso/contoso-repo:ref:refs/heads/*' and claims['repository_id'] eq '456789'\", 'languageVersion': 1}}"

Currency and verification

  • Date checked: 2026-08-25.
  • Verify Azure API versions before final IaC: az provider show --namespace <namespace> --query "resourceTypes[?resourceType=='<type>'].apiVersions" -o tsv.
  • Verify Azure.Identity package behaviour against the version used by the repo, especially when constraining DefaultAzureCredential.
  • Prefer Microsoft Learn, GitHub Docs, SDK docs, and provider schemas over blog posts.

Azure DevOps Workload Identity Federation: creation order changed (verified live 2026-08-25)

Since ADO sprint 253, newly created WorkloadIdentityFederation service connections default to the Microsoft Entra issuer (https://login.microsoftonline.com/{tenant}/v2.0 with subject /eid1/c/pub/t/{b64(tenant)}/a/{b64(appId)}/sc/{orgGuid}/{endpointGuid}), NOT the classic https://vstoken.dev.azure.com/{orgGuid} + sc://{org}/{project}/{connectionName} pair. The Entra-flavour subject embeds the server-assigned endpoint id, so it is uncomputable before creation.

  1. Create the service connection FIRST, read back authorization.parameters.workloadIdentityFederationIssuer / ...Subject, then create the federated credential from those exact values (docs: "automate-service-connections").
  2. A brand-new SC/environment is a protected resource: pipeline runs park at Checkpoint.Authorization until you PATCH {org}/{project}/_apis/pipelines/pipelinepermissions/endpoint/{id} and /environment/{id} (api-version 7.2-preview.1, method PATCH, body {"pipelines":[{"id":N,"authorized":true}]})
    • PUT returns 405.
  3. Symptom of flavour mismatch: pipeline az login --service-principal --federated-token ... fails AADSTS700211: No matching federated identity record found.
  4. The well-known Azure DevOps resource id 499b84ac-1321-427f-aa17-42cd2cad8a26 may not exist in every tenant; use the resource id your tenant actually registered (some CSP/CDX tenants expose a different GUID) - probe before hardcoding.
  5. Multi-tenant apps: the vstoken issuer is deprecated (retirement 2027) but multi-tenant app registrations are explicitly excluded; single-tenant/MI targets should migrate to Entra issuer.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.