From a3bedc89be42e32e21bfca5a80a3df0cb67fa375 Mon Sep 17 00:00:00 2001 From: Nolan Brubaker Date: Fri, 6 Dec 2024 17:18:44 -0500 Subject: [PATCH] Attempt to clean up CF IAM users Periodic tests seemed to get into a failure loop because an IAM user with the same name already existed, which is not allowed. This then failed the entire CloudFoundation stack. Depite the stack claiming to have been rolled back, the next iteration would run into the same problem. This change includes IAM users in the list of resources we need to specifically delete in the case of a CloudFoundation failure, just in case they've leaked Signed-off-by: Nolan Brubaker --- test/e2e/shared/aws.go | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/test/e2e/shared/aws.go b/test/e2e/shared/aws.go index 31a6ac283a..92bf96d044 100644 --- a/test/e2e/shared/aws.go +++ b/test/e2e/shared/aws.go @@ -474,6 +474,7 @@ func deleteResourcesInCloudFormation(prov client.ConfigProvider, t *cfn_bootstra iamSvc := iam.New(prov) temp := *renderCustomCloudFormation(t) var ( + iamUsers []*cfn_iam.User iamRoles []*cfn_iam.Role instanceProfiles []*cfn_iam.InstanceProfile policies []*cfn_iam.ManagedPolicy @@ -484,6 +485,9 @@ func deleteResourcesInCloudFormation(prov client.ConfigProvider, t *cfn_bootstra // temp.Resources is a map. Traversing that directly results in undetermined order. for _, val := range temp.Resources { switch val.AWSCloudFormationType() { + case configservice.ResourceTypeAwsIamUser: + user := val.(*cfn_iam.User) + iamUsers = append(iamUsers, user) case configservice.ResourceTypeAwsIamRole: role := val.(*cfn_iam.Role) iamRoles = append(iamRoles, role) @@ -498,6 +502,19 @@ func deleteResourcesInCloudFormation(prov client.ConfigProvider, t *cfn_bootstra groups = append(groups, group) } } + for _, user := range iamUsers { + By(fmt.Sprintf("deleting the following user: %q", user.UserName)) + repeat := false + Eventually(func(gomega Gomega) bool { + err := DeleteUser(prov, user.UserName) + if err != nil && !repeat { + By(fmt.Sprintf("failed to delete user '%q'; reason: %+v", user.UserName, err)) + repeat = true + } + code, ok := awserrors.Code(err) + return err == nil || (ok && code == iam.ErrCodeNoSuchEntityException) + }, 5*time.Minute, 5*time.Second).Should(BeTrue(), fmt.Sprintf("Eventually failed deleting the user: %q", user.UserName)) + } for _, role := range iamRoles { By(fmt.Sprintf("deleting the following role: %s", role.RoleName)) repeat := false @@ -598,6 +615,28 @@ func detachAllPoliciesForRole(prov client.ConfigProvider, name string) error { return nil } +// DeleteUser deletes an IAM user in a best effort manner. +func DeleteUser(prov client.ConfigProvider, name string) error { + iamSvc := iam.New(prov) + + // if role does not exist, return. + _, err := iamSvc.GetUser(&iam.GetUserInput{UserName: aws.String(name)}) + if err != nil { + return err + } + + //if err := detachAllPoliciesForRole(prov, name); err != nil { + // return err + //} + + _, err = iamSvc.DeleteUser(&iam.DeleteUserInput{UserName: aws.String(name)}) + if err != nil { + return err + } + + return nil +} + // DeleteRole deletes roles in a best effort manner. func DeleteRole(prov client.ConfigProvider, name string) error { iamSvc := iam.New(prov)