From 5c657ffe486106045361f61f62fb8dea72dbb911 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Thu, 22 May 2025 09:11:42 +0100 Subject: [PATCH 1/6] DOC-4990 started Go AMR page --- content/develop/clients/go/amr.md | 215 ++++++++++++++++++++++++ content/develop/clients/go/connect.md | 2 +- content/develop/clients/go/produsage.md | 2 +- content/develop/clients/go/queryjson.md | 2 +- content/develop/clients/go/transpipe.md | 2 +- content/develop/clients/go/vecsearch.md | 2 +- 6 files changed, 220 insertions(+), 5 deletions(-) create mode 100644 content/develop/clients/go/amr.md diff --git a/content/develop/clients/go/amr.md b/content/develop/clients/go/amr.md new file mode 100644 index 0000000000..03e1284dff --- /dev/null +++ b/content/develop/clients/go/amr.md @@ -0,0 +1,215 @@ +--- +categories: +- docs +- develop +- stack +- oss +- rs +- rc +- oss +- kubernetes +- clients +description: Learn how to authenticate to an Azure Managed Redis (AMR) database +linkTitle: Connect to AMR +title: Connect to Azure Managed Redis +weight: 15 +--- + +The [`go-redis-entraid`](https://github.com/redis/go-redis-entraid) package +lets you authenticate your app to +[Azure Managed Redis (AMR)](https://azure.microsoft.com/en-us/products/managed-redis) +using [Microsoft Entra ID](https://learn.microsoft.com/en-us/entra/identity/). +You can authenticate using a system-assigned or user-assigned +[managed identity](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) +or a [service principal](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals), +letting `go-redis-entraid` fetch and renew the authentication tokens for you automatically. + +## Install + +From a Go module folder, install `go-redis-entraid` with the +following command: + +```bash +go get github.com/redis-developer/go-redis-entraid +``` + +## Create a `StreamingCredentialsProvider` instance + +The `StreamingCredentialsProvider` interface defines methods +to provide credentials for authentication. Use an object that +implements this interface to obtain the authentication credentials you +need when you connect to Redis. See the sections below to learn how +to create the `StreamingCredentialsProvider` instances for AMR +using the factory functions that `go-redis-entraid` provides. + + +### `CredentialProvider` for a service principal + +Use the `create_from_service_principal()` factory function to create a +`CredentialProvider` that authenticates to AMR using a +service principal (see the +[Microsoft documentation](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals) to learn more about service principals). + +You will need the following details of your service principal to make the connection: + +- Client ID +- Client secret +- Tenant ID + +The example below shows how to import the required modules and call +`create_from_service_principal()`: + +```python +from redis import Redis +from redis_entraid.cred_provider import * + +credential_provider = create_from_service_principal( + , + , + +) +``` + +### `StreamingCredentialsProvider` for a managed identity + +Use the `NewManagedIdentityCredentialsProvider()` function to create a +`StreamingCredentialsProvider` that authenticates to AMR using a +managed identity (see the +[Microsoft documentation](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) to learn more about managed identities). + +The example below shows how to import the required modules and call +`NewManagedIdentityCredentialsProvider()`. +Pass `identity.SystemAssignedIdentity` or `identity.UserAssignedIdentity` +as the `ManagedIdentityType` parameter. + +```go +import ( + "github.com/redis-developer/go-redis-entraid/entraid" + "github.com/redis-developer/go-redis-entraid/identity" + ... +) + . + . +provider, err := entraid.NewManagedIdentityCredentialsProvider( + entraid.ManagedIdentityCredentialsProviderOptions{ + CredentialsProviderOptions: entraid.CredentialsProviderOptions{ + ClientID: "", + }, + ManagedIdentityType: identity.UserAssignedIdentity, + UserAssignedClientID: "", + }, +) +``` + +### Custom configuration + +The examples above use a default configuration but you can also provide a custom +configuration using the `TokenManagerOptions` field of `CredentialsProviderOptions`: + +```go +options := entraid.CredentialsProviderOptions{ + ClientID: os.Getenv("AZURE_CLIENT_ID"), + TokenManagerOptions: manager.TokenManagerOptions{ + ExpirationRefreshRatio: 0.7, + LowerRefreshBounds: 10000, + RetryOptions: manager.RetryOptions{ + MaxAttempts: 3, + InitialDelay: 1000 * time.Millisecond, + MaxDelay: 30000 * time.Millisecond, + BackoffMultiplier: 2.0, + IsRetryable: func(err error) bool { + return strings.Contains(err.Error(), "network error") || + strings.Contains(err.Error(), "timeout") + }, + }, + }, +} +``` + +These options are explained below: + +- `ExpirationRefreshRatio`: A `float` value representing the fraction + of a token's lifetime that should elapse before attempting to + refresh it. For example, a value of 0.75 means that you want to + refresh the token after 75% of its lifetime has passed. +- `LowerRefreshBounds`: The minimum amount of the token's lifetime + (in milliseconds) remaining before attempting to refresh, regardless + of the `expirationRefreshRatio` value. Set this to zero if you want + the refresh time to depend only on `expirationRefreshRatio`. +- `RetryOptions`: This object specifies how to retry a token request + after failure. The available options are: + - `MaxAttempts`: The maximum number of times to retry a token request + The default value is 3. + - `InitialDelay`: The initial delay between retries in milliseconds. This + will be modified during successive attempts by the `BackoffMultiplier` + value (see below). The default is 1000ms. + - `BackoffMultiplier`: The factor by which the `InitialDelay` is multiplied + between attempts, following an + [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) + strategy. The default multiplier is 2.0. + - `IsRetryable`: A function that receives an `error` parameter and returns + a boolean `true` result if an attempt that failed with that error is + retryable and `false` otherwise. Use this to implement your own custom + logic to decide which errors should be retried. + + +## Connect + +When you have created your `StreamingCredentialsProvider` instance, you are ready to +connect to AMR. +The example below shows how to pass the instance as a parameter to the standard +`NewClient()` connection method. It also illustrates how to use +[`os.Getenv()`](https://pkg.go.dev/os#Getenv) to get the connection details +from environment variables rather than include their values in the code. + +```go +package main + +import ( + "context" + "fmt" + "log" + "os" + "strings" + + "github.com/redis-developer/go-redis-entraid/entraid" + "github.com/redis/go-redis/v9" +) + +func main() { + // Get required environment variables + clientID := os.Getenv("AZURE_CLIENT_ID") + redisEndpoint := os.Getenv("REDIS_ENDPOINT") + if clientID == "" || redisEndpoint == "" { + log.Fatal( + "AZURE_CLIENT_ID and REDIS_ENDPOINT env variables are required" + ) + } + + // Create credentials provider + provider, err := entraid.NewManagedIdentityCredentialsProvider( + entraid.ManagedIdentityCredentialsProviderOptions{ + CredentialsProviderOptions: entraid.CredentialsProviderOptions{ + ClientID: clientID, + }, + } + ) + if err != nil { + log.Fatalf("Failed to create credentials provider: %v", err) + } + + // Create Redis client + client := redis.NewClient(&redis.Options{ + Addr: redisEndpoint, + StreamingCredentialsProvider: provider, + }) + defer client.Close() + + // Test connection + ctx := context.Background() + if err := client.Ping(ctx).Err(); err != nil { + log.Fatalf("Failed to connect to Redis: %v", err) + } + log.Println("Connected to Redis!") +} +``` diff --git a/content/develop/clients/go/connect.md b/content/develop/clients/go/connect.md index b75881e833..a6e1f115e3 100644 --- a/content/develop/clients/go/connect.md +++ b/content/develop/clients/go/connect.md @@ -12,7 +12,7 @@ categories: description: Connect your Go application to a Redis database linkTitle: Connect title: Connect to the server -weight: 1 +weight: 10 --- ## Basic connection diff --git a/content/develop/clients/go/produsage.md b/content/develop/clients/go/produsage.md index 52fa4833ec..166f898470 100644 --- a/content/develop/clients/go/produsage.md +++ b/content/develop/clients/go/produsage.md @@ -12,7 +12,7 @@ categories: description: Get your `go-redis` app ready for production linkTitle: Production usage title: Production usage -weight: 6 +weight: 60 --- This guide offers recommendations to get the best reliability and diff --git a/content/develop/clients/go/queryjson.md b/content/develop/clients/go/queryjson.md index f4c25bcce4..922aba3200 100644 --- a/content/develop/clients/go/queryjson.md +++ b/content/develop/clients/go/queryjson.md @@ -12,7 +12,7 @@ categories: description: Learn how to use the Redis query engine with JSON and hash documents. linkTitle: Index and query documents title: Index and query documents -weight: 2 +weight: 20 --- This example shows how to create a diff --git a/content/develop/clients/go/transpipe.md b/content/develop/clients/go/transpipe.md index 436b05809e..f22e401501 100644 --- a/content/develop/clients/go/transpipe.md +++ b/content/develop/clients/go/transpipe.md @@ -12,7 +12,7 @@ categories: description: Learn how to use Redis pipelines and transactions linkTitle: Pipelines/transactions title: Pipelines and transactions -weight: 4 +weight: 40 --- Redis lets you send a sequence of commands to the server together in a batch. diff --git a/content/develop/clients/go/vecsearch.md b/content/develop/clients/go/vecsearch.md index 47a26501aa..0dc6dfc25f 100644 --- a/content/develop/clients/go/vecsearch.md +++ b/content/develop/clients/go/vecsearch.md @@ -12,7 +12,7 @@ categories: description: Learn how to index and query vector embeddings with Redis linkTitle: Index and query vectors title: Index and query vectors -weight: 3 +weight: 30 --- [Redis Query Engine]({{< relref "/develop/interact/search-and-query" >}}) From ea330344d8439c3fc957c23e07e948a30d465e03 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Thu, 22 May 2025 11:41:47 +0100 Subject: [PATCH 2/6] DOC-4990 rounded out Go AMR page --- content/develop/clients/go/amr.md | 56 ++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/content/develop/clients/go/amr.md b/content/develop/clients/go/amr.md index 03e1284dff..cdd3a87ec5 100644 --- a/content/develop/clients/go/amr.md +++ b/content/develop/clients/go/amr.md @@ -26,6 +26,9 @@ letting `go-redis-entraid` fetch and renew the authentication tokens for you aut ## Install +Install [`go-redis`]({{< relref "/develop/clients/go" >}}) if you +have not already done so. + From a Go module folder, install `go-redis-entraid` with the following command: @@ -43,10 +46,10 @@ to create the `StreamingCredentialsProvider` instances for AMR using the factory functions that `go-redis-entraid` provides. -### `CredentialProvider` for a service principal +### `StreamingCredentialsProvider` for a service principal -Use the `create_from_service_principal()` factory function to create a -`CredentialProvider` that authenticates to AMR using a +Use the `NewConfidentialCredentialsProvider()` factory function to create a +`StreamingCredentialsProvider` that authenticates to AMR using a service principal (see the [Microsoft documentation](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals) to learn more about service principals). @@ -56,17 +59,41 @@ You will need the following details of your service principal to make the connec - Client secret - Tenant ID -The example below shows how to import the required modules and call -`create_from_service_principal()`: +Use an `AuthorityConfiguration` instance to pass the tenant ID. +This type has the following fields: -```python -from redis import Redis -from redis_entraid.cred_provider import * +- `AuthorityType`: This should have one of the values + - `identity.AuthorityTypeDefault` ("default") + - `identity.AuthorityTypeMultiTenant` ("multi-tenant") + - `identity.AuthorityTypeCustom` ("custom") +- `TenantID`: Pass your tenant ID string here, or use "common" for + a multi-tentant application. +- `Authority`: Custom authority URL. This is only required if you + specified `AuthorityTypeCustom` in the `AuthorityType` field. + +The example below shows how to import the required modules and call +`NewConfidentialCredentialsProvider()`: -credential_provider = create_from_service_principal( - , - , - +```go +import ( + "github.com/redis-developer/go-redis-entraid/entraid" + "github.com/redis-developer/go-redis-entraid/identity" + ... +) + . + . +provider, err := entraid.NewConfidentialCredentialsProvider( + entraid.ConfidentialIdentityProviderOptions{ + CredentialsProviderOptions: entraid.CredentialsProviderOptions{ + ClientID: "", + }, + CredentialsType: identity.ClientSecretCredentialType, + ClientSecret: "", + Authority: identity.AuthorityConfiguration{ + AuthorityType: identity.AuthorityTypeDefault, + TenantID: "", + }, + } ) ``` @@ -213,3 +240,8 @@ func main() { log.Println("Connected to Redis!") } ``` + +## More information + +See the [`go-redis-entraid`](https://github.com/redis/go-redis-entraid) +GitHub repository for full source code and more examples and details. From 69e9b7c51eb3a3badfd5effae7f81e46347a5766 Mon Sep 17 00:00:00 2001 From: andy-stark-redis <164213578+andy-stark-redis@users.noreply.github.com> Date: Fri, 30 May 2025 09:58:20 +0100 Subject: [PATCH 3/6] Apply suggestions from code review Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com> --- content/develop/clients/go/amr.md | 46 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/content/develop/clients/go/amr.md b/content/develop/clients/go/amr.md index cdd3a87ec5..f93c61691f 100644 --- a/content/develop/clients/go/amr.md +++ b/content/develop/clients/go/amr.md @@ -29,11 +29,11 @@ letting `go-redis-entraid` fetch and renew the authentication tokens for you aut Install [`go-redis`]({{< relref "/develop/clients/go" >}}) if you have not already done so. -From a Go module folder, install `go-redis-entraid` with the +Install `go-redis-entraid` with the following command: ```bash -go get github.com/redis-developer/go-redis-entraid +go get github.com/redis/go-redis-entraid ``` ## Create a `StreamingCredentialsProvider` instance @@ -84,16 +84,16 @@ import ( . provider, err := entraid.NewConfidentialCredentialsProvider( entraid.ConfidentialIdentityProviderOptions{ - CredentialsProviderOptions: entraid.CredentialsProviderOptions{ - ClientID: "", - }, - CredentialsType: identity.ClientSecretCredentialType, - ClientSecret: "", - Authority: identity.AuthorityConfiguration{ - AuthorityType: identity.AuthorityTypeDefault, - TenantID: "", - }, - } + ConfidentialIdentityProviderOptions: identity.ConfidentialIdentityProviderOptions{ + ClientID: "", + ClientSecret: "", + CredentialsType: identity.ClientSecretCredentialType, + Authority: identity.AuthorityConfiguration{ + AuthorityType: identity.AuthorityTypeDefault, + TenantID: "", + }, + }, + }, ) ``` @@ -118,13 +118,12 @@ import ( . . provider, err := entraid.NewManagedIdentityCredentialsProvider( - entraid.ManagedIdentityCredentialsProviderOptions{ - CredentialsProviderOptions: entraid.CredentialsProviderOptions{ - ClientID: "", - }, - ManagedIdentityType: identity.UserAssignedIdentity, - UserAssignedClientID: "", - }, + entraid.ManagedIdentityCredentialsProviderOptions{ + ManagedIdentityProviderOptions: identity.ManagedIdentityProviderOptions{ + ManagedIdentityType: identity.UserAssignedObjectID, + UserAssignedObjectID: "", + }, + }, ) ``` @@ -135,7 +134,6 @@ configuration using the `TokenManagerOptions` field of `CredentialsProviderOptio ```go options := entraid.CredentialsProviderOptions{ - ClientID: os.Getenv("AZURE_CLIENT_ID"), TokenManagerOptions: manager.TokenManagerOptions{ ExpirationRefreshRatio: 0.7, LowerRefreshBounds: 10000, @@ -213,12 +211,12 @@ func main() { ) } - // Create credentials provider + // Create credentials provider for system assigned identity provider, err := entraid.NewManagedIdentityCredentialsProvider( entraid.ManagedIdentityCredentialsProviderOptions{ - CredentialsProviderOptions: entraid.CredentialsProviderOptions{ - ClientID: clientID, - }, + ManagedIdentityProviderOptions: identity.ManagedIdentityProviderOptions{ + ManagedIdentityType: identity.SystemAssignedIdentity, + }, } ) if err != nil { From 45b941eaa402a3f530548108352d183bee9ab60b Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Fri, 30 May 2025 10:06:44 +0100 Subject: [PATCH 4/6] DOC-4990 implemented PR feedback --- content/develop/clients/go/amr.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/content/develop/clients/go/amr.md b/content/develop/clients/go/amr.md index f93c61691f..675fab5342 100644 --- a/content/develop/clients/go/amr.md +++ b/content/develop/clients/go/amr.md @@ -27,10 +27,11 @@ letting `go-redis-entraid` fetch and renew the authentication tokens for you aut ## Install Install [`go-redis`]({{< relref "/develop/clients/go" >}}) if you -have not already done so. +have not already done so. Note that `go-redis-entraid` +requires `go-redis` v9.9.0 or above, so you should upgrade if you +are using an earlier version. -Install `go-redis-entraid` with the -following command: +Install `go-redis-entraid` with the following command: ```bash go get github.com/redis/go-redis-entraid @@ -203,11 +204,10 @@ import ( func main() { // Get required environment variables - clientID := os.Getenv("AZURE_CLIENT_ID") redisEndpoint := os.Getenv("REDIS_ENDPOINT") - if clientID == "" || redisEndpoint == "" { + if redisEndpoint == "" { log.Fatal( - "AZURE_CLIENT_ID and REDIS_ENDPOINT env variables are required" + "REDIS_ENDPOINT environment variable is required" ) } From 9d9e46f599b60b1e3b98f978a20e5201b4be2181 Mon Sep 17 00:00:00 2001 From: andy-stark-redis <164213578+andy-stark-redis@users.noreply.github.com> Date: Wed, 4 Jun 2025 14:41:10 +0100 Subject: [PATCH 5/6] Apply suggestions from code review Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com> --- content/develop/clients/go/amr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/develop/clients/go/amr.md b/content/develop/clients/go/amr.md index 675fab5342..a664c5b9bc 100644 --- a/content/develop/clients/go/amr.md +++ b/content/develop/clients/go/amr.md @@ -84,7 +84,7 @@ import ( . . provider, err := entraid.NewConfidentialCredentialsProvider( - entraid.ConfidentialIdentityProviderOptions{ + entraid.ConfidentialCredentialsProviderOptions{ ConfidentialIdentityProviderOptions: identity.ConfidentialIdentityProviderOptions{ ClientID: "", ClientSecret: "", From 0ab1114521b69f0d2908c95a93dceaaffe4e6180 Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Wed, 4 Jun 2025 16:11:05 +0100 Subject: [PATCH 6/6] DOC-4990 added extra example suggested in feedback --- content/develop/clients/go/amr.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/content/develop/clients/go/amr.md b/content/develop/clients/go/amr.md index a664c5b9bc..a9981d6349 100644 --- a/content/develop/clients/go/amr.md +++ b/content/develop/clients/go/amr.md @@ -152,7 +152,23 @@ options := entraid.CredentialsProviderOptions{ } ``` -These options are explained below: +You can then pass this configuration when you create the +`StreamingCredentialsProvider`. The example below shows how to do this +with the `NewManagedIdentityCredentialsProvider()` method: + +```go +provider, err := entraid.NewManagedIdentityCredentialsProvider( + entraid.ManagedIdentityCredentialsProviderOptions{ + CredentialsProviderOptions: options, + ManagedIdentityProviderOptions: identity.ManagedIdentityProviderOptions{ + ManagedIdentityType: identity.UserAssignedObjectID, + UserAssignedObjectID: "", + }, + }, +) +``` + +The fields of `TokenManagerOptions` are explained below: - `ExpirationRefreshRatio`: A `float` value representing the fraction of a token's lifetime that should elapse before attempting to