Skip to content

Commit

Permalink
Rework CRTB,PRTB collection, add GRB migration logic
Browse files Browse the repository at this point in the history
  • Loading branch information
nflynt committed Aug 15, 2023
1 parent 14c5f72 commit b897e47
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 62 deletions.
31 changes: 23 additions & 8 deletions pkg/agent/clean/ad_unmigration/migrate.go
Expand Up @@ -28,6 +28,7 @@ const (
migrateTokensOperation = "migrate-ad-tokens"
migrateCrtbsOperation = "migrate-ad-crtbs"
migratePrtbsOperation = "migrate-ad-prtbs"
migrateGrbsOperation = "migrate-ad-grbs"
activeDirectoryPrefix = "activedirectory_user://"
localPrefix = "local://"
adGUIDMigrationLabel = "ad-guid-migration"
Expand All @@ -42,16 +43,21 @@ const (
)

type migrateUserWorkUnit struct {
distinguishedName string
guid string
originalUser *v3.User
duplicateUsers []*v3.User
guidCRTBs []v3.ClusterRoleTemplateBinding
distinguishedName string
guid string
originalUser *v3.User
duplicateUsers []*v3.User

activeDirectoryCRTBs []v3.ClusterRoleTemplateBinding
duplicateLocalCRTBs []v3.ClusterRoleTemplateBinding
guidPRTBs []v3.ProjectRoleTemplateBinding

activeDirectoryPRTBs []v3.ProjectRoleTemplateBinding
duplicateLocalPRTBs []v3.ProjectRoleTemplateBinding
guidTokens []v3.Token
duplicateLocalTokens []v3.Token

duplicateLocalGRBs []v3.GlobalRoleBinding

activeDirectoryTokens []v3.Token
duplicateLocalTokens []v3.Token
}

type missingUserWorkUnit struct {
Expand Down Expand Up @@ -152,6 +158,10 @@ func UnmigrateAdGUIDUsers(clientConfig *restclient.Config, dryRun bool, deleteMi
if err != nil {
return err
}
err = collectGRBs(&usersToMigrate, sc)
if err != nil {
return err
}

for _, user := range skippedUsers {
logrus.Errorf("[%v] unable to migrate user '%v' due to a connection failure; this user will be skipped", migrateAdUserOperation, user.originalUser.Name)
Expand Down Expand Up @@ -190,6 +200,11 @@ func UnmigrateAdGUIDUsers(clientConfig *restclient.Config, dryRun bool, deleteMi
logrus.Errorf("[%v] unable to migrate PRTBs for user '%v': %v", migrateAdUserOperation, userToMigrate.originalUser.Name, err)
continue
}
err = migrateGRBs(&userToMigrate, sc, dryRun)
if err != nil {
logrus.Errorf("[%v] unable to migrate GRBs for user '%v': %v", migrateAdUserOperation, userToMigrate.originalUser.Name, err)
continue
}
replaceGUIDPrincipalWithDn(userToMigrate.originalUser, userToMigrate.distinguishedName, userToMigrate.guid, dryRun)

if dryRun {
Expand Down
122 changes: 96 additions & 26 deletions pkg/agent/clean/ad_unmigration/rtbs.go
Expand Up @@ -9,6 +9,27 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// principalsToMigrate collects workunits whose resources we wish to migrate into two groups:
//
// adWorkUnitsByPrincipal - resources should be migrated to an ActiveDirectory principal with a Distinguished Name
// duplicateLocalWorkUnitsByPrincipal - resources should be migrated to the local ID of the original (kept) user
func principalsToMigrate(workunits *[]migrateUserWorkUnit) (adWorkUnitsByPrincipal map[string]int, duplicateLocalWorkUnitsByPrincipal map[string]int) {
// first build a map of guid-principalid -> work unit, which will make the following logic more efficient
adWorkUnitsByPrincipal = map[string]int{}
duplicateLocalWorkUnitsByPrincipal = map[string]int{}

for i, workunit := range *workunits {
adWorkUnitsByPrincipal[activeDirectoryPrefix+workunit.guid] = i
for j := range workunit.duplicateUsers {
duplicateLocalWorkUnitsByPrincipal[activeDirectoryPrefix+workunit.guid] = j
duplicateLocalWorkUnitsByPrincipal[activeDirectoryPrefix+workunit.distinguishedName] = j
duplicateLocalWorkUnitsByPrincipal[localPrefix+workunit.duplicateUsers[j].Name] = j
}
}

return adWorkUnitsByPrincipal, duplicateLocalWorkUnitsByPrincipal
}

func collectCRTBs(workunits *[]migrateUserWorkUnit, sc *config.ScaledContext) error {
crtbInterface := sc.Management.ClusterRoleTemplateBindings("")
crtbList, err := crtbInterface.List(metav1.ListOptions{})
Expand All @@ -17,25 +38,17 @@ func collectCRTBs(workunits *[]migrateUserWorkUnit, sc *config.ScaledContext) er
return err
}

// first build a map of guid-principalid -> work unit, which will make the following logic more efficient
originalGUIDWorkUnits := map[string]int{}
duplicateGUIDWorkUnits := map[string]int{}
for i, workunit := range *workunits {
originalGUIDWorkUnits[activeDirectoryPrefix+workunit.guid] = i
for j := range workunit.duplicateUsers {
duplicateGUIDWorkUnits[activeDirectoryPrefix+workunit.guid] = j
}
}
adWorkUnitsByPrincipal, duplicateLocalWorkUnitsByPrincipal := principalsToMigrate(workunits)

for _, crtb := range crtbList.Items {
if index, exists := originalGUIDWorkUnits[crtb.UserPrincipalName]; exists {
if index, exists := adWorkUnitsByPrincipal[crtb.UserPrincipalName]; exists {
if workUnitContainsName(&(*workunits)[index], crtb.UserName) {
(*workunits)[index].guidCRTBs = append((*workunits)[index].guidCRTBs, crtb)
(*workunits)[index].activeDirectoryCRTBs = append((*workunits)[index].activeDirectoryCRTBs, crtb)
} else {
logrus.Warnf("[%v] found CRTB for user with guid-based principal '%v' and name '%v', but no user object with that name matches the GUID or its associated DN. refusing to process",
identifyAdUserOperation, crtb.UserPrincipalName, crtb.UserName)
}
} else if index, exists = duplicateGUIDWorkUnits[crtb.UserPrincipalName]; exists {
} else if index, exists = duplicateLocalWorkUnitsByPrincipal[crtb.UserPrincipalName]; exists {
if workUnitContainsName(&(*workunits)[index], crtb.UserName) {
(*workunits)[index].duplicateLocalCRTBs = append((*workunits)[index].duplicateLocalCRTBs, crtb)
} else {
Expand All @@ -56,25 +69,17 @@ func collectPRTBs(workunits *[]migrateUserWorkUnit, sc *config.ScaledContext) er
return err
}

// first build a map of guid-principalid -> work unit, which will make the following logic more efficient
originalGUIDWorkUnits := map[string]int{}
duplicateGUIDWorkUnits := map[string]int{}
for i, workunit := range *workunits {
originalGUIDWorkUnits[activeDirectoryPrefix+workunit.guid] = i
for j := range workunit.duplicateUsers {
duplicateGUIDWorkUnits[activeDirectoryPrefix+workunit.guid] = j
}
}
adWorkUnitsByPrincipal, duplicateLocalWorkUnitsByPrincipal := principalsToMigrate(workunits)

for _, prtb := range prtbList.Items {
if index, exists := originalGUIDWorkUnits[prtb.UserPrincipalName]; exists {
if index, exists := adWorkUnitsByPrincipal[prtb.UserPrincipalName]; exists {
if workUnitContainsName(&(*workunits)[index], prtb.UserName) {
(*workunits)[index].guidPRTBs = append((*workunits)[index].guidPRTBs, prtb)
(*workunits)[index].activeDirectoryPRTBs = append((*workunits)[index].activeDirectoryPRTBs, prtb)
} else {
logrus.Warnf("[%v] found PRTB for user with guid-based principal '%v' and name '%v', but no user object with that name matches the GUID or its associated DN. refusing to process",
identifyAdUserOperation, prtb.UserPrincipalName, prtb.UserName)
}
} else if index, exists = duplicateGUIDWorkUnits[prtb.UserPrincipalName]; exists {
} else if index, exists = duplicateLocalWorkUnitsByPrincipal[prtb.UserPrincipalName]; exists {
if workUnitContainsName(&(*workunits)[index], prtb.UserName) {
(*workunits)[index].duplicateLocalPRTBs = append((*workunits)[index].duplicateLocalPRTBs, prtb)
} else {
Expand All @@ -87,11 +92,36 @@ func collectPRTBs(workunits *[]migrateUserWorkUnit, sc *config.ScaledContext) er
return nil
}

func collectGRBs(workunits *[]migrateUserWorkUnit, sc *config.ScaledContext) error {
grbInterface := sc.Management.GlobalRoleBindings("")
grbList, err := grbInterface.List(metav1.ListOptions{})
if err != nil {
logrus.Errorf("[%v] unable to fetch GRB objects: %v", migrateAdUserOperation, err)
return err
}

duplicateLocalWorkUnitsByName := map[string]int{}

for _, workunit := range *workunits {
for j := range workunit.duplicateUsers {
duplicateLocalWorkUnitsByName[workunit.duplicateUsers[j].Name] = j
}
}

for _, grb := range grbList.Items {
if index, exists := duplicateLocalWorkUnitsByName[grb.UserName]; exists {
(*workunits)[index].duplicateLocalGRBs = append((*workunits)[index].duplicateLocalGRBs, grb)
}
}

return nil
}

func migrateCRTBs(workunit *migrateUserWorkUnit, sc *config.ScaledContext, dryRun bool) error {
crtbInterface := sc.Management.ClusterRoleTemplateBindings("")
// First convert all GUID-based CRTBs to their equivalent Distinguished Name variants
dnPrincipalID := activeDirectoryPrefix + workunit.distinguishedName
for _, oldCrtb := range workunit.guidCRTBs {
for _, oldCrtb := range workunit.activeDirectoryCRTBs {
if dryRun {
logrus.Infof("[%v] DRY RUN: would migrate CRTB '%v' from GUID principal '%v' to DN principal '%v'. "+
"Additionally, an annotation, %v, would be added containing the principal being migrated from and"+
Expand Down Expand Up @@ -183,7 +213,7 @@ func migratePRTBs(workunit *migrateUserWorkUnit, sc *config.ScaledContext, dryRu
prtbInterface := sc.Management.ProjectRoleTemplateBindings("")
// First convert all GUID-based PRTBs to their equivalent Distinguished Name variants
dnPrincipalID := activeDirectoryPrefix + workunit.distinguishedName
for _, oldPrtb := range workunit.guidPRTBs {
for _, oldPrtb := range workunit.activeDirectoryPRTBs {
if dryRun {
logrus.Infof("[%v] DRY RUN: would migrate PRTB '%v' from GUID principal '%v' to DN principal '%v'. "+
"Additionally, an annotation, %v, would be added containing the principal being migrated from and"+
Expand Down Expand Up @@ -272,3 +302,43 @@ func migratePRTBs(workunit *migrateUserWorkUnit, sc *config.ScaledContext, dryRu
}
return nil
}

func migrateGRBs(workunit *migrateUserWorkUnit, sc *config.ScaledContext, dryRun bool) error {
grbInterface := sc.Management.GlobalRoleBindings("")

for _, oldGrb := range workunit.duplicateLocalGRBs {
if dryRun {
logrus.Infof("[%v] DRY RUN: would migrate GRB '%v' from duplicate local user '%v' to original user '%v'"+
"Additionally, labels %v and %v will be added. These contain the name of the previous GRB and indicate that this GRB has been migrated.",
migrateGrbsOperation, oldGrb.Name, oldGrb.UserName, workunit.originalUser.Name, migrationPreviousName, adGUIDMigrationLabel)
} else {
newLabels := oldGrb.Labels
if newLabels == nil {
newLabels = make(map[string]string)
}
newLabels[migrationPreviousName] = oldGrb.Name
newLabels[adGUIDMigrationLabel] = migratedLabelValue

newGrb := &v3.GlobalRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "",
GenerateName: "grb-",
Annotations: oldGrb.Annotations,
Labels: newLabels,
},
GlobalRoleName: oldGrb.GlobalRoleName,
GroupPrincipalName: oldGrb.GroupPrincipalName,
UserName: workunit.originalUser.Name,
}
_, err := grbInterface.Create(newGrb)
if err != nil {
return fmt.Errorf("[%v] unable to create new GRB: %w", migrateGrbsOperation, err)
}
err = sc.Management.GlobalRoleBindings("").Delete(oldGrb.Name, &metav1.DeleteOptions{})
if err != nil {
return fmt.Errorf("[%v] unable to delete GRB: %w", migrateGrbsOperation, err)
}
}
}
return nil
}
56 changes: 28 additions & 28 deletions pkg/agent/clean/ad_unmigration/tokens.go
Expand Up @@ -9,10 +9,37 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func collectTokens(workunits *[]migrateUserWorkUnit, sc *config.ScaledContext) error {
tokenInterface := sc.Management.Tokens("")
tokenList, err := tokenInterface.List(metav1.ListOptions{})
if err != nil {
logrus.Errorf("[%v] unable to fetch token objects: %v", migrateAdUserOperation, err)
return err
}

for i, workunit := range *workunits {
guidPrincipal := activeDirectoryPrefix + workunit.guid
for _, token := range tokenList.Items {
if guidPrincipal == token.UserPrincipal.Name || workunit.originalUser.Name == token.UserID {
workunit.activeDirectoryTokens = append(workunit.activeDirectoryTokens, token)
} else {
for _, duplicateLocalUser := range workunit.duplicateUsers {
if localPrincipalID(duplicateLocalUser) == token.UserPrincipal.Name {
workunit.duplicateLocalTokens = append(workunit.duplicateLocalTokens, token)
}
}
}
}
(*workunits)[i] = workunit
}

return nil
}

func migrateTokens(workunit *migrateUserWorkUnit, sc *config.ScaledContext, dryRun bool) error {
tokenInterface := sc.Management.Tokens("")
dnPrincipalID := activeDirectoryPrefix + workunit.distinguishedName
for _, userToken := range workunit.guidTokens {
for _, userToken := range workunit.activeDirectoryTokens {
if dryRun {
logrus.Infof("[%v] DRY RUN: would migrate token '%v' from GUID principal '%v' to DN principal '%v'. "+
"Additionally, it would add an annotation, %v, indicating the former principalID of this token "+
Expand Down Expand Up @@ -72,30 +99,3 @@ func migrateTokens(workunit *migrateUserWorkUnit, sc *config.ScaledContext, dryR
}
return nil
}

func collectTokens(workunits *[]migrateUserWorkUnit, sc *config.ScaledContext) error {
tokenInterface := sc.Management.Tokens("")
tokenList, err := tokenInterface.List(metav1.ListOptions{})
if err != nil {
logrus.Errorf("[%v] unable to fetch token objects: %v", migrateAdUserOperation, err)
return err
}

for i, workunit := range *workunits {
guidPrincipal := activeDirectoryPrefix + workunit.guid
for _, token := range tokenList.Items {
if guidPrincipal == token.UserPrincipal.Name || workunit.originalUser.Name == token.UserID {
workunit.guidTokens = append(workunit.guidTokens, token)
} else {
for _, duplicateLocalUser := range workunit.duplicateUsers {
if localPrincipalID(duplicateLocalUser) == token.UserPrincipal.Name {
workunit.duplicateLocalTokens = append(workunit.duplicateLocalTokens, token)
}
}
}
}
(*workunits)[i] = workunit
}

return nil
}

0 comments on commit b897e47

Please sign in to comment.