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
10 changes: 10 additions & 0 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,16 @@ const (
// during the setup of Connect My Computer. The prefix is followed by the name of the cluster
// user. See teleterm.connectmycomputer.RoleSetup.
ConnectMyComputerRoleNamePrefix = "connect-my-computer-"

// SystemOktaRequesterRoleName is a name of a system role that allows
Comment thread
zmb3 marked this conversation as resolved.
// for requesting access to Okta resources. This differs from the requester role
// in that it allows for requesting longer lived access.
SystemOktaRequesterRoleName = "okta-requester"

// SystemOktaAccessRoleName is the name of the system role that allows
// access to Okta resources. This will be used by the Okta requester role to
// search for Okta resources.
SystemOktaAccessRoleName = "okta-access"
)

var PresetRoles = []string{PresetEditorRoleName, PresetAccessRoleName, PresetAuditorRoleName}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ spec:
max_duration: 4d
```

The value of `max_duration` can never exceed seven days.
The value of `max_duration` can never exceed fourteen days.

### How long Access Requests are valid

Expand Down
2 changes: 2 additions & 0 deletions lib/auth/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,8 @@ func GetPresetRoles() []types.Role {
services.NewPresetDeviceAdminRole(),
services.NewPresetDeviceEnrollRole(),
services.NewPresetRequireTrustedDeviceRole(),
services.NewSystemOktaAccessRole(),
services.NewSystemOktaRequesterRole(),
}

// Certain `New$FooRole()` functions will return a nil role if the
Expand Down
2 changes: 2 additions & 0 deletions lib/auth/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -797,6 +797,8 @@ func TestPresets(t *testing.T) {

enterpriseSystemRoleNames := []string{
teleport.SystemAutomaticAccessApprovalRoleName,
teleport.SystemOktaAccessRoleName,
teleport.SystemOktaRequesterRoleName,
}

enterpriseUsers := []types.User{
Expand Down
9 changes: 4 additions & 5 deletions lib/services/access_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const day = 24 * time.Hour

// maxAccessDuration is the maximum duration that an access request can be
// granted for.
const maxAccessDuration = 7 * day
const maxAccessDuration = 14 * day

// ValidateAccessRequest validates the AccessRequest and sets default values
func ValidateAccessRequest(ar types.AccessRequest) error {
Expand Down Expand Up @@ -369,7 +369,7 @@ func ValidateAccessPredicates(role types.Role) error {

if maxDuration := role.GetAccessRequestConditions(types.Allow).MaxDuration; maxDuration.Duration() != 0 &&
maxDuration.Duration() > maxAccessDuration {
return trace.BadParameter("max access duration must be less or equal 7 days")
return trace.BadParameter("max access duration must be less than or equal to %v", maxAccessDuration)
}

return nil
Expand Down Expand Up @@ -1230,17 +1230,16 @@ func (m *RequestValidator) calculateMaxAccessDuration(req types.AccessRequest) (

maxDuration := maxDurationTime.Sub(req.GetCreationTime())

// For dry run requests, the max_duration is set to 7 days.
// For dry run requests, use the maximum possible duration.
// This prevents the time drift that can occur as the value is set on the client side.
// TODO(jakule): Replace with MaxAccessDuration that is a duration (5h, 4d etc), and not a point in time.
if req.GetDryRun() {
maxDuration = maxAccessDuration
} else if maxDuration < 0 {
return 0, trace.BadParameter("invalid maxDuration: must be greater than creation time")
}

if maxDuration > maxAccessDuration {
return 0, trace.BadParameter("max_duration must be less or equal 7 days")
return 0, trace.BadParameter("max_duration must be less than or equal to %v", maxAccessDuration)
}

minAdjDuration := maxDuration
Expand Down
137 changes: 124 additions & 13 deletions lib/services/presets.go
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,70 @@ func NewPresetRequireTrustedDeviceRole() types.Role {
}
}

// NewSystemOktaAccessRoleName is the system role that allows
// access to Okta resources. This will be used by the Okta requester role to
// search for Okta resources.
func NewSystemOktaAccessRole() types.Role {
if modules.GetModules().BuildType() != modules.BuildEnterprise {
return nil
}

role := &types.RoleV6{
Kind: types.KindRole,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.SystemOktaAccessRoleName,
Namespace: apidefaults.Namespace,
Description: "Request Okta resources",
Labels: map[string]string{
types.TeleportInternalResourceType: types.SystemResource,
},
},
Spec: types.RoleSpecV6{
Allow: types.RoleConditions{
AppLabels: types.Labels{
types.OriginLabel: []string{types.OriginOkta},
},
GroupLabels: types.Labels{
types.OriginLabel: []string{types.OriginOkta},
},
Rules: []types.Rule{
types.NewRule(types.KindUserGroup, RO()),
},
},
},
}
return role
}

// NewSystemOktaRequesterRoleName is a system role that allows
// for requesting access to Okta resources. This differs from the requester role
// in that it allows for requesting longer lived access.
func NewSystemOktaRequesterRole() types.Role {
if modules.GetModules().BuildType() != modules.BuildEnterprise {
return nil
}

role := &types.RoleV6{
Kind: types.KindRole,
Version: types.V7,
Metadata: types.Metadata{
Name: teleport.SystemOktaRequesterRoleName,
Namespace: apidefaults.Namespace,
Description: "Request Okta resources",
Labels: map[string]string{
types.TeleportInternalResourceType: types.SystemResource,
},
},
Spec: types.RoleSpecV6{
Allow: types.RoleConditions{
Request: defaultAllowAccessRequestConditions(true)[teleport.SystemOktaRequesterRoleName],
},
},
}
return role
}

// bootstrapRoleMetadataLabels are metadata labels that will be applied to each role.
// These are intended to add labels for older roles that didn't previously have them.
func bootstrapRoleMetadataLabels() map[string]map[string]string {
Expand Down Expand Up @@ -520,14 +584,25 @@ func defaultAllowRules() map[string][]types.Rule {
// defaultAllowLabels has the Allow labels that should be set as default when they were not explicitly defined.
// This is used to update existing builtin preset roles with new permissions during cluster upgrades.
// The following Labels are supported:
// - AppLabels
// - DatabaseServiceLabels (db_service_labels)
func defaultAllowLabels() map[string]types.RoleConditions {
return map[string]types.RoleConditions{
// - GroupLabels
func defaultAllowLabels(enterprise bool) map[string]types.RoleConditions {
conditions := map[string]types.RoleConditions{
teleport.PresetAccessRoleName: {
DatabaseServiceLabels: types.Labels{types.Wildcard: []string{types.Wildcard}},
DatabaseRoles: []string{teleport.TraitInternalDBRolesVariable},
},
}

if enterprise {
conditions[teleport.SystemOktaAccessRoleName] = types.RoleConditions{
AppLabels: types.Labels{types.OriginLabel: []string{types.OriginOkta}},
GroupLabels: types.Labels{types.OriginLabel: []string{types.OriginOkta}},
}
}

return conditions
}

// defaultAllowAccessRequestConditions has the access request conditions that should be set as default when they were
Expand All @@ -541,6 +616,12 @@ func defaultAllowAccessRequestConditions(enterprise bool) map[string]*types.Acce
teleport.PresetGroupAccessRoleName,
},
},
teleport.SystemOktaRequesterRoleName: {
SearchAsRoles: []string{
teleport.SystemOktaAccessRoleName,
},
MaxDuration: types.NewDuration(maxAccessDuration),
},
}
}

Expand Down Expand Up @@ -597,7 +678,8 @@ func AddRoleDefaults(role types.Role) (types.Role, error) {
// labels because we set the role metadata labels for roles that have been well established (access,
// editor, auditor) that may not already have this label set, but we don't set it for newer roles
// (group-access, reviewer, requester) that may have customer definitions.
if role.GetMetadata().Labels[types.TeleportInternalResourceType] != types.PresetResource {
resourceType := role.GetMetadata().Labels[types.TeleportInternalResourceType]
if resourceType != types.PresetResource && resourceType != types.SystemResource {
return nil, trace.AlreadyExists("not modifying user created role")
}

Expand All @@ -619,25 +701,37 @@ func AddRoleDefaults(role types.Role) (types.Role, error) {
}
}

enterprise := modules.GetModules().BuildType() == modules.BuildEnterprise

// Labels
defaultLabels, ok := defaultAllowLabels()[role.GetName()]
defaultLabels, ok := defaultAllowLabels(enterprise)[role.GetName()]
if ok {
if unset, err := labelMatchersUnset(role, types.KindDatabaseService); err != nil {
return nil, trace.Wrap(err)
} else if unset && len(defaultLabels.DatabaseServiceLabels) > 0 {
role.SetLabelMatchers(types.Allow, types.KindDatabaseService, types.LabelMatchers{
Labels: defaultLabels.DatabaseServiceLabels,
})
changed = true
for _, kind := range []string{
types.KindApp,
types.KindDatabaseService,
types.KindUserGroup,
} {
var labels types.Labels
switch kind {
case types.KindApp:
labels = defaultLabels.AppLabels
case types.KindDatabaseService:
labels = defaultLabels.DatabaseServiceLabels
case types.KindUserGroup:
labels = defaultLabels.GroupLabels
}
labelsUpdated, err := updateAllowLabels(role, kind, labels)
if err != nil {
return nil, trace.Wrap(err)
}
changed = changed || labelsUpdated
}
if len(defaultLabels.DatabaseRoles) > 0 && len(role.GetDatabaseRoles(types.Allow)) == 0 {
role.SetDatabaseRoles(types.Allow, defaultLabels.DatabaseRoles)
changed = true
}
}

enterprise := modules.GetModules().BuildType() == modules.BuildEnterprise

if role.GetAccessRequestConditions(types.Allow).IsEmpty() {
arc := defaultAllowAccessRequestConditions(enterprise)[role.GetName()]
if arc != nil {
Expand Down Expand Up @@ -685,3 +779,20 @@ func resourceBelongsToRules(rules []types.Rule, resources []string) bool {

return false
}

func updateAllowLabels(role types.Role, kind string, defaultLabels types.Labels) (bool, error) {
unset, err := labelMatchersUnset(role, kind)
if err != nil {
return false, trace.Wrap(err)
}

var changed bool
if unset && len(defaultLabels) > 0 {
role.SetLabelMatchers(types.Allow, kind, types.LabelMatchers{
Labels: defaultLabels,
})
changed = true
}

return changed, nil
}
Loading