Skip to content

Commit 13fd8c1

Browse files
authored
Merge pull request #292575 from xfz11/xf/redissample
add sample for redis entra auth
2 parents 3a025ca + 1f5fec8 commit 13fd8c1

File tree

4 files changed

+328
-12
lines changed

4 files changed

+328
-12
lines changed

articles/service-connector/how-to-integrate-redis-cache.md

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,43 @@ The table below shows which combinations of authentication methods and clients a
2828

2929
| Client type | System-assigned managed identity | User-assigned managed identity | Secret / connection string | Service principal |
3030
|--------------------|----------------------------------|--------------------------------|----------------------------|-------------------|
31-
| .NET | No | No | Yes | No |
31+
| .NET | Yes | Yes | Yes | Yes |
3232
| Go | No | No | Yes | No |
33-
| Java | No | No | Yes | No |
33+
| Java | Yes | Yes | Yes | Yes |
3434
| Java - Spring Boot | No | No | Yes | No |
35-
| Node.js | No | No | Yes | No |
36-
| Python | No | No | Yes | No |
37-
| None | No | No | Yes | No |
35+
| Node.js | Yes | Yes | Yes | Yes |
36+
| Python | Yes | Yes | Yes | Yes |
37+
| None | Yes | Yes | Yes | Yes |
3838

3939
This table indicates that the only supported authentication method for all client types in the table is the Secret / connection string method. Other authentication methods are not supported for any of the client types to connect to Azure Cache for Redis using Service Connector.
4040

4141
## Default environment variable names or application properties and sample code
4242

