diff --git a/lib/srv/db/access_test.go b/lib/srv/db/access_test.go index 9a4f3d0ab7925..d6a5c8152da6b 100644 --- a/lib/srv/db/access_test.go +++ b/lib/srv/db/access_test.go @@ -281,13 +281,18 @@ func TestAccessMySQL(t *testing.T) { // TestAccessRedis verifies access scenarios to a Redis database based // on the configured RBAC rules. func TestAccessRedis(t *testing.T) { - ctx := context.Background() - testCtx := setupTestContext(ctx, t, withSelfHostedRedis("redis")) + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + testCtx := setupTestContext(ctx, t, + withSelfHostedRedis("redis"), + withAzureRedis("azure-redis", azureRedisToken)) go testCtx.startHandlingConnections() tests := []struct { // desc is the test case description. desc string + // dbService is the name of the database service to connect to. + dbService string // user is the Teleport local username the test will use. user string // role is the Teleport role name to create and assign to the user. @@ -301,6 +306,7 @@ func TestAccessRedis(t *testing.T) { }{ { desc: "has access to all database users", + dbService: "redis", user: "alice", role: "admin", allowDbUsers: []string{types.Wildcard}, @@ -308,6 +314,7 @@ func TestAccessRedis(t *testing.T) { }, { desc: "has access to nothing", + dbService: "redis", user: "alice", role: "admin", allowDbUsers: []string{}, @@ -316,6 +323,7 @@ func TestAccessRedis(t *testing.T) { }, { desc: "access allowed to specific user", + dbService: "redis", user: "alice", role: "admin", allowDbUsers: []string{"alice"}, @@ -323,12 +331,30 @@ func TestAccessRedis(t *testing.T) { }, { desc: "access denied to specific user", + dbService: "redis", user: "alice", role: "admin", allowDbUsers: []string{"alice"}, dbUser: "root", err: "access to db denied", }, + { + desc: "azure access allowed to default user", + dbService: "azure-redis", + user: "alice", + role: "admin", + allowDbUsers: []string{"default"}, + dbUser: "default", + }, + { + desc: "azure access denied to non-default user", + dbService: "azure-redis", + user: "alice", + role: "admin", + allowDbUsers: []string{"alice"}, + dbUser: "alice", + err: "access denied to non-default db user", + }, } for _, test := range tests { @@ -336,9 +362,8 @@ func TestAccessRedis(t *testing.T) { // Create user/role with the requested permissions. testCtx.createUserAndRole(ctx, t, test.user, test.role, test.allowDbUsers, []string{types.Wildcard}) - ctx := context.Background() // Try to connect to the database as this user. - redisClient, err := testCtx.redisClient(ctx, test.user, "redis", test.dbUser) + redisClient, err := testCtx.redisClient(ctx, test.user, test.dbService, test.dbUser) if test.err != "" { require.Error(t, err) require.Contains(t, err.Error(), test.err) diff --git a/lib/srv/db/redis/engine.go b/lib/srv/db/redis/engine.go index 9c0dcd760e5dc..51e66ce022011 100644 --- a/lib/srv/db/redis/engine.go +++ b/lib/srv/db/redis/engine.go @@ -81,6 +81,10 @@ func (e *Engine) InitializeConnection(clientConn net.Conn, sessionCtx *common.Se // authorizeConnection does authorization check for Redis connection about // to be established. func (e *Engine) authorizeConnection(ctx context.Context) error { + if err := e.checkDefaultUserRequired(); err != nil { + e.Audit.OnSessionStart(e.Context, e.sessionCtx, err) + return trace.Wrap(err) + } authPref, err := e.Auth.GetAuthPreference(ctx) if err != nil { return trace.Wrap(err) @@ -104,6 +108,24 @@ func (e *Engine) authorizeConnection(ctx context.Context) error { return nil } +// checkDefaultUserRequired checks if the session db user is the "default" Redis +// user, and checks if the session db user must be the default user. +// When the session db user is not "default", but it's required to be "default", +// return an error. +func (e *Engine) checkDefaultUserRequired() error { + // When the db user is already "default", there's no need to check if it's + // required to be "default". + if defaults.DefaultRedisUsername == e.sessionCtx.DatabaseUser { + return nil + } + if e.sessionCtx.Database.IsAzure() { + return trace.AccessDenied("access denied to non-default db user: "+ + "Azure Cache for Redis requires authentication as default user %q", + defaults.DefaultRedisUsername) + } + return nil +} + // SendError sends error message to connected client. func (e *Engine) SendError(redisErr error) { if redisErr == nil || utils.IsOKNetworkError(redisErr) { diff --git a/lib/srv/db/redis/protocol/resp2_test.go b/lib/srv/db/redis/protocol/resp2_test.go index eed140d34169f..8ac9a90a7bf2c 100644 --- a/lib/srv/db/redis/protocol/resp2_test.go +++ b/lib/srv/db/redis/protocol/resp2_test.go @@ -146,8 +146,8 @@ func TestMakeUnknownCommandErrorForCmd(t *testing.T) { }{ { name: "HELLO", - command: []interface{}{"HELLO", 3, "user", "TOKEN"}, - expectedError: "ERR unknown command 'HELLO', with args beginning with: '3' 'user' 'TOKEN'", + command: []interface{}{"HELLO", 3, "AUTH", "user", "TOKEN"}, + expectedError: "ERR unknown command 'HELLO', with args beginning with: '3' 'AUTH' 'user' 'TOKEN'", }, { name: "no extra args",