Security and access
Export PDFThe first question any security reviewer asks is “who can call this, and how?”. Foundry answers it with Microsoft Entra ID identities and role-based access control instead of shared secrets. This lesson explains authentication and authorization from first principles, maps every built-in Foundry role to a real job, shows keyless code for laptops and production, and covers keys, Key Vault, and private networking.
Authentication vs authorization
Proving who you are. In Foundry this is either an Entra ID token (recommended) or an API key.
Deciding what an authenticated identity may do. In Azure this is RBAC: a role (a set of permissions) assigned to an identity at a scope (subscription, resource group, resource, or project).
The control plane manages resources (create a project, change a deployment). The data plane uses them (call a model, create an agent, upload a file). Azure roles grant these separately, which is why an Owner of a resource may still be unable to call a model.
Why keyless (Entra ID) beats API keys
| API key | Entra ID token | |
|---|---|---|
| What it is | A long-lived shared secret | A short-lived token (about an hour) issued to a specific identity |
| Scope | Full access to the whole resource and every project | Only what that identity's roles allow |
| If leaked | Works for anyone until manually rotated | Expires quickly; can be revoked centrally |
| Audit | Logs show “a key” | Logs show which user or app did what |
| Agent Service and many features | Not supported | Required |
Many organisations disable key auth entirely (disableLocalAuth: true) through Azure Policy. Write your code for Entra ID from day one and you never have to migrate.
DefaultAzureCredential: one line, every environment
A class in azure-identity that tries a chain of credential sources in order — environment variables, workload identity, managed identity, Visual Studio Code, Azure CLI, Azure PowerShell, Azure Developer CLI, and others — and uses the first that works. The same code authenticates as you on a laptop and as the app's managed identity in production.
This example calls your Azure resources, so it needs a deployed project and a signed-in identity. Output will differ on every run.
import os
from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential
# on your laptop this uses `az login`; in Azure it uses the managed identity
credential = DefaultAzureCredential()
project = AIProjectClient(
endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
credential=credential,
)
for deployment in project.deployments.list():
print(deployment.name, "→", deployment.model_name)
If the token request succeeds but the call returns 401 or 403, authentication worked and authorization failed: your identity lacks a role. If you see CredentialUnavailableError, no credential source in the chain was available — run az login.
DefaultAzureCredential is convenient but probes many sources, which adds startup latency and can pick an unexpected identity. In production, many teams use ManagedIdentityCredential directly, or set AZURE_TOKEN_CREDENTIALS=prod to restrict the chain to production sources.
The built-in Foundry roles
Foundry has its own roles designed for least privilege. They were renamed in 2026 — the old names (Azure AI User, Azure AI Project Manager, and so on) still appear in places, but the role IDs and permissions are unchanged.
| Role (old name) | Can do | Give it to |
|---|---|---|
| Foundry Agent Consumer | Only interact with published agent endpoints | Apps or users that just chat with an agent |
| Foundry User (Azure AI User) | Read projects; build agents, call models, upload data (data actions) | Developers, and your project's managed identity |
| Foundry Project Manager (Azure AI Project Manager) | Everything Foundry User can, plus manage projects, publish agents, and assign Foundry User to others | Team leads |
| Foundry Account Owner (Azure AI Account Owner) | Create resources and projects, manage deployments, assign limited roles — but no data actions | Platform or IT admins |
| Foundry Owner (Azure AI Owner) | Full control plane and data plane access | Small teams where one person does everything |
Two traps to avoid:
- Owner and Contributor do not include data actions. A subscription Owner can create a project but get
403when calling a model until they also have Foundry User. - “Azure AI Developer” is not for Foundry projects. Despite the name, it is scoped to Azure Machine Learning workspaces and hubs.
Other roles you will meet: Cognitive Services OpenAI User (call the account-level OpenAI endpoint directly), Cognitive Services User (Speech, Vision, Language), Cognitive Services Usages Reader (view quota), and Search Index Data Reader (let an agent read an Azure AI Search index).
# give yourself data-plane access to the Foundry resource
ME=$(az ad signed-in-user show --query id -o tsv)
SCOPE=$(az cognitiveservices account show -n $RES -g $RG --query id -o tsv)
az role assignment create \
--assignee-object-id $ME \
--assignee-principal-type User \
--role "Foundry User" \
--scope $SCOPE
# If your tenant still shows the old name, use --role "Azure AI User".
# Role assignments can take a few minutes to take effect.
Managed identities
An Entra ID identity that Azure creates and manages for a resource (an App Service, Container App, Function, VM, or the Foundry resource and project themselves). Code running on that resource can get tokens without any secret. System-assigned identities live and die with the resource; user-assigned identities are standalone and can be shared.
Managed identities show up in two directions:
- Your app → Foundry. Your web app's managed identity gets Foundry User (or Foundry Agent Consumer) on the Foundry resource. The app calls Foundry with
DefaultAzureCredential, no keys in config. - Foundry → other resources. The project's managed identity needs roles on resources the agent uses: Search Index Data Reader on Azure AI Search, Storage Blob Data Reader on storage, and so on.
your Container App ──(managed identity: Foundry User)──► Foundry project
│
(project managed identity: Search Index Data Reader)
▼
Azure AI Search index
If you must use keys
Some quick experiments and a few tools still need a key. If you use one:
- Never commit it. Load it from an environment variable or, better, Azure Key Vault.
- Rotate regularly. Each resource has two keys so you can rotate one while the other stays live.
- Remember a key grants access to the whole resource, not one project.
# read a secret from Key Vault using your Entra identity — no secret in code
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
vault = SecretClient("https://kv-support-prod.vault.azure.net", DefaultAzureCredential())
partner_api_key = vault.get_secret("partner-api-key").value
Named, stored references from a Foundry resource or project to another service (Azure AI Search, Storage, Bing, an MCP server, an OpenAPI endpoint). A connection holds the target URL and either uses Entra ID or stores the credential securely, so agents and code reference the connection by name instead of handling secrets.
Network security
| Control | What it does | When to use it |
|---|---|---|
| Public network access: enabled | Endpoint reachable from the internet (still requires auth) | Learning and many internal tools |
| IP firewall rules | Allow only listed IP ranges | Simple restriction to office or CI IPs |
| Private endpoint | Gives the resource a private IP inside your virtual network; disable public access | Regulated workloads; most enterprise production |
| Agent network isolation (bring your own VNet) | Runs agent tool traffic inside your network | When agents must reach private data sources |
| Customer-managed keys | Encrypt data at rest with your own Key Vault key | Compliance requirements |
Private networking changes DNS: <res>.services.ai.azure.com must resolve to the private IP from inside your network. Most “it works on my laptop but not in the VNet” issues are DNS configuration on private DNS zones.
- Assign yourself Foundry User on your resource and run the
deployments.list()example. - Remove the role, wait a few minutes, run again, and read the
403error message. - Add it back. You have now debugged the most common Foundry error.
- Authentication proves identity; authorization (RBAC) decides permissions at a scope.
- Prefer Entra ID tokens over API keys; many features and many organisations require it.
DefaultAzureCredentialusesaz loginlocally and managed identity in Azure, with the same code.- Foundry User is the developer role; Owner and Contributor do not grant data-plane access.
- Give apps managed identities, and give the project's identity roles on the resources its agents use.
- Use Key Vault for any unavoidable secrets, and private endpoints for regulated production.