Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 5 additions & 20 deletions lib/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,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"
Expand Down Expand Up @@ -7692,25 +7691,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()})
Expand Down
30 changes: 29 additions & 1 deletion lib/auth/auth_with_roles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3850,7 +3850,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",
Expand All @@ -3876,6 +3878,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 {
Expand Down
Loading