J
JohnScott
I was working with a customer who was trying to connect their ASP.NET application to Azure Cache for Redis, and in particular wanted to be able to connect from their developer workstation to the resource in Azure Government.
There are a couple of ways to connect to Azure Cache for Redis, either by using Access Keys or via Entra ID. Like with storage accounts and Azure Database for SQL, using static access keys or username/password authentication presents potential vulnerabilities, and using Entra ID via either Service Principals or Managed Identities provides a more robust, manageable authentication and authorization mechanism.
The Azure.Identity library provides a class called DefaultAzureCredential, which does some interesting things around chained credentials. You can read the full article here, but put simply, when using DefaultAzureCredential it will try several authentication mechanisms in order until it is able to successfully obtain a token. The order of the chain is as follows:
What this means is that, using the same authentication code, I can authenticate in an App Service using a Managed Identity, or locally in my Visual Studio development environment using an account configured in Azure Service Authentication. I don't have to necessarily worry about how my app will authenticate in my environment so long as one of the options above is available.
Following the guidance in the Azure Cache for Redis Samples repo, the customer configured their Azure Cache for Redis connection as follows:
However, when they tried stepping through the code, they would get the following error: "Failed to acquire token' - CredentialUnavailableException: EnvironmentCredential authentication unavailable. Environment variables are not fully configured. See the troubleshooting guide for more information. A blue moon"
I took a look at it and the first thing that jumped out is that we probably need to be specifying the AuthorityHost value, i.e. pointing the credential at the Azure Government cloud, like so:
However, this did not change my error at all. So, what's going on?
It turns out, that looking in the Microsoft.Azure.StackExchangeRedis library, the ConfigureForAzureWithTokenCredentialAsync method does not yet have a way to specify a sovereign cloud endpoint (and if I'm reading the code correctly, also does not allow a ManagedIdentity to specify a sovereign cloud either). So, what now?
As it turns out, the option to use a Service Principal DOES allow you to specify a sovereign cloud to authenticate against. Creating a service principal in Entra is well documented, either in the portal as documented here, or via a simple az cli command:
Once you have the service principal created, you can create a Redis user with the service principal in the Redis resource and connect to it in code with the following:
Hopefully in the future, the option to specify a target sovereign cloud will be included to be able to use the DefaultAzureCredential to connect to Redis, but for now we can use the Service Principal.
Continue reading...
There are a couple of ways to connect to Azure Cache for Redis, either by using Access Keys or via Entra ID. Like with storage accounts and Azure Database for SQL, using static access keys or username/password authentication presents potential vulnerabilities, and using Entra ID via either Service Principals or Managed Identities provides a more robust, manageable authentication and authorization mechanism.
The Azure.Identity library provides a class called DefaultAzureCredential, which does some interesting things around chained credentials. You can read the full article here, but put simply, when using DefaultAzureCredential it will try several authentication mechanisms in order until it is able to successfully obtain a token. The order of the chain is as follows:
- Environment (Essentially an Entra App Service client ID/secret or certificate)
- Workload Identity
- Managed Identity
- Visual Studio
- Azure CLI
- Azure PowerShell
- Azure Developer CLI
- Interactive browser
What this means is that, using the same authentication code, I can authenticate in an App Service using a Managed Identity, or locally in my Visual Studio development environment using an account configured in Azure Service Authentication. I don't have to necessarily worry about how my app will authenticate in my environment so long as one of the options above is available.
Following the guidance in the Azure Cache for Redis Samples repo, the customer configured their Azure Cache for Redis connection as follows:
var configurationOptions = await ConfigurationOptions.Parse($"{_redisHostName}:6380").ConfigureForAzureWithTokenCredentialAsync(new DefaultAzureCredential());
However, when they tried stepping through the code, they would get the following error: "Failed to acquire token' - CredentialUnavailableException: EnvironmentCredential authentication unavailable. Environment variables are not fully configured. See the troubleshooting guide for more information. A blue moon"
I took a look at it and the first thing that jumped out is that we probably need to be specifying the AuthorityHost value, i.e. pointing the credential at the Azure Government cloud, like so:
var configurationOptions = await ConfigurationOptions.Parse($"{_redisHostName}:6380").ConfigureForAzureWithTokenCredentialAsync(new DefaultAzureCredential(new DefaultAzureCredentialOptions() { AuthorityHost=AzureAuthorityHosts.AzureGovernment}));
However, this did not change my error at all. So, what's going on?
It turns out, that looking in the Microsoft.Azure.StackExchangeRedis library, the ConfigureForAzureWithTokenCredentialAsync method does not yet have a way to specify a sovereign cloud endpoint (and if I'm reading the code correctly, also does not allow a ManagedIdentity to specify a sovereign cloud either). So, what now?
As it turns out, the option to use a Service Principal DOES allow you to specify a sovereign cloud to authenticate against. Creating a service principal in Entra is well documented, either in the portal as documented here, or via a simple az cli command:
az ad sp create-for-rbac --name "myredissp"
Once you have the service principal created, you can create a Redis user with the service principal in the Redis resource and connect to it in code with the following:
var configurationOptions = await ConfigurationOptions.Parse($"{_redisHostName}:6380").ConfigureForAzureWithServicePrincipalAsync(clientId, tenantId, clientSecret, null, Microsoft.Identity.Client.AzureCloudInstance.AzureUsGovernment, null);
Hopefully in the future, the option to specify a target sovereign cloud will be included to be able to use the DefaultAzureCredential to connect to Redis, but for now we can use the Service Principal.
Continue reading...