Skip to content

Commit

Permalink
GitHub proxy: role presets and user traits (#51299)
Browse files Browse the repository at this point in the history
* GitHub proxy: role presets and user traits

* fix ut
  • Loading branch information
greedy52 authored Jan 22, 2025
1 parent 3c9354d commit 00bfcac
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 1 deletion.
4 changes: 4 additions & 0 deletions api/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,10 @@ const (
// TraitHostUserGID is the name of the variable used to specify
// the GID to create host user account with.
TraitHostUserGID = "host_user_gid"

// TraitGitHubOrgs is the name of the variable to specify the GitHub
// organizations for GitHub integration.
TraitGitHubOrgs = "github_orgs"
)

const (
Expand Down
4 changes: 4 additions & 0 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,10 @@ const (
// TraitInternalJWTVariable is the variable used to store JWT token for
// app sessions.
TraitInternalJWTVariable = "{{internal.jwt}}"

// TraitInternalGitHubOrgs is the variable used to store allowed GitHub
// organizations for GitHub integrations.
TraitInternalGitHubOrgs = "{{internal.github_orgs}}"
)

// SCP is Secure Copy.
Expand Down
21 changes: 21 additions & 0 deletions lib/services/presets.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ func NewPresetEditorRole() types.Role {
types.NewRule(types.KindAutoUpdateVersion, RW()),
types.NewRule(types.KindAutoUpdateConfig, RW()),
types.NewRule(types.KindAutoUpdateAgentRollout, RO()),
types.NewRule(types.KindGitServer, RW()),
},
},
},
Expand Down Expand Up @@ -253,6 +254,9 @@ func NewPresetAccessRole() types.Role {
Verbs: []string{types.Wildcard},
},
},
GitHubPermissions: []types.GitHubPermission{{
Organizations: []string{teleport.TraitInternalGitHubOrgs},
}},
Rules: []types.Rule{
types.NewRule(types.KindEvent, RO()),
{
Expand Down Expand Up @@ -693,6 +697,7 @@ func NewPresetTerraformProviderRole() types.Role {
types.NewRule(types.KindDynamicWindowsDesktop, RW()),
types.NewRule(types.KindStaticHostUser, RW()),
types.NewRule(types.KindWorkloadIdentity, RW()),
types.NewRule(types.KindGitServer, RW()),
},
},
},
Expand Down Expand Up @@ -955,6 +960,16 @@ func AddRoleDefaults(ctx context.Context, role types.Role) (types.Role, error) {
}
}

// GitHub permissions.
if len(role.GetGitHubPermissions(types.Allow)) == 0 {
if githubOrgs := defaultGitHubOrgs()[role.GetName()]; len(githubOrgs) > 0 {
role.SetGitHubPermissions(types.Allow, []types.GitHubPermission{{
Organizations: githubOrgs,
}})
changed = true
}
}

if !changed {
return nil, trace.AlreadyExists("no change")
}
Expand Down Expand Up @@ -1066,3 +1081,9 @@ func updateAllowLabels(role types.Role, kind string, defaultLabels types.Labels)

return changed, nil
}

func defaultGitHubOrgs() map[string][]string {
return map[string][]string{
teleport.PresetAccessRoleName: []string{teleport.TraitInternalGitHubOrgs},
}
}
13 changes: 13 additions & 0 deletions lib/services/presets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ func TestAddRoleDefaults(t *testing.T) {
DatabaseServiceLabels: defaultAllowLabels(false)[teleport.PresetAccessRoleName].DatabaseServiceLabels,
DatabaseRoles: defaultAllowLabels(false)[teleport.PresetAccessRoleName].DatabaseRoles,
Rules: NewPresetAccessRole().GetRules(types.Allow),
GitHubPermissions: []types.GitHubPermission{{
Organizations: defaultGitHubOrgs()[teleport.PresetAccessRoleName],
}},
},
},
},
Expand Down Expand Up @@ -171,6 +174,9 @@ func TestAddRoleDefaults(t *testing.T) {
DatabaseServiceLabels: defaultAllowLabels(false)[teleport.PresetAccessRoleName].DatabaseServiceLabels,
DatabaseRoles: defaultAllowLabels(false)[teleport.PresetAccessRoleName].DatabaseRoles,
Rules: defaultAllowRules()[teleport.PresetAccessRoleName],
GitHubPermissions: []types.GitHubPermission{{
Organizations: defaultGitHubOrgs()[teleport.PresetAccessRoleName],
}},
},
},
},
Expand All @@ -186,6 +192,9 @@ func TestAddRoleDefaults(t *testing.T) {
DatabaseServiceLabels: defaultAllowLabels(false)[teleport.PresetAccessRoleName].DatabaseServiceLabels,
DatabaseRoles: defaultAllowLabels(false)[teleport.PresetAccessRoleName].DatabaseRoles,
Rules: defaultAllowRules()[teleport.PresetAccessRoleName],
GitHubPermissions: []types.GitHubPermission{{
Organizations: defaultGitHubOrgs()[teleport.PresetAccessRoleName],
}},
},
},
},
Expand All @@ -202,6 +211,9 @@ func TestAddRoleDefaults(t *testing.T) {
DatabaseServiceLabels: defaultAllowLabels(false)[teleport.PresetAccessRoleName].DatabaseServiceLabels,
DatabaseRoles: defaultAllowLabels(false)[teleport.PresetAccessRoleName].DatabaseRoles,
Rules: defaultAllowRules()[teleport.PresetAccessRoleName],
GitHubPermissions: []types.GitHubPermission{{
Organizations: defaultGitHubOrgs()[teleport.PresetAccessRoleName],
}},
},
},
},
Expand Down Expand Up @@ -735,6 +747,7 @@ func TestAddRoleDefaults(t *testing.T) {
types.NewRule(types.KindDynamicWindowsDesktop, RW()),
types.NewRule(types.KindStaticHostUser, RW()),
types.NewRule(types.KindWorkloadIdentity, RW()),
types.NewRule(types.KindGitServer, RW()),
},
},
},
Expand Down
9 changes: 8 additions & 1 deletion lib/services/role.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,12 @@ func ApplyTraits(r types.Role, traits map[string][]string) (types.Role, error) {
outDbRoles := applyValueTraitsSlice(inDbRoles, traits, "database role")
r.SetDatabaseRoles(condition, apiutils.Deduplicate(outDbRoles))

githubPermissions := r.GetGitHubPermissions(condition)
for i, perm := range githubPermissions {
githubPermissions[i].Organizations = applyValueTraitsSlice(perm.Organizations, traits, "github organizations")
}
r.SetGitHubPermissions(condition, githubPermissions)

var out []types.KubernetesResource
// we access the resources in the role using the role conditions
// to avoid receiving the compatibility resources added in GetKubernetesResources
Expand Down Expand Up @@ -677,7 +683,8 @@ func ApplyValueTraits(val string, traits map[string][]string) ([]string, error)
constants.TraitKubeGroups, constants.TraitKubeUsers,
constants.TraitDBNames, constants.TraitDBUsers, constants.TraitDBRoles,
constants.TraitAWSRoleARNs, constants.TraitAzureIdentities,
constants.TraitGCPServiceAccounts, constants.TraitJWT:
constants.TraitGCPServiceAccounts, constants.TraitJWT,
constants.TraitGitHubOrgs:
default:
return trace.BadParameter("unsupported variable %q", name)
}
Expand Down
33 changes: 33 additions & 0 deletions lib/services/role_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2960,6 +2960,8 @@ func TestApplyTraits(t *testing.T) {
inSudoers []string
outSudoers []string
outKubeResources []types.KubernetesResource
inGitHubPermissions []types.GitHubPermission
outGitHubPermissions []types.GitHubPermission
}
tests := []struct {
comment string
Expand Down Expand Up @@ -3728,6 +3730,34 @@ func TestApplyTraits(t *testing.T) {
},
},
},
{
comment: "GitHub permissions in allow rule",
inTraits: map[string][]string{
"github_orgs": {"my-org1", "my-org2"},
},
allow: rule{
inGitHubPermissions: []types.GitHubPermission{{
Organizations: []string{"{{internal.github_orgs}}"},
}},
outGitHubPermissions: []types.GitHubPermission{{
Organizations: []string{"my-org1", "my-org2"},
}},
},
},
{
comment: "GitHub permissions in deny rule",
inTraits: map[string][]string{
"orgs": {"my-org1", "my-org2"},
},
deny: rule{
inGitHubPermissions: []types.GitHubPermission{{
Organizations: []string{"{{external.orgs}}"},
}},
outGitHubPermissions: []types.GitHubPermission{{
Organizations: []string{"my-org1", "my-org2"},
}},
},
},
}
for _, tt := range tests {
t.Run(tt.comment, func(t *testing.T) {
Expand Down Expand Up @@ -3759,6 +3789,7 @@ func TestApplyTraits(t *testing.T) {
Impersonate: &tt.allow.inImpersonate,
HostSudoers: tt.allow.inSudoers,
KubernetesResources: tt.allow.inKubeResources,
GitHubPermissions: tt.allow.inGitHubPermissions,
},
Deny: types.RoleConditions{
Logins: tt.deny.inLogins,
Expand All @@ -3780,6 +3811,7 @@ func TestApplyTraits(t *testing.T) {
Impersonate: &tt.deny.inImpersonate,
HostSudoers: tt.deny.outSudoers,
KubernetesResources: tt.deny.inKubeResources,
GitHubPermissions: tt.deny.inGitHubPermissions,
},
},
}
Expand Down Expand Up @@ -3813,6 +3845,7 @@ func TestApplyTraits(t *testing.T) {
require.Equal(t, rule.spec.outImpersonate, outRole.GetImpersonateConditions(rule.condition))
require.Equal(t, rule.spec.outSudoers, outRole.GetHostSudoers(rule.condition))
require.Equal(t, rule.spec.outKubeResources, outRole.GetRoleConditions(rule.condition).KubernetesResources)
require.Equal(t, rule.spec.outGitHubPermissions, outRole.GetRoleConditions(rule.condition).GitHubPermissions)
}
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const traitsPreset = [
'kubernetes_users',
'logins',
'windows_logins',
'github_orgs',
];

/**
Expand Down

0 comments on commit 00bfcac

Please sign in to comment.