Azure Redis Cache with Entra ID Authentication

111 Views Asked by At

I am trying to add Azure Redis Cache to my .NET 8 api. I added the connectionString and added the code as:

services.AddStackExchangeRedisCache(
    options =>
    {
        options.Configuration = builder.Configuration.GetConnectionString("RedisCache");
        options.InstanceName = builder.Environment.EnvironmentName;
    })
.AddDistributedMemoryCache();

This is working when I added my password in the connectionString. But I do not want to do this, I want to use Entra ID authentication. So I have enabled the option, and also selected the web app (also in azure) which needs to use it. Access Policy as data owner. But when I leave out the password, I am getting an error:

StackExchange.Redis.RedisConnectionException: 'The message timed out in the backlog attempting to send because no connection became available (5000ms) - Last Connection Exception: AuthenticationFailure on tsg-pas-dev-redis.redis.cache.windows.net:6380/Interactive, Flushed/ComputeResult, last: ECHO, origin: SetResult, outstanding: 0, last-read: 0s ago, last-write: 0s ago, keep-alive: 60s, state: ConnectedEstablishing, mgr: 9 of 10 available, last-heartbeat: never, global: 0s ago, v: 2.6.122.38350, command=SET, timeout: 5000, inst: 12, qu: 1, qs: 0, aw: False, bw: SpinningDown, rs: ReadAsync, ws: Flushed, in: 0, last-in: 0, cur-in: 0, sync-ops: 1, async-ops: 1, serverEndpoint: tsg-pas-dev-redis.redis.cache.windows.net:6380, conn-sec: 0.23, aoc: 0, mc: 1/1/0, mgr: 10 of 10 available, clientName: DBSX1Y6-54977(SE.Redis-v2.6.122.38350), IOCP: (Busy=1,Free=999,Min=8,Max=1000), WORKER: (Busy=1,Free=32766,Min=8,Max=32767), POOL: (Threads=15,QueuedItems=0,CompletedItems=347,Timers=3), v: 2.6.122.38350 (Please take a look at this article for some common client-side issues that can cause timeouts: https://stackexchange.github.io/StackExchange.Redis/Timeouts)'

Exception: Error: NOAUTH Authentication required. Verify if the Redis password provided is correct. Attempted command: ECHO

Any clue what I am missing? I remember with one of the other services, I had to do something in the main, to fetch/initialize the token... but no clue if it is related or not.

-- EDIT: After the answer below I made a small change so I can still use IDistributedCache, because locally i can still use MemoryCache:

public static void AddDistributedCache(this IServiceCollection services, WebApplicationBuilder builder)
{
    if (builder.Configuration["UseMemoryCache"]?.Equals("yes", StringComparison.OrdinalIgnoreCase) ?? true)
    {
        services.AddDistributedMemoryCache();
    }
    else
    {
        services.AddStackExchangeRedisCache(options =>
        {
            options.InstanceName = builder.Environment.EnvironmentName;
            options.ConnectionMultiplexerFactory = () => ConnectionMultiplexerFactory(builder);
        })
        .AddDistributedMemoryCache();
    }
}

private static async Task<IConnectionMultiplexer> ConnectionMultiplexerFactory(WebApplicationBuilder builder)
{
    var configurationOptions = await ConfigurationOptions.Parse(builder.Configuration.GetConnectionString("RedisCache")!)
        .ConfigureForAzureWithTokenCredentialAsync("XXXX", new DefaultAzureCredential());

    var connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync(configurationOptions);

    return connectionMultiplexer;
}

The XXX needs to come from appsettings, allthough I do not understand yet why I need it. And not very handy when using multiple apps on the same redis ache instance yet I guess... But at least no passwords :) The good thing about this is that I can easily switch and also do not have to worry about multiplexer getDatabase etc...

1

There are 1 best solutions below

2
Gaurav Mantri On BEST ANSWER

Based on the documentation available here, in order to use Entra ID authentication, you would need to use Microsoft.Azure.StackExchangeRedis Nuget package.

Code sample for the same is available here: https://github.com/Azure/Microsoft.Azure.StackExchangeRedis/tree/main/sample.

From this link, sample code to use DefaultAzureCredential:

Write("Redis cache host name: ");
cacheHostName = ReadLine()?.Trim();
Write("'Username' from the 'Data Access Configuration' blade on the Azure Cache for Redis resource): ");
var username = ReadLine()?.Trim();

Write("Connecting using TokenCredential...");
configurationOptions = await ConfigurationOptions.Parse($"{cacheHostName}:6380").ConfigureForAzureWithTokenCredentialAsync(username!, new DefaultAzureCredential());
configurationOptions.AbortOnConnectFail = true; // Fail fast for the purposes of this sample. In production code, this should remain false to retry connections on startup
LogTokenEvents(configurationOptions);

connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync(configurationOptions, connectionLog);