diff --git a/lib/auth/auth.go b/lib/auth/auth.go index 37b059d05cd07..cb2d502de287f 100644 --- a/lib/auth/auth.go +++ b/lib/auth/auth.go @@ -124,7 +124,6 @@ import ( "github.com/gravitational/teleport/lib/services/local" "github.com/gravitational/teleport/lib/services/readonly" "github.com/gravitational/teleport/lib/spacelift" - "github.com/gravitational/teleport/lib/srv/db/common/role" "github.com/gravitational/teleport/lib/sshca" "github.com/gravitational/teleport/lib/sshutils" "github.com/gravitational/teleport/lib/terraformcloud" @@ -7290,25 +7289,11 @@ func (a *Server) isMFARequired(ctx context.Context, checker services.AccessCheck return nil, trace.NotFound("database service %q not found", t.Database.ServiceName) } - autoCreate, err := checker.DatabaseAutoUserMode(db) - switch { - case errors.Is(err, services.ErrSessionMFARequired): - noMFAAccessErr = err - case err != nil: - return nil, trace.Wrap(err) - default: - dbRoleMatchers := role.GetDatabaseRoleMatchers(role.RoleMatchersConfig{ - Database: db, - DatabaseUser: t.Database.Username, - DatabaseName: t.Database.GetDatabase(), - AutoCreateUser: autoCreate.IsEnabled(), - }) - noMFAAccessErr = checker.CheckAccess( - db, - services.AccessState{}, - dbRoleMatchers..., - ) - } + // Note that we are not checking RoleMatchers for db user/name/roles. + // Per-session MFA requirement is only tested on the resource itself by + // db_labels/db_labels_expression, so db user/name/roles are irrelevant. + // Those will be enforced at protocol level on the database service. + noMFAAccessErr = checker.CheckAccess(db, services.AccessState{}) case *proto.IsMFARequiredRequest_WindowsDesktop: desktops, err := a.GetWindowsDesktops(ctx, types.WindowsDesktopFilter{Name: t.WindowsDesktop.GetWindowsDesktop()}) diff --git a/lib/auth/auth_with_roles_test.go b/lib/auth/auth_with_roles_test.go index de18ceac4aed7..80b522e3545f6 100644 --- a/lib/auth/auth_with_roles_test.go +++ b/lib/auth/auth_with_roles_test.go @@ -3751,7 +3751,9 @@ func TestIsMFARequired_databaseProtocols(t *testing.T) { role.SetDatabaseLabels(types.Allow, types.Labels{types.Wildcard: {types.Wildcard}}) role.SetDatabaseNames(types.Allow, nil) }, - want: proto.MFARequired_MFA_REQUIRED_NO, + // MFA should be required if the role says so, regardless of whether + // the database name matches or not. + want: proto.MFARequired_MFA_REQUIRED_YES, }, { name: "RequireSessionMFA on Postgres protocol database name matches", @@ -3777,6 +3779,32 @@ func TestIsMFARequired_databaseProtocols(t *testing.T) { }, want: proto.MFARequired_MFA_REQUIRED_YES, }, + { + name: "RequireSessionMFA database user does not match", + dbProtocol: defaults.ProtocolPostgres, + req: &proto.IsMFARequiredRequest{ + Target: &proto.IsMFARequiredRequest_Database{ + Database: &proto.RouteToDatabase{ + ServiceName: databaseName, + Protocol: defaults.ProtocolPostgres, + Username: userName, + Database: "example", + }, + }, + }, + modifyRoleFunc: func(role types.Role) { + roleOpt := role.GetOptions() + roleOpt.RequireMFAType = types.RequireMFAType_SESSION + role.SetOptions(roleOpt) + + role.SetDatabaseUsers(types.Allow, nil) + role.SetDatabaseLabels(types.Allow, types.Labels{types.Wildcard: {types.Wildcard}}) + role.SetDatabaseNames(types.Allow, []string{"example"}) + }, + // MFA should be required if the role says so, regardless of whether + // the database user matches or not. + want: proto.MFARequired_MFA_REQUIRED_YES, + }, } for _, tc := range tests {