Home

Published

- 7 min read

Using Managed Identities with AI Agents

img of Using Managed Identities with AI Agents

AI agents make credential mistakes more dangerous. A traditional web application usually follows predictable paths. An agent can plan, call tools, retry, summarize, transform data, and chain actions together. If that agent carries broad keys, every mistake has more room to become an incident.

That is why I strongly prefer managed identities for Azure based agents. Keys are static secrets. Managed identities are workload identities issued by Microsoft Entra ID, scoped by RBAC, logged by the platform, and removable without searching through code, prompts, containers, and notebooks.

The rule I use is simple: if an agent runs on Azure and calls Azure services, it should authenticate as an identity, not as a string.

Why API keys are a liability

API keys are easy to start with and painful to govern. They often end up in environment variables, local settings files, pipeline variables, notebooks, prompt examples, or temporary scripts. Once an agent framework matures, nobody is completely sure which path still uses which key.

For agents, the risk is higher because keys can leak through:

  • Tool error messages.
  • Debug logs.
  • Prompt traces.
  • Misconfigured observability exports.
  • Developer notebooks.
  • Container images.
  • Support bundles.
  • Agent memory stores.

Even when the key does not leak, it is usually too coarse. A storage account key is not a least privilege identity. It grants broad access to the account. A search admin key can read and write indexes. A shared model key does not tell me which workload performed a call.

Managed identities help because the platform issues tokens at runtime. There is no secret to rotate in the application. Access is granted through role assignments, and sign in activity can be correlated with the resource identity.

System assigned and user assigned identities

Azure gives me two common managed identity patterns.

System assigned identity is tied to one Azure resource. If I enable it on an App Service, Container App, Function App, or virtual machine, Azure creates an identity with the same lifecycle as that resource. When the resource is deleted, the identity is deleted.

I use system assigned identity when:

  • The agent runtime is a single deployed resource.
  • Permissions should disappear when the resource disappears.
  • The deployment model is simple.
  • I do not need the same identity across slots or environments.

User assigned identity is a standalone Azure resource that can be attached to one or more compute resources. It has its own lifecycle and stable principal ID.

I use user assigned identity when:

  • Blue green or canary deployments need the same permissions.
  • Multiple replicas or services share one workload identity by design.
  • Infrastructure teams manage identity separately from compute.
  • CI/CD needs to assign permissions before the compute resource exists.
  • I want stable audit records across redeployments.

For enterprise agents, user assigned identity is often the cleaner pattern because agents evolve. Tool hosts move, containers are replaced, and deployment slots change. Stable identity reduces operational noise.

Map tools to roles

An agent should not have one powerful identity for every action. I start by listing the tools the agent can call, then mapping each tool to the least privileged Azure role.

Common role mappings include:

  • Azure OpenAI calls: Cognitive Services OpenAI User on the Azure OpenAI account where applicable.
  • Azure AI Search queries: Search Index Data Reader on the target index or search service.
  • Azure AI Search ingestion: Search Index Data Contributor for ingestion identity only.
  • Blob reads: Storage Blob Data Reader on a specific container where possible.
  • Blob writes: Storage Blob Data Contributor for controlled write scenarios.
  • Key Vault secret reads: Key Vault Secrets User on the vault or narrower scope.
  • Service Bus send: Azure Service Bus Data Sender on a queue or topic.
  • Cosmos DB data access: Cosmos DB Built in Data Reader or a custom data plane role depending on the API.

The architecture decision is not just which role to assign. It is also which identity receives the role. Runtime, ingestion, administration, and CI/CD should usually be separate.

Assign roles with narrow scope

I avoid subscription wide role assignments for agents. They are convenient and almost always excessive. Resource group scope can be acceptable for a tightly bounded workload group, but service or child resource scope is better where supported.

This example assigns a user assigned identity read access to a search service and a storage container.

   az identity create \
  --name id-agent-prod \
  --resource-group rg-ai-prod \
  --location swedencentral

