diff --git a/lib/auth/auth.go b/lib/auth/auth.go index 9e3a36d801042..9dccbee790571 100644 --- a/lib/auth/auth.go +++ b/lib/auth/auth.go @@ -136,7 +136,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" @@ -7674,25 +7673,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 a086cf2dddb19..2b18ccc84a29b 100644 --- a/lib/auth/auth_with_roles_test.go +++ b/lib/auth/auth_with_roles_test.go @@ -3854,7 +3854,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", @@ -3880,6 +3882,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 {