|
| 1 | +# Authentication |
| 2 | + |
| 3 | +There are multiple ways of connecting to a Redis server, depending on the authentication model. The simplest |
| 4 | +(but least secure) approach is to use the `default` user, with no authentication, and no transport security. |
| 5 | +This is as simple as: |
| 6 | + |
| 7 | +``` csharp |
| 8 | +var muxer = await ConnectionMultiplexer.ConnectAsync("myserver"); // or myserver:1241 to use a custom port |
| 9 | +``` |
| 10 | + |
| 11 | +This approach is often used for local transient servers - it is simple, but insecure. But from there, |
| 12 | +we can get more complex! |
| 13 | + |
| 14 | +## TLS |
| 15 | + |
| 16 | +If your server has TLS enabled, SE.Redis can be instructed to use it. In some cases (Azure Managed Redis, etc), the |
| 17 | +library will recognize the endpoint address, meaning: *you do not need to do anything*. To |
| 18 | +*manually* enable TLS, the `ssl` token can be used: |
| 19 | + |
| 20 | +``` csharp |
| 21 | +var muxer = await ConnectionMultiplexer.ConnectAsync("myserver,ssl=true"); |
| 22 | +``` |
| 23 | + |
| 24 | +This will work fine if the server is using a server-certificate that is already trusted by the local |
| 25 | +machine. If this is *not* the case, we need to tell the library about the server. This requires |
| 26 | +the `ConfigurationOptions` type: |
| 27 | + |
| 28 | +``` csharp |
| 29 | +var options = ConfigurationOptions.Parse("myserver,ssl=true"); |
| 30 | +// or: var options = new ConfigurationOptions { Endpoints = { "myserver" }, Ssl = true }; |
| 31 | +// TODO configure |
| 32 | +var muxer = await ConnectionMultiplexer.ConnectAsync(options); |
| 33 | +``` |
| 34 | + |
| 35 | +If we have a local *issuer* public certificate (commonly `ca.crt`), we can use: |
| 36 | + |
| 37 | +``` csharp |
| 38 | +options.TrustIssuer(caPath); |
| 39 | +``` |
| 40 | + |
| 41 | +Alternatively, in advanced scenarios: to provide your own custom server validation, the `options.CertificateValidation` callback |
| 42 | +can be used; this uses the normal [`RemoteCertificateValidationCallback`](https://learn.microsoft.com/dotnet/api/system.net.security.remotecertificatevalidationcallback) |
| 43 | +API. |
| 44 | + |
| 45 | +## Usernames and Passwords |
| 46 | + |
| 47 | +Usernames and passwords can be specified with the `user` and `password` tokens, respectively: |
| 48 | + |
| 49 | +``` csharp |
| 50 | +var muxer = await ConnectionMultiplexer.ConnectAsync("myserver,ssl=true,user=myuser,password=mypassword"); |
| 51 | +``` |
| 52 | + |
| 53 | +If no `user` is provided, the `default` user is assumed. In some cases, an authentication-token can be |
| 54 | +used in place of a classic password. |
| 55 | + |
| 56 | +## Managed identities |
| 57 | + |
| 58 | +If the server is an Azure Managed Redis resource, connections can be secured using Microsoft Entra ID authentication. Use the [Microsoft.Azure.StackExchangeRedis](https://github.com/Azure/Microsoft.Azure.StackExchangeRedis) extension package to handle the authentication using tokens retrieved from Microsoft Entra. The package integrates via the ConfigurationOptions class, and can use various types of identities for token retrieval. For example with a user-assigned managed identity: |
| 59 | + |
| 60 | +```csharp |
| 61 | +var options = ConfigurationOptions.Parse("mycache.region.redis.azure.net:10000"); |
| 62 | +await options.ConfigureForAzureWithUserAssignedManagedIdentityAsync(managedIdentityClientId); |
| 63 | +``` |
| 64 | + |
| 65 | +For details and samples see [https://github.com/Azure/Microsoft.Azure.StackExchangeRedis](https://github.com/Azure/Microsoft.Azure.StackExchangeRedis) |
| 66 | + |
| 67 | +## Client certificates |
| 68 | + |
| 69 | +If the server is configured to require a client certificate, this can be supplied in multiple ways. |
| 70 | +If you have a local public / private key pair (such as `MyUser2.crt` and `MyUser2.key`), the |
| 71 | +`options.SetUserPemCertificate(...)` method can be used: |
| 72 | + |
| 73 | +``` csharp |
| 74 | +options.SetUserPemCertificate( |
| 75 | + userCertificatePath: userCrtPath, |
| 76 | + userKeyPath: userKeyPath |
| 77 | +); |
| 78 | +``` |
| 79 | + |
| 80 | +If you have a single `pfx` file that contains the public / private pair, the `options.SetUserPfxCertificate(...)` |
| 81 | +method can be used: |
| 82 | + |
| 83 | +``` csharp |
| 84 | +options.SetUserPfxCertificate( |
| 85 | + userCertificatePath: userCrtPath, |
| 86 | + password: filePassword // optional |
| 87 | +); |
| 88 | +``` |
| 89 | + |
| 90 | +Alternatively, in advanced scenarios: to provide your own custom client-certificate lookup, the `options.CertificateSelection` callback |
| 91 | +can be used; this uses the normal |
| 92 | +[`LocalCertificateSelectionCallback`](https://learn.microsoft.com/dotnet/api/system.net.security.remotecertificatevalidationcallback) |
| 93 | +API. |
| 94 | + |
| 95 | +## User certificates with implicit user authentication |
| 96 | + |
| 97 | +Historically, the client certificate only provided access to the server, but as the `default` user. From 8.6, |
| 98 | +the server can be configured to use client certificates to provide user identity. This replaces the |
| 99 | +usage of passwords, and requires: |
| 100 | + |
| 101 | +- An 8.6+ server, configured to use TLS with client certificates mapped - typically using the `CN` of the certificate as the user. |
| 102 | +- A matching `ACL` user account configured on the server, that is enabled (`on`) - i.e. the `ACL LIST` command should |
| 103 | + display something like `user MyUser2 on sanitize-payload ~* &* +@all` (the details will vary depending on the user permissions). |
| 104 | +- At the client: access to the client certificate pair. |
| 105 | + |
| 106 | +For example: |
| 107 | + |
| 108 | +``` csharp |
| 109 | +string certRoot = // some path to a folder with ca.crt, MyUser2.crt and MyUser2.key |
| 110 | +
|
| 111 | +var options = ConfigurationOptions.Parse("myserver:6380"); |
| 112 | +options.SetUserPemCertificate(// automatically enables TLS |
| 113 | + userCertificatePath: Path.Combine(certRoot, "MyUser2.crt"), |
| 114 | + userKeyPath: Path.Combine(certRoot, "MyUser2.key")); |
| 115 | +options.TrustIssuer(Path.Combine(certRoot, "ca.crt")); |
| 116 | +await using var conn = await ConnectionMultiplexer.ConnectAsync(options); |
| 117 | + |
| 118 | +// prove we are connected as MyUser2 |
| 119 | +var user = (string?)await conn.GetDatabase().ExecuteAsync("acl", "whoami"); |
| 120 | +Console.WriteLine(user); // writes "MyUser2" |
| 121 | +``` |
| 122 | + |
| 123 | +## More info |
| 124 | + |
| 125 | +For more information: |
| 126 | + |
| 127 | +- [Redis Security](https://redis.io/docs/latest/operate/oss_and_stack/management/security/) |
| 128 | + - [ACL](https://redis.io/docs/latest/operate/oss_and_stack/management/security/acl/) |
| 129 | + - [TLS](https://redis.io/docs/latest/operate/oss_and_stack/management/security/encryption/) |
0 commit comments