Azure / Microsoft.Azure.StackExchangeRedis

Azure-specific wrapper for the StackExchange.Redis client library
MIT License
17 stars 14 forks source link

Unable to use MI authentication with extension functions #44

Closed laurenlindsey1 closed 6 months ago

laurenlindsey1 commented 9 months ago

Hello, I currently have my Azure Redis Cache set up in my C# repository using a reference to a secret, which contains the connection string. I am trying to instead, use a Managed Identity to authenticate to the Redis Cache. I am trying to follow the documentation to use the method ConfigureForAzureWithUserAssignedManagedIdentityAsync. The current code I have is the following:

var managedIdentityClientId = "client-id"; // removed for privacy
var managedIdentityPrincipalId = "principal-id"; // removed for privacy

var configurationOptions = ConfigurationOptions.Parse("WorkflowResourceProviderCacheTest.redis.cache.windows.net:6380");

configurationOptions.ConfigureForAzureWithUserAssignedManagedIdentityAsync(managedIdentityClientId, managedIdentityPrincipalId).ConfigureAwait(false).GetAwaiter();

services.AddStackExchangeRedisCache(options =>
{
    options.ConfigurationOptions = configurationOptions;
    options.InstanceName = "master";
});

Where the client id and the principal id are the values that show up in "Overview" for my Managed Identity resource. With regard to set up in the Azure portal, I have:

  1. Linked the User Assigned Managed Identity in the Identity -> User Assigned section of my Azure Cache for Redis resource.
  2. Added the User MSI into the (PREVIEW) Data Access Configuration section of my Azure Cache for Redis resource.
  3. Added the User Assigned Managed Identity as Redis Cache contributor in the Access control (IAM) -> Role Assignments section of my Azure Cache for Redis resource.

However, when I try to access data in the cache, using the following code (which works when I use the connection secret auth):

var data = await distributed cache.GetStringAsync(key, token);

I get an error stating that the cache has had a timeout error, due to unsuccessful authentication to check that the connection string password value is correct.

Please advise on if there is any step I am missing, and how I can make a change to get Managed Identity authentication working for my Redis Cache. Thank you!

philon-msft commented 9 months ago

Can you successfully run the sample app in this repo using your cache and creds? That should help narrow down the issue.

laurenlindsey1 commented 9 months ago

Hi @philon-msft, thanks for the quick reply! I am running the sample app with option 3: User Assigned Managed Identity, and getting an error:

Redis cache host name: WorkflowResourceProviderCacheTest.redis.cache.windows.net:6380
Managed identity Client ID or resource ID: <redacted>
Managed identity Principal (object) ID ('Username' from the 'Data Access Configuration' blade on the Azure Cache for Redis resource): <redacted>
Connecting with a user-assigned managed identity...
Failed to connect: MSAL.NetCore.4.57.0.0.MsalManagedIdentityException:
        ErrorCode: managed_identity_unreachable_network
Microsoft.Identity.Client.MsalManagedIdentityException: A socket operation was attempted to an unreachable network. (169.254.169.254:80)
 ---> System.Net.Sockets.SocketException (10051): A socket operation was attempted to an unreachable network.
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
   at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|277_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at Microsoft.Azure.StackExchangeRedis.AzureCacheOptionsProviderWithToken.AcquireTokenAsync(Boolean throwOnFailure) in C:\Users\llindsey\Desktop\redisTest\Microsoft.Azure.StackExchangeRedis\src\AzureCacheOptionsProviderWithToken.cs:line 216
   at StackExchange.Redis.AzureCacheForRedis.ConfigureForAzureAsync(ConfigurationOptions configurationOptions, AzureCacheOptions azureCacheOptions) in C:\Users\llindsey\Desktop\redisTest\Microsoft.Azure.StackExchangeRedis\src\AzureCacheForRedis.cs:line 117
   at StackExchange.Redis.AzureCacheForRedis.ConfigureForAzureWithUserAssignedManagedIdentityAsync(ConfigurationOptions configurationOptions, String clientId, String principalId) in C:\Users\llindsey\Desktop\redisTest\Microsoft.Azure.StackExchangeRedis\src\AzureCacheForRedis.cs:line 51
   at Program.<Main>$(String[] args) in C:\Users\llindsey\Desktop\redisTest\Microsoft.Azure.StackExchangeRedis\sample\Sample.cs:line 62
Inner Exception: System.Net.Sockets.SocketException (10051): A socket operation was attempted to an unreachable network.
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token)
   at System.Net.Sockets.Socket.<ConnectAsync>g__WaitForConnectWithCancellation|277_0(AwaitableSocketAsyncEventArgs saea, ValueTask connectTask, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.ConnectToTcpHostAsync(String host, Int32 port, HttpRequestMessage initialRequest, Boolean async, CancellationToken cancellationToken)
        StatusCode: 0
        ResponseBody:
        Headers:

Connection log from StackExchange.Redis:

Please advise if there is some additional set up required to allow the Managed Identity access to the Redis Cache.

philon-msft commented 9 months ago

That IP address 169.254.169.254 is for the Azure Instance Metadata Service (IMDS). Failure to connect to IMDS indicates that your app isn't running on an Azure VM (or other type of Azure resource). To use Managed Identity, the client code must be running in an Azure resource where it can access IMDS.

laurenlindsey1 commented 9 months ago

Thanks for the reply. I integrated the change to auth with user-assigned managed identity into my dev test environment, which runs in the same tenant where both the redis cache and the managed identity sit. I tested this code out and still got an error regarding authentication. It looks like as follows:

The message timed out in the backlog attempting to send because no connection became available (5000ms) - Last Connection 
Exception: AuthenticationFailure on <my-cache-name>.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: 2s ago, v: 2.7.4.20928, command=HMGET, timeout: 5000, inst: 12, qu: 0, qs: 0, aw: 
False, bw: CheckingForTimeout, last-in: 0, cur-in: 0, sync-ops: 0, async-ops: 2, serverEndpoint: 
<my-cache-name>.redis.cache.windows.net:6380, conn-sec: n/a, aoc: 0, mc: 1/1/0, mgr: 10 of 10 available, clientName: 
dw0sdwk00045D(SE.Redis-v2.7.4.20928), IOCP: (Busy=0,Free=1000,Min=1,Max=1000), WORKER: 
(Busy=3,Free=32764,Min=1,Max=32767), v: 2.7.4.20928 (Please take a look at this article for some common client-side issues that 
can cause timeouts: https://stackexchange.github.io/StackExchange.Redis/Timeouts)'.

Seems there is still an issue with authentication with user assigned managed identity. Are there some steps that need to be followed to ensure a managed identity is linked properly with permissions to the redis cache? Is there some documentation around that so that I can double check my set up?

Again, the redis cache works both locally and in my dev test environment with the connection string, but currently the user-assigned managed identity does not work in either.

philon-msft commented 6 months ago

To authenticate with a user-assigned managed identity, your code needs to be running in an Azure VM and the identity needs to be added to that VM. For more details see: https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview

I'll close this issue now to tidy up, but let me know if you're still seeing issues.