If you are using the DefaultAzureCredential
class from the Azure Identity SDK while your user account is associated with multiple tenants, you may find yourself frequently running into API authentication errors (such as HTTP 401/Unauthorized). This post is for you!
These are your two options for successful authentication from a non-default tenant:
- Setup your environment precisely to force
DefaultAzureCredential
to use the desired tenant - Use a specific credential class and explicitly pass in the desired tenant ID
Option 1: Get DefaultAzureCredential working
The DefaultAzureCredential
class is a credential chain, which means that it tries a sequence of credential classes until it finds one that can authenticate successfully. The current sequence is:
EnvironmentCredential
WorkloadIdentityCredential
ManagedIdentityCredential
SharedTokenCacheCredential
AzureCliCredential
AzurePowerShellCredential
AzureDeveloperCliCredential
InteractiveBrowserCredential
For example, on my personal machine, only two of those credentials can retrieve tokens:
AzureCliCredential
: from logging in with Azure CLI (az login
)AzureDeveloperCliCredential
: from logging in with Azure Developer CLI (azd auth login
)
Many developers are logged in with those two credentials, so it's crucial to understand how this chained credential works. The AzureCliCredential
is earlier in the chain, so if you are logged in with that, you must have the desired tenant set as the "active tenant". According to Azure CLI documentation, there are two ways to set the active tenant:
az account set --subscription SUBSCRIPTION-ID
where the subscription is from the desired tenantaz login --tenant TENANT-ID
, with no subsequentaz login
commands after
Whatever option you choose, you can confirm that your desired tenant is currently the default by running az account show
and verifying the tenantId
in the account details shown.
If you are only logged in with the azd CLI and not the Azure CLI, you have a problem: the azd cli does not currently have a way to set the active tenant. If that credential is called with no additional information, azd assumes your home tenant, which may not be desired. The azd credential does check for a system variable called AZURE_TENANT_ID
, however, so you can try setting that in your environment before running code that uses DefaultAzureCredential
. That should work as long as the DefaultAzureCredential
code is truly running in the same environment where AZURE_TENANT_ID
has been set.
Option 2: Use specific credentials
Several credential types allow you to explicitly pass in a tenant ID, including both the AzureCliCredential
and AzureDeveloperCliCredential
. If you know that you’re always going to be logging in with a specific CLI, you can change your code to that credential:
For example, in the Python SDK:
azure_cred = AzureDeveloperCliCredential(
tenant_id=os.environ["AZURE_TENANT_ID"])
For more flexibility, you can use conditionals to only pass in a tenant ID if one is set in the environment:
if AZURE_TENANT_ID := os.environ("AZURE_TENANT_ID"):
azure_cred = AzureDeveloperCliCredential(tenant_id=AZURE_TENANT_ID)
else:
azure_cred = AzureDeveloperCliCredential()
As a best practice, I always like to log out exactly what credential I'm calling and whether I'm passing in a tenant ID, to help me spot any misconfiguration from my logs.
⚠️ Be careful when replacing DefaultAzureCredential
if your code will be deployed to a production host! That means you were previously relying on it using the ManagedIdentityCredential
in the chain, and that you now need to call that credential class specifically. You will also need to pass in the managed identity ID, if using user-assigned identity instead of system-assigned identity.
For example, using managed identity in the Python SDK with user-assigned identity:
azure_cred = ManagedIdentityCredential(
client_id=os.environ["AZURE_CLIENT_ID"])
Here’s a full credential setup for an app that works locally with azd and works in production with managed identity (either system or user-assigned):
if RUNNING_ON_AZURE:
if AZURE_CLIENT_ID := os.getenv("AZURE_CLIENT_ID"):
azure_cred = ManagedIdentityCredential(client_id=AZURE_CLIENT_ID)
else:
azure_cred = ManagedIdentityCredential()
elif AZURE_TENANT_ID := os.getenv("AZURE_TENANT_ID"):
azure_cred = AzureDeveloperCliCredential(tenant_id=AZURE_TENANT_ID)
else:
azure_cred = AzureDeveloperCliCredential()
For a full walkthrough of an end-to-end template that uses keyless auth in multiple languages, check out my colleague's tutorials on using keyless auth in AI apps.
No comments:
Post a Comment