4343
Use the environment variable names and application properties listed below to connect compute services to Redis Server. For each example below, replace the placeholder texts `<redis-server-name>`, and `<redis-key>` with your own Redis server name and key. For more information about naming conventions, check the [Service Connector internals](concept-service-connector-internals.md#configuration-naming-convention) article.
4444

45+
### System-assigned managed identity
46+
47+
| Default environment variable name | Description | Sample value |
48+
| ---------------------------------------- | --------------------- | -------------------------------------------------- |
49+
| AZURE_REDIS_HOST | Redis Endpoint | `<RedisName>.redis.cache.windows.net` |
50+
51+
#### Sample code
52+
53+
Refer to the steps and code below to connect to Redis using a system-assigned managed identity.
54+
[!INCLUDE [code sample for redis](./includes/code-redis-me-id.md)]
55+
56+
### User-assigned managed identity
57+
58+
| Default environment variable name | Description | Sample value |
59+
| ---------------------------------------- | --------------------- | -------------------------------------------------- |
60+
| AZURE_REDIS_HOST | Redis Endpoint | `<RedisName>.redis.cache.windows.net` |
61+
| AZURE_REDIS_CLIENTID | managed identity client ID | `<client-ID>` |
62+
63+
#### Sample code
64+
65+
Refer to the steps and code below to connect to Redis using a user-assigned managed identity.
66+
[!INCLUDE [code sample for Redis](./includes/code-redis-me-id.md)]
67+
4568
### Connection String
4669

4770
> [!WARNING]
@@ -104,6 +127,20 @@ Use the environment variable names and application properties listed below to co
104127
Refer to the steps and code below to connect to Azure Cache for Redis using a connection string.
105128
[!INCLUDE [code for redis](./includes/code-redis-secret.md)]
106129

130+
### Service Principal
131+
132+
| Default environment variable name | Description | Sample value |
133+
| ---------------------------------------- | --------------------- | -------------------------------------------------- |
134+
| AZURE_REDIS_HOST | Redis Endpoint | `<RedisName>.redis.cache.windows.net` |
135+
| AZURE_REDIS_CLIENTID | client ID of service principal | `<client-ID>` |
136+
| AZURE_REDIS_CLIENTSECRET | secret of the service principal | `<client-secret>` |
137+
| AZURE_REDIS_TENANTID | tenant ID of the service principal | `<tenant-id>` |
138+
139+
#### Sample code
140+
141+
Refer to the steps and code below to connect to Redis using a Service Principal.
142+
[!INCLUDE [code sample for Redis](./includes/code-redis-me-id.md)]
143+
107144
## Next steps
108145

109146
Follow the tutorials listed below to learn more about Service Connector.

articles/service-connector/includes/code-postgres-me-id.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ For more tutorials, see [Use Spring Data JDBC with Azure Database for PostgreSQL
269269
// const tenantId = process.env.AZURE_POSTGRESQL_TENANTID;
270270
// const clientId = process.env.AZURE_POSTGRESQL_CLIENTID;
271271
// const clientSecret = process.env.AZURE_POSTGRESQL_CLIENTSECRET;
272+
// const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
272273

273274
// Acquire the access token.
274275
var accessToken = await credential.getToken('https://ossrdbms-aad.database.windows.net/.default');
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
---
2+
author: xfz11
3+
description: Code example
4+
ms.service: service-connector
5+
ms.topic: include
6+
ms.date: 1/2/2025
7+
ms.author: xiaofanzhou
8+
---
9+
10+
#### [.NET](#tab/dotnet)
11+
12+
1. Install dependencies.
13+
```bash
14+
dotnet add package Microsoft.Azure.StackExchangeRedis --version 3.2.0
15+
```
16+
1. Add the authentication logic with environment variables set by Service Connector. For more information, see [Microsoft.Azure.StackExchangeRedis Extension](https://github.com/Azure/Microsoft.Azure.StackExchangeRedis).
17+
18+
19+
```csharp
20+
using StackExchange.Redis;
21+
var cacheHostName = Environment.GetEnvironmentVariable("AZURE_REDIS_HOST");
22+
var configurationOptions = ConfigurationOptions.Parse($"{cacheHostName}:6380");
23+
24+
// Uncomment the following lines corresponding to the authentication type you want to use.
25+
// For system-assigned identity.
26+
// await configurationOptions.ConfigureForAzureWithTokenCredentialAsync(new DefaultAzureCredential());
27+
28+
// For user-assigned identity.
29+
// var managedIdentityClientId = Environment.GetEnvironmentVariable("AZURE_REDIS_CLIENTID");
30+
// await configurationOptions.ConfigureForAzureWithUserAssignedManagedIdentityAsync(managedIdentityClientId);
31+
32+
// Service principal secret
33+
// var clientId = Environment.GetEnvironmentVariable("AZURE_REDIS_CLIENTID");
34+
// var tenantId = Environment.GetEnvironmentVariable("AZURE_REDIS_TENANTID");
35+
// var secret = Environment.GetEnvironmentVariable("AZURE_REDIS_CLIENTSECRET");
36+
// await configurationOptions.ConfigureForAzureWithServicePrincipalAsync(clientId, tenantId, secret);
37+
38+
39+
var connectionMultiplexer = await ConnectionMultiplexer.ConnectAsync(configurationOptions);
40+
```
41+
42+
#### [Java](#tab/java)
43+
44+
1. Add the following dependency in your *pom.xml* file:
45+
```xml
46+
<dependency>
47+
<groupId>com.azure</groupId>
48+
<artifactId>azure-identity</artifactId>
49+
<version>1.11.2</version> <!-- {x-version-update;com.azure:azure-identity;dependency} -->
50+
</dependency>
51+
52+
<dependency>
53+
<groupId>redis.clients</groupId>
54+
<artifactId>jedis</artifactId>
55+
<version>5.1.0</version> <!-- {x-version-update;redis.clients:jedis;external_dependency} -->
56+
</dependency>
57+
```
58+
1. Add the authentication logic with environment variables set by Service Connector. For more information, see [Azure-AAD-Authentication-With-Jedis](https://aka.ms/redis/aad/sample-code/java-jedis).
59+
```java
60+
import redis.clients.jedis.DefaultJedisClientConfig;
61+
import redis.clients.jedis.Jedis;
62+
import redis.clients.jedis.JedisShardInfo;
63+
import java.net.URI;
64+
65+
// Uncomment the following lines corresponding to the authentication type you want to use.
66+
// For system-assigned identity.
67+
// DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilder().build();
68+
69+
// For user-assigned identity.
70+
// String clientId = System.getenv("AZURE_REDIS_CLIENTID");
71+
// DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilder().managedIdentityClientId(clientId).build();
72+
73+
// For AKS workload identity identity.
74+
// String clientId = System.getenv("AZURE_REDIS_CLIENTID");
75+
// DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilder().workloadIdentityClientId(clientId).build();
76+
77+
// For service principal.
78+
// String clientId = System.getenv("AZURE_REDIS_CLIENTID");
79+
// String secret = System.getenv("AZURE_REDIS_CLIENTSECRET");
80+
// String tenant = System.getenv("AZURE_REDIS_TENANTID");
81+
// ClientSecretCredential defaultAzureCredential = new ClientSecretCredentialBuilder().tenantId(tenant).clientId(clientId).clientSecret(secret).build();
82+
83+
String token = defaultAzureCredential
84+
.getToken(new TokenRequestContext()
85+
.addScopes("https://redis.azure.com/.default")).block().getToken();
86+
87+
// SSL connection is required.
88+
boolean useSsl = true;
89+
// TODO: Replace Host Name with Azure Cache for Redis Host Name.
90+
String username = extractUsernameFromToken(token);
91+
String cacheHostname = System.getenv("AZURE_REDIS_HOST");
92+
93+
// Create Jedis client and connect to the Azure Cache for Redis over the TLS/SSL port using the access token as password.
94+
// Note, Redis Cache Host Name and Port are required below
95+
Jedis jedis = new Jedis(cacheHostname, 6380, DefaultJedisClientConfig.builder()
96+
.password(token) // Microsoft Entra access token as password is required.
97+
.user(username) // Username is Required
98+
.ssl(useSsl) // SSL Connection is Required
99+
.build());
100+
101+
// Set a value against your key in the Redis cache.
102+
jedis.set("Az:key", "testValue");
103+
System.out.println(jedis.get("Az:key"));
104+
105+
// Close the Jedis Client
106+
jedis.close();
107+
```
108+
109+
#### [Python](#tab/python)
110+
111+
1. Install dependencies.
112+
```bash
113+
pip install redis azure-identity
114+
```
115+
1. Add the authentication logic with environment variables set by Service Connector. For more information, see [azure-aad-auth-with-redis-py](https://aka.ms/redis/aad/sample-code/python).
116+
```python
117+
import os
118+
import time
119+
import logging
120+
import redis
121+
import base64
122+
import json
123+
from azure.identity import DefaultAzureCredential
124+
125+
host = os.getenv('AZURE_REDIS_HOST')
126+
scope = "https://redis.azure.com/.default"
127+
port = 6380 # Required
128+
129+
def extract_username_from_token(token):
130+
parts = token.split('.')
131+
base64_str = parts[1]
132+
133+
if len(base64_str) % 4 == 2:
134+
base64_str += "=="
135+
elif len(base64_str) % 4 == 3:
136+
base64_str += "="
137+
138+
json_bytes = base64.b64decode(base64_str)
139+
json_str = json_bytes.decode('utf-8')
140+
jwt = json.loads(json_str)
141+
142+
return jwt['oid']
143+
144+
def re_authentication():
145+
_LOGGER = logging.getLogger(__name__)
146+
# Uncomment the following lines corresponding to the authentication type you want to use.
147+
# For system-assigned identity.
148+
# cred = DefaultAzureCredential()
149+
150+
# For user-assigned identity.
151+
# client_id = os.getenv('AZURE_REDIS_CLIENTID')
152+
# cred = DefaultAzureCredential(managed_identity_client_id=client_id)
153+
154+
# For user-assigned identity.
155+
# client_id = os.getenv('AZURE_REDIS_CLIENTID')
156+
# cred = DefaultAzureCredential(managed_identity_client_id=client_id)
157+
158+
# For service principal.
159+
# tenant_id = os.getenv("AZURE_TENANT_ID")
160+
# client_id = os.getenv("AZURE_CLIENT_ID")
161+
# client_secret = os.getenv("AZURE_CLIENT_SECRET")
162+
# cred = ServicePrincipalCredentials(tenant=tenant_id, client_id=client_id, secret=client_secret)
163+
164+
token = cred.get_token(scope)
165+
user_name = extract_username_from_token(token.token)
166+
r = redis.Redis(host=host,
167+
port=port,
168+
ssl=True, # ssl connection is required.
169+
username=user_name,
170+
password=token.token,
171+
decode_responses=True)
172+
max_retry = 3
173+
for index in range(max_retry):
174+
try:
175+
if _need_refreshing(token):
176+
_LOGGER.info("Refreshing token...")
177+
tmp_token = cred.get_token(scope)
178+
if tmp_token:
179+
token = tmp_token
180+
r.execute_command("AUTH", user_name, token.token)
181+
r.set("Az:key1", "value1")
182+
t = r.get("Az:key1")
183+
print(t)
184+
break
185+
except redis.ConnectionError:
186+
_LOGGER.info("Connection lost. Reconnecting.")
187+
token = cred.get_token(scope)
188+
r = redis.Redis(host=host,
189+
port=port,
190+
ssl=True, # ssl connection is required.
191+
username=user_name,
192+
password=token.token,
193+
decode_responses=True)
194+
except Exception:
195+
_LOGGER.info("Unknown failures.")
196+
break
197+
198+
199+
def _need_refreshing(token, refresh_offset=300):
200+
return not token or token.expires_on - time.time() < refresh_offset
201+
202+
if __name__ == '__main__':
203+
re_authentication()
204+
```
205+
206+
#### [NodeJS](#tab/nodejs)
207+
208+
1. Install dependencies.
209+
```bash
210+
npm install redis @azure/identity
211+
```
212+
1. Add the authentication logic with environment variables set by Service Connector. For more information, see (Azure Cache for Redis: Microsoft Entra ID with node-redis client library)[https://aka.ms/redis/aad/sample-code/js-noderedis].
213+
214+
```javascript
215+
import { createClient } from "redis";
216+
import { DefaultAzureCredential } from "@azure/identity";
217+
218+
function extractUsernameFromToken(accessToken: AccessToken): string{
219+
const base64Metadata = accessToken.token.split(".")[1];
220+
const { oid } = JSON.parse(
221+
Buffer.from(base64Metadata, "base64").toString("utf8"),
222+
);
223+
return oid;
224+
}
225+
226+
async function main() {
227+
// Uncomment the following lines corresponding to the authentication type you want to use.
228+
// For system-assigned identity.
229+
// const credential = new DefaultAzureCredential();
230+
231+
// For user-assigned identity.
232+
// const clientId = process.env.AZURE_REDIS_CLIENTID;
233+
// const credential = new DefaultAzureCredential({
234+
// managedIdentityClientId: clientId
235+
// });
236+
237+
// For service principal.
238+
// const tenantId = process.env.AZURE_REDIS_TENANTID;
239+
// const clientId = process.env.AZURE_REDIS_CLIENTID;
240+
// const clientSecret = process.env.AZURE_REDIS_CLIENTSECRET;
241+
// const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
242+
243+
// Fetch a Microsoft Entra token to be used for authentication. This token will be used as the password.
244+
const redisScope = "https://redis.azure.com/.default";
245+
let accessToken = await credential.getToken(redisScope);
246+
console.log("access Token", accessToken);
247+
const host = process.env.AZURE_REDIS_HOST;
248+
249+
// Create redis client and connect to the Azure Cache for Redis over the TLS port using the access token as password.
250+
const client = createClient({
251+
username: extractUsernameFromToken(accessToken),
252+
password: accessToken.token,
253+
url: `redis://${host}:6380`,
254+
pingInterval: 100000,
255+
socket: {
256+
tls: true,
257+
keepAlive: 0
258+
},
259+
});
260+
261+
client.on("error", (err) => console.log("Redis Client Error", err));
262+
await client.connect();
263+
// Set a value against your key in the Azure Redis Cache.
264+
await client.set("Az:key", "value1312");
265+
// Get value of your key in the Azure Redis Cache.
266+
console.log("value-", await client.get("Az:key"));
267+
}
268+
269+
main().catch((err) => {
270+
console.log("error code: ", err.code);
271+
console.log("error message: ", err.message);
272+
console.log("error stack: ", err.stack);
273+
});
274+
```
275+
276+
### [Other](#tab/none)
277+
278+
For other languages, you can use the Azure Identity client library and connection information that Service Connector sets to the environment variables to connect to Azure Cache for Redis.

0 commit comments

Comments
 (0)