-
Notifications
You must be signed in to change notification settings - Fork 490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature: add redis token refresh support #3238
Conversation
Signed-off-by: sadath-12 <[email protected]>
Signed-off-by: sadath-12 <[email protected]>
Signed-off-by: sadath-12 <[email protected]>
Please fix CI. ping @johnewart @ItalyPaleAle |
Signed-off-by: sadath-12 <[email protected]>
Sure, Thank you @daixiang0 |
Signed-off-by: sadath-12 <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments from me 🙂
Signed-off-by: sadath-12 <[email protected]>
Push the changes @JoshVanL . In order to make sure that background goroutine is terminated I have used |
loop must run every "a little bit less than 1hr" ? why and how ? please |
So in here the person from the Azure Redis Cache team explained that the service expects a new AUTH command, with a new token, sent every hour at most. If you run the loop every 1h exactly, you may be sending the updated command too late, maybe even by a few ms, so this would cause the session to expire. When there's something that must be renewed periodically, the common pattern is to do that a little bit before the deadline. In this case, if the deadline is 1h, maybe do it every 50m. This also leaves us some buffer, so if requesting the token fails, it can be retried 1m later, and we are still < 1h so the session is kept active. |
Signed-off-by: sadath-12 <[email protected]>
Thank you 😊👌 |
thank you @ItalyPaleAle , following that |
Signed-off-by: sadath-12 <[email protected]>
@sadath-12 you need to run your changed files through an autoformatter. |
Signed-off-by: sadath-12 <[email protected]>
I did following to verify this:
time="2024-01-29T12:50:50.191942482Z" level=fatal msg="Fatal error from runtime: process component statestore error: [INIT_COMPONENT_FAILURE]: initialization error occurred for statestore (state.redis/v1): [INIT_COMPONENT_FAILURE]: initialization error occurred for statestore (state.redis/v1): redis store: error connecting to redis at : dial tcp [::1]:6379: connect: connection refused" app_id=nodeapp instance=nodeapp-577cc79c45-4b7rs scope=dapr.runtime type=log ver=edge When I had tried to add principalId in user identity section of "azure redis", then it was not able to recognize that. Do we need to enable managed identity some other way to verify this? @shpathak-msft if you could please confirm here? |
This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
@DeepanshuA please use Azure Workload Identity instead. For this you first create a managed identity - user assigned or system assigned. Obviously you need to give the correct Redis permissions (role assignment) to this identity. Then you must follow these steps for your Dapr enabled deployment:
If the AKS cluster has workload identity enabled what will happen is that a special service account token gets mounted in each container of the annotated deployment and env vars are also injected. This allows the Azure Identity SDK to then make a request to authenticate has the managed identity. I suggest first making sure with another Azure Dapr component that you have workload identity working correctly if you run into issues. |
var v9logger = logger.NewLogger("dapr.components.redisv9") | ||
|
||
const ( | ||
tokenRefreshInterval = 50 * time.Minute |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently we do not have to do this every hour -- instead we should examine the most recent token expiration / duration, and then refresh the token say 10 minutes before it expires.
The token validity is variable and can be longer than one hour.
There should be a function you can use to examine the validity of the token.
@sadath-12 and @ItalyPaleAle apologies for the confusion in the other issue, adding some clarifications here. Redis server does not care what is the lifetime of the token - it can be 1 hour or 24 hours. The only expectation is that the redis server receives an auth command before the previous token expires. I would recommend not hard coding the "re-auth" loop to run every 50 minutes but it should run ~10 minutes before the token expiry. |
This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
This pull request has been automatically closed because it has not had activity in the last 37 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
@sadath-12 This PR is being tracked for v1.14, a few comments are outstanding - do you have the bandwidth to pick this up still? |
Signed-off-by: Bernd Verst <[email protected]>
ticker := time.NewTicker(tokenRefreshInterval) | ||
defer ticker.Stop() | ||
|
||
if !s.useAzureAD { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to see this exit condition instead be used in the v8client and v9client only.
if s.useAzureAd {
authenticateWithAzureRedis()
}
or something like that
@@ -252,3 +255,65 @@ type RedisError string | |||
func (e RedisError) Error() string { return string(e) } | |||
|
|||
func (RedisError) RedisError() {} | |||
|
|||
func (s *Settings) refreshTokenRoutineForRedis(ctx context.Context, redisClient RedisClient, version string, meta map[string]string, logger logger.Logger) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rename this to
func (s *Settings) refreshTokenRoutineForRedis(ctx context.Context, redisClient RedisClient, version string, meta map[string]string, logger logger.Logger) { | |
func (s *Settings) authenticateWithAzureRedis(ctx context.Context, redisClient RedisClient, version string, meta map[string]string, logger logger.Logger) { |
@@ -252,3 +255,65 @@ type RedisError string | |||
func (e RedisError) Error() string { return string(e) } | |||
|
|||
func (RedisError) RedisError() {} | |||
|
|||
func (s *Settings) refreshTokenRoutineForRedis(ctx context.Context, redisClient RedisClient, version string, meta map[string]string, logger logger.Logger) { | |||
ticker := time.NewTicker(tokenRefreshInterval) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ticker value must be reset every time you get a new token. The value must be token expiration time minus 10 minutes (so that we refresh 10 minutes before expiration).
|
||
// Authenticate with Redis using the refreshed token | ||
var authErr error | ||
if version == "v8" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this is bad.
Instead the Auth
method should be added to the interface in redis.go
, then an implementation should be added for the v8client.go
and v9client.go
That way you can then simply call client.Auth
without using the Pipeline client and without using version specific clients in this code. The version should not be required here.
References:
https://pkg.go.dev/github.com/go-redis/redis/v8#Conn.Auth
https://pkg.go.dev/github.com/go-redis/redis/v9#Conn.Auth
} | ||
at, err := tokenCred.GetToken(ctx, policy.TokenRequestOptions{ | ||
Scopes: []string{ | ||
env.Cloud.Services[azure.ServiceOSSRDBMS].Audience + "/.default", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ItalyPaleAle does this dapr.io/oss-rdbms
environment setting always exist? I don't think so?
This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
This pull request has been automatically closed because it has not had activity in the last 37 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
Description
Please explain the changes you've made
The changes proposed will support token refresh of redis using auth command every hour and maintains the connection without terminating as before
Issue reference
We strive to have all PR being opened based on an issue, where the problem or feature have been discussed prior to implementation.
Please reference the issue this PR will close: #3088
Checklist
Please make sure you've completed the relevant tasks for this PR, out of the following list: