Skip to content

Commit

Permalink
GitHub proxy: role presets and user traits (#51299) (#51369)
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 06bde83 commit dd09b26
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
@@ -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 (
4 changes: 4 additions & 0 deletions constants.go
Original file line number Diff line number Diff line change
@@ -639,6 +639,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.
21 changes: 21 additions & 0 deletions lib/services/presets.go
Original file line number Diff line number Diff line change
@@ -195,6 +195,7 @@ func NewPresetEditorRole() types.Role {
types.NewRule(types.KindWorkloadIdentity, RW()),
types.NewRule(types.KindAutoUpdateVersion, RW()),
types.NewRule(types.KindAutoUpdateConfig, RW()),
types.NewRule(types.KindGitServer, RW()),
},
},
},
@@ -251,6 +252,9 @@ func NewPresetAccessRole() types.Role {
Verbs: []string{types.Wildcard},
},
},
GitHubPermissions: []types.GitHubPermission{{
Organizations: []string{teleport.TraitInternalGitHubOrgs},
}},
Rules: []types.Rule{
types.NewRule(types.KindEvent, RO()),
{
@@ -691,6 +695,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()),
},
},
},
@@ -950,6 +955,16 @@ func AddRoleDefaults(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")
}
@@ -1061,3 +1076,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
@@ -138,6 +138,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],
}},
},
},
},
@@ -170,6 +173,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],
}},
},
},
},
@@ -185,6 +191,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],
}},
},
},
},
@@ -201,6 +210,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],
}},
},
},
},
@@ -734,6 +746,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()),
},
},
},
9 changes: 8 additions & 1 deletion lib/services/role.go
Original file line number Diff line number Diff line change
@@ -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
@@ -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)
}
33 changes: 33 additions & 0 deletions lib/services/role_test.go
Original file line number Diff line number Diff line change
@@ -3007,6 +3007,8 @@ func TestApplyTraits(t *testing.T) {
inSudoers []string
outSudoers []string
outKubeResources []types.KubernetesResource
inGitHubPermissions []types.GitHubPermission
outGitHubPermissions []types.GitHubPermission
}
tests := []struct {
comment string
@@ -3775,6 +3777,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) {
@@ -3806,6 +3836,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,
@@ -3827,6 +3858,7 @@ func TestApplyTraits(t *testing.T) {
Impersonate: &tt.deny.inImpersonate,
HostSudoers: tt.deny.outSudoers,
KubernetesResources: tt.deny.inKubeResources,
GitHubPermissions: tt.deny.inGitHubPermissions,
},
},
}
@@ -3860,6 +3892,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)
}
})
}
Original file line number Diff line number Diff line change
@@ -42,6 +42,7 @@ const traitsPreset = [
'kubernetes_users',
'logins',
'windows_logins',
'github_orgs',
];

/**

0 comments on commit dd09b26

Please sign in to comment.