StackExchange / StackExchange.Redis

General purpose redis client
https://stackexchange.github.io/StackExchange.Redis/
Other
5.87k stars 1.51k forks source link

Not able to get identity auth to work #2519

Open dxynnez opened 1 year ago

dxynnez commented 1 year ago

I am trying out the new identity auth with a basic tier azure redis (v6.0 with AAD access auth enabled with minTLS 1.2). I tried using a client app to connect but am getting:

StackExchange.Redis.RedisConnectionException: It was not possible to connect to the redis server(s). There was an authentication failure; check that passwords (or client certificates) are configured correctly: (RedisServerException) NOAUTH Returned - connection has not yet authenticated

The client service principal had been granted the data contributor access policy to the cluster.

Am I missing anything here or is there any way I can further troubleshoot the issue?

Thanks so much!

NickCraver commented 1 year ago

How are you setting this up? Are you using https://github.com/Azure/Microsoft.Azure.StackExchangeRedis?

NickCraver commented 1 year ago

cc @philon-msft

philon-msft commented 1 year ago

I'd recommend double-checking that everything is configured per https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-azure-active-directory-for-authentication, and use the sample app in https://github.com/Azure/Microsoft.Azure.StackExchangeRedis to test connecting to Redis using your AAD identity from within an Azure VM. If it still doesn't work, you could contact Azure Support for assistance.

dxynnez commented 1 year ago

yes I have been following the guidance.

Using the sample app also doesn't work - I am getting:

Failed to connect: StackExchange.Redis.RedisConnectionException: It was not possible to connect to the redis server(s). Error connecting right now. To allow this multiplexer to continue retrying until it's able to connect, use abortConnect=false in your connection string or AbortOnConnectFail=false; in your code.

dxynnez commented 1 year ago

@philon-msft

Hey seems like it's working now. I guess there were just some delays for the settings to take effect..

One question, though -

Is there any way to get the identity auth to work using the user's visualstudio credential / ps credential? I was hoping to get this to work with the Azure.Identity.TokenCredential but I do notice this requires extra fields like principalId & tenantId... Still, any way I can roll my own implementation on top of TokenCredential to get this to work?

Also is there any sync version API for various ConfigureForAzureAsync calls? As the configure will most likely happen during startup, I want to avoid blocking on the async call to get the method to return...

philon-msft commented 1 year ago

No, Azure Cache for Redis only support Managed Identity or Service Principal for authentication, so an individual user's VS/PS creds won't work. For more discussion on TokenCredential support see https://github.com/Azure/Microsoft.Azure.StackExchangeRedis/issues/2.

Only async methods will be available because they rely on async communication with the identity service.

pinkfloydx33 commented 1 year ago

Only async methods will be available because they rely on async communication with the identity service.

Unless you're using minimal/top-level programs that makes it virtually impossible to use.

We call Connect on the muxer in Startup synchronously. I get that password/token retrieval is an async operation but does anyone have any ideas (short of total program conversion) to handle this? Best I can come up with is a custom factory-like service that can get creds and connects the muxer async and then caches the muxer for later use. But now it's a new abstraction and none of my existing code will just work.

We'd love to switch to managed identity for azure redis but this is a big hurdle blocking us and migrating the format of our apps is out of the question for now.

philon-msft commented 1 year ago

You should be able to use ConfigureForAzureAsync().GetAwaiter().GetResult() in a sync Startup method to force sync-over-async. This is a potentially dangerous anti-pattern, but should be reasonably safe in a Startup method that isn't a hot path

dxynnez commented 1 year ago

Only async methods will be available because they rely on async communication with the identity service.

Unless you're using minimal/top-level programs that makes it virtually impossible to use.

We call Connect on the muxer in Startup synchronously. I get that password/token retrieval is an async operation but does anyone have any ideas (short of total program conversion) to handle this? Best I can come up with is a custom factory-like service that can get creds and connects the muxer async and then caches the muxer for later use. But now it's a new abstraction and none of my existing code will just work.

We'd love to switch to managed identity for azure redis but this is a big hurdle blocking us and migrating the format of our apps is out of the question for now.

yeah, exactly... We don't want to do sync over async so instead I cache the mux in a Task - in constructor I fire the task to get the token & connect the mux & assign it to the task of the mux; all of my usage on the mux had to change to await on the mux task so that I don't have to block the async call (pretty much the same for the factory-like service which would return the mux in an async method)... weird but it works.

NickCraver commented 1 year ago

@dxynnez Ultimately that's a sync-over-async call somewhere if we did present it as sync, it's just a matter of who's pretending to be sync...so I agree with leaving this off and not having inherent/hidden sync-over-async in the libraries here.

dxynnez commented 1 year ago

@dxynnez Ultimately that's a sync-over-async call somewhere if we did present it as sync, it's just a matter of who's pretending to be sync...so I agree with leaving this off and not having inherent/hidden sync-over-async in the libraries here.

@NickCraver Or maybe the mux can internally cache the task of retrieving the key, and await the task whenever it needs the key? Then nobody would need to do sync-over-async. This is pretty much what we are doing right now, we cache the Task\<IConnectionMultiplexer> and await it whenever we need the mux.

NickCraver commented 1 year ago

@dxynnez It needs the key immediately, as we connect immediately, so that doesn't make much sense overall, the key needs to be ready to go when calling ConnectionMultiplexer.Connect(Async)() and that's the first call we get. Leaving it to the application owner to determine how their settings work and how it's best to wait for not at which stages for identity auth is the preferable path here. Anything beyond that is more restrictive and very possibly both incorrect and undesirable behavior.