PRINCIPAL_ID=$(az identity show \
  --name id-agent-prod \
  --resource-group rg-ai-prod \
  --query principalId \
  --output tsv)

az role assignment create \
  --assignee $PRINCIPAL_ID \
  --role "Search Index Data Reader" \
  --scope $SEARCH_SERVICE_ID

az role assignment create \
  --assignee $PRINCIPAL_ID \
  --role "Storage Blob Data Reader" \
  --scope $CONTAINER_ID

I also document why each role exists. Six months later, that note is the difference between confident cleanup and fear based permission hoarding.

Authenticate in code

In most Azure SDKs, DefaultAzureCredential is the practical starting point. In local development, it can use the developer’s Azure CLI or Visual Studio Code sign in. In Azure, it can use the managed identity assigned to the host.

For Python based agent tools, the pattern is straightforward.

   from azure.identity import DefaultAzureCredential
from azure.search.documents import SearchClient

credential = DefaultAzureCredential()

search_client = SearchClient(
    endpoint="https://my-search.search.windows.net",
    index_name="enterprise-documents",
    credential=credential,
)

results = search_client.search(
    search_text="incident response policy",
    top=5,
)

For a user assigned managed identity, configure the client ID so the runtime selects the intended identity when multiple identities are attached.

   from azure.identity import ManagedIdentityCredential

credential = ManagedIdentityCredential(
    client_id="00000000-0000-0000-0000-000000000000"
)

I keep that client ID in configuration, not in the prompt. The agent instructions should say what the tool does, not how to authenticate with secrets.

Agent tool calls need authorization boundaries

Managed identity proves the workload identity. It does not automatically prove that every requested action is safe. The tool layer still needs authorization logic.

For example, an agent may have a tool that reads customer case files. The managed identity can read the storage container, but the tool must still check whether the human user is allowed to access that case. Otherwise the agent becomes a confused deputy: a user asks the agent for data they cannot access directly, and the agent fetches it with its own privileges.

I design tools with explicit inputs and policy checks:

  • Validate the user identity and tenant.
  • Validate the requested resource identifier.
  • Check user authorization before reading data.
  • Log the decision and correlation ID.
  • Return only the minimum data needed by the model.
  • Reject broad export requests by default.

The agent identity should be powerful enough to perform approved tool work, but the tool should enforce user specific access when the scenario requires it.

Keep secrets out of prompts and memory

Managed identities reduce secrets, but they do not eliminate all sensitive configuration. Some third party systems still require tokens. Some legacy APIs still require connection strings.

When secrets remain, I keep them in Key Vault and retrieve them inside the tool implementation. I do not place them in agent instructions, examples, memory, or retrieved documents. If a tool needs a secret, the agent calls the tool, and the tool uses its own credential flow.

This separation matters. Prompt content is part of the model interaction. Tool implementation is part of the trusted application boundary. Mixing the two is a common way to leak secrets during debugging or prompt injection.

Monitor identity usage

Managed identities give useful audit signals. I look for:

  • Unexpected services called by the agent identity.
  • Role assignments added outside the deployment pipeline.
  • Failed authorization spikes.
  • Token use from unexpected hosts.
  • Runtime identity performing ingestion or administration tasks.
  • Unused roles that should be removed.

This telemetry should feed the same operational process as other enterprise identities. Agents are workloads. They deserve workload identity governance, access reviews, and incident response playbooks.

Key takeaways

  • API keys are static secrets and are poorly suited for autonomous agent workloads.
  • Use system assigned identities for simple single resource agents and user assigned identities for stable enterprise workloads.
  • Map each agent tool to the least privileged Azure role at the narrowest practical scope.
  • Managed identity authenticates the workload, but tool code must still enforce user authorization.
  • Keep credentials out of prompts, memory, logs, and examples by moving authentication into the trusted tool layer.