From 36d5c75bc27faf9cc19df27b1de28af467de6b44 Mon Sep 17 00:00:00 2001 From: Katherine Lin Date: Tue, 13 Jul 2021 13:44:38 -0400 Subject: [PATCH 1/2] Add unassign account --- cmd/account/mgmt/account-unassign.go | 410 ++++++++++++++++++++ cmd/account/mgmt/account-unassign_test.go | 453 ++++++++++++++++++++++ cmd/account/mgmt/cmd.go | 1 + pkg/provider/aws/client.go | 75 +++- pkg/provider/aws/mock/client.go | 180 +++++++++ 5 files changed, 1112 insertions(+), 7 deletions(-) create mode 100644 cmd/account/mgmt/account-unassign.go create mode 100644 cmd/account/mgmt/account-unassign_test.go diff --git a/cmd/account/mgmt/account-unassign.go b/cmd/account/mgmt/account-unassign.go new file mode 100644 index 00000000..8e590df4 --- /dev/null +++ b/cmd/account/mgmt/account-unassign.go @@ -0,0 +1,410 @@ +package mgmt + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/organizations" + "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" + "github.com/openshift/osdctl/pkg/printer" + awsprovider "github.com/openshift/osdctl/pkg/provider/aws" + "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericclioptions" + cmdutil "k8s.io/kubectl/pkg/cmd/util" +) + +func newCmdAccountUnassign(streams genericclioptions.IOStreams, flags *genericclioptions.ConfigFlags) *cobra.Command { + ops := newAccountUnassignOptions(streams, flags) + accountUnassignCmd := &cobra.Command{ + Use: "unassign", + Short: "Unassign account to user", + DisableAutoGenTag: true, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.CheckErr(ops.complete(cmd, args)) + cmdutil.CheckErr(ops.run()) + }, + } + ops.printFlags.AddFlags(accountUnassignCmd) + accountUnassignCmd.Flags().StringVarP(&ops.payerAccount, "payer-account", "p", "", "Payer account type") + accountUnassignCmd.Flags().StringVarP(&ops.username, "username", "u", "", "LDAP username") + accountUnassignCmd.Flags().StringVarP(&ops.accountID, "account-id", "i", "", "Account ID") + + return accountUnassignCmd +} + +type accountUnassignOptions struct { + awsClient awsprovider.Client + username string + payerAccount string + accountID string + + flags *genericclioptions.ConfigFlags + printFlags *printer.PrintFlags + genericclioptions.IOStreams +} + +func newAccountUnassignOptions(streams genericclioptions.IOStreams, flags *genericclioptions.ConfigFlags) *accountUnassignOptions { + return &accountUnassignOptions{ + flags: flags, + printFlags: printer.NewPrintFlags(), + IOStreams: streams, + } +} + +func (o *accountUnassignOptions) complete(cmd *cobra.Command, _ []string) error { + if o.payerAccount == "" { + return cmdutil.UsageErrorf(cmd, "Payer account was not provided") + } + if o.username == "" && o.accountID == "" { + return cmdutil.UsageErrorf(cmd, "Please provide either an username or account ID") + } + return nil +} + +func (o *accountUnassignOptions) run() error { + + var ( + accountUsername string + accountIdList []string + destinationOU string + rootID string + ) + + // Instantiate Aws client + awsClient, err := awsprovider.NewAwsClient(o.payerAccount, "us-east-1", "") + if err != nil { + return err + } + + if o.payerAccount == "osd-staging-1" { + rootID = OSDStaging1RootID + destinationOU = OSDStaging1OuID + } else if o.payerAccount == "osd-staging-2" { + rootID = OSDStaging2RootID + destinationOU = OSDStaging2OuID + } else { + return fmt.Errorf("invalid payer account provided") + } + + o.awsClient = awsClient + + if o.accountID != "" { + + accountUsername, err = o.checkForHiveNameTag(o.accountID) + if err != nil { + return err + } + accountIdList = append(accountIdList, o.accountID) + + } + + if o.username != "" { + // Check that username is not a hive + if strings.HasPrefix(o.username, "hive") { + return ErrHiveNameProvided + } + + accountUsername = o.username + accountIdList, err = o.listAccountsFromUser(accountUsername) + if err != nil { + return err + } + } + + fmt.Printf("Are you sure you want to unassign account(s) [%v] from %s? [y/n] ", accountIdList, accountUsername) + reader := bufio.NewReader(os.Stdin) + + response, err := reader.ReadString('\n') + if err != nil { + return err + } + + response = strings.ToLower(response[0:1]) + if response != "y" { + os.Exit(0) + } + + // loop through accounts list and untag and move them back into root OU + for _, id := range accountIdList { + + err = o.untagAccount(id) + if err != nil { + return err + } + + err = o.moveAccount(id, rootID, destinationOU) + if err != nil { + return err + } + } + + // Delete login profile + err = o.deleteLoginProfile(accountUsername) + if err != nil { + return err + } + // Delete access keys + err = o.deleteAccessKeys(accountUsername) + if err != nil { + return err + } + // Delete signing certificates + err = o.deleteSigningCert(accountUsername) + if err != nil { + return err + } + // Delete policies + err = o.deletePolicies(accountUsername) + if err != nil { + return err + } + // Delete attached policies + err = o.deleteAttachedPolicies(accountUsername) + if err != nil { + return err + } + // Delete groups + err = o.deleteGroups(accountUsername) + if err != nil { + return err + } + // Delete user + err = o.deleteUser(accountUsername) + if err != nil { + return err + } + + return nil +} + +var ErrHiveNameProvided error = fmt.Errorf("hive-managed account provided, only developers account accepted") +var ErrAccountPartiallyTagged error = fmt.Errorf("account is only partially tagged") + +func (o *accountUnassignOptions) checkForHiveNameTag(id string) (string, error) { + + inputListTags := &organizations.ListTagsForResourceInput{ + ResourceId: &id, + } + tags, err := o.awsClient.ListTagsForResource(inputListTags) + if err != nil { + return "", err + } + + if len(tags.Tags) == 0 { + return "", ErrNoTagsOnAccount + } + + for _, t := range tags.Tags { + if *t.Key == "owner" && strings.HasPrefix(*t.Value, "hive") { + return "", ErrHiveNameProvided + } + if *t.Key == "owner" && !strings.HasPrefix(*t.Value, "hive") { + return *t.Value, nil + } + } + return "", ErrNoOwnerTag +} + +func (o *accountUnassignOptions) untagAccount(id string) error { + inputUntag := &organizations.UntagResourceInput{ + ResourceId: &id, + TagKeys: []*string{ + aws.String("owner"), + aws.String("claimed"), + }, + } + _, err := o.awsClient.UntagResource(inputUntag) + if err != nil { + return err + } + return nil +} + +func (o *accountUnassignOptions) moveAccount(id string, rootID string, destinationOU string) error { + inputMove := &organizations.MoveAccountInput{ + AccountId: aws.String(id), + DestinationParentId: aws.String(rootID), + SourceParentId: aws.String(destinationOU), + } + + _, err := o.awsClient.MoveAccount(inputMove) + if err != nil { + return err + } + return nil +} + +var ErrNoAccountsForUser error = fmt.Errorf("user has no aws accounts") + +func (o *accountUnassignOptions) listAccountsFromUser(user string) ([]string, error) { + + inputFilterTag := &resourcegroupstaggingapi.GetResourcesInput{ + TagFilters: []*resourcegroupstaggingapi.TagFilter{ + { + Key: aws.String("owner"), + Values: []*string{ + aws.String(user), + }, + }, + }, + } + accounts, err := o.awsClient.GetResources(inputFilterTag) + if err != nil { + return []string{}, err + } + + if len(accounts.ResourceTagMappingList) == 0 { + return []string{}, ErrNoAccountsForUser + } + + var accountIdList []string + // Get last 12 digits of ResourceARN and append it to account list + for _, a := range accounts.ResourceTagMappingList { + accountIdList = append(accountIdList, (*a.ResourceARN)[len(*a.ResourceARN)-12:]) + } + + return accountIdList, nil +} + +func (o *accountUnassignOptions) deleteLoginProfile(user string) error { + + inputDeleteLogin := &iam.DeleteLoginProfileInput{ + UserName: &user, + } + _, err := o.awsClient.DeleteLoginProfile(inputDeleteLogin) + if err != nil { + return err + } + return nil +} + +func (o *accountUnassignOptions) deleteAccessKeys(user string) error { + + inputListAccessKeys := &iam.ListAccessKeysInput{ + UserName: &user, + } + accessKeys, err := o.awsClient.ListAccessKeys(inputListAccessKeys) + if err != nil { + return err + } + + for _, m := range accessKeys.AccessKeyMetadata { + + inputDelKey := &iam.DeleteAccessKeyInput{ + AccessKeyId: m.AccessKeyId, + UserName: &user, + } + _, err = o.awsClient.DeleteAccessKey(inputDelKey) + if err != nil { + return err + } + } + return nil +} + +func (o *accountUnassignOptions) deleteSigningCert(user string) error { + + inputListCert := &iam.ListSigningCertificatesInput{ + UserName: &user, + } + cert, err := o.awsClient.ListSigningCertificates(inputListCert) + if err != nil { + return err + } + + for _, c := range cert.Certificates { + inputDelCert := &iam.DeleteSigningCertificateInput{ + CertificateId: c.CertificateId, + UserName: &user, + } + _, err = o.awsClient.DeleteSigningCertificate(inputDelCert) + if err != nil { + return err + } + } + return nil +} + +func (o *accountUnassignOptions) deletePolicies(user string) error { + inputListPolicies := &iam.ListUserPoliciesInput{ + UserName: &user, + } + policies, err := o.awsClient.ListUserPolicies(inputListPolicies) + if err != nil { + return err + } + + for _, p := range policies.PolicyNames { + inputDelPolicies := &iam.DeleteUserPolicyInput{ + PolicyName: p, + UserName: &user, + } + _, err = o.awsClient.DeleteUserPolicy(inputDelPolicies) + if err != nil { + return err + } + } + return nil +} + +func (o *accountUnassignOptions) deleteAttachedPolicies(user string) error { + inputListAttachedPol := &iam.ListAttachedUserPoliciesInput{ + UserName: &user, + } + attachedPol, err := o.awsClient.ListAttachedUserPolicies(inputListAttachedPol) + if err != nil { + return err + } + + for _, ap := range attachedPol.AttachedPolicies { + inputDetachPol := &iam.DetachUserPolicyInput{ + PolicyArn: ap.PolicyArn, + UserName: &user, + } + _, err = o.awsClient.DetachUserPolicy(inputDetachPol) + if err != nil { + return err + } + } + return nil +} + +func (o *accountUnassignOptions) deleteGroups(user string) error { + + inputListGroups := &iam.ListGroupsForUserInput{ + UserName: &user, + } + groups, err := o.awsClient.ListGroupsForUser(inputListGroups) + if err != nil { + return err + } + + for _, g := range groups.Groups { + inputRemoveFromGroup := &iam.RemoveUserFromGroupInput{ + GroupName: g.GroupName, + UserName: &user, + } + _, err = o.awsClient.RemoveUserFromGroup(inputRemoveFromGroup) + if err != nil { + return err + } + } + return nil +} + +func (o *accountUnassignOptions) deleteUser(user string) error { + inputDelUser := &iam.DeleteUserInput{ + UserName: &user, + } + _, err := o.awsClient.DeleteUser(inputDelUser) + if err != nil { + return err + } + + fmt.Printf("user %s successfully deleted", user) + return nil +} diff --git a/cmd/account/mgmt/account-unassign_test.go b/cmd/account/mgmt/account-unassign_test.go new file mode 100644 index 00000000..6f049ef0 --- /dev/null +++ b/cmd/account/mgmt/account-unassign_test.go @@ -0,0 +1,453 @@ +package mgmt + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/organizations" + + "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" + "github.com/golang/mock/gomock" + "github.com/openshift/osdctl/pkg/provider/aws/mock" + + "k8s.io/apimachinery/pkg/runtime" +) + +func TestCheckForHiveNameTage(t *testing.T) { + var genericAWSError error = fmt.Errorf("Generic AWS Error") + + testData := []struct { + name string + tags map[string]string + expectedUsername string + expectErr error + expectedAWSError error + }{ + { + name: "test for both tags present", + expectErr: nil, + expectedAWSError: nil, + tags: map[string]string{ + "owner": "tuser", + "claimed": "true", + }, + expectedUsername: "tuser", + }, + { + name: "test for hive name tag present", + expectErr: ErrHiveNameProvided, + expectedAWSError: nil, + tags: map[string]string{ + "owner": "hivesomething", + }, + expectedUsername: "", + }, + { + name: "test for no owner tag present", + expectErr: ErrNoOwnerTag, + expectedAWSError: nil, + tags: map[string]string{ + "claimed": "true", + "asldkjfa": "alskdjfaksjd", + }, + expectedUsername: "", + }, + { + name: "test for no tags present", + expectErr: ErrNoTagsOnAccount, + expectedAWSError: nil, + tags: map[string]string{}, + expectedUsername: "", + }, + { + name: "test for AWS error catching", + expectErr: genericAWSError, + expectedAWSError: genericAWSError, + tags: map[string]string{}, + expectedUsername: "", + }, + } + + for _, test := range testData { + t.Run(test.name, func(t *testing.T) { + mocks := setupDefaultMocks(t, []runtime.Object{}) + + mockAWSClient := mock.NewMockClient(mocks.mockCtrl) + accountID := "111111111111" + + awsOutput := &organizations.ListTagsForResourceOutput{} + if test.expectedAWSError == nil { + tags := []*organizations.Tag{} + for key, value := range test.tags { + tag := &organizations.Tag{ + Key: aws.String(key), + Value: aws.String(value), + } + tags = append(tags, tag) + } + awsOutput.Tags = tags + } + + mockAWSClient.EXPECT().ListTagsForResource(gomock.Any()).Return( + awsOutput, + test.expectedAWSError, + ) + + o := &accountUnassignOptions{} + o.awsClient = mockAWSClient + returnVal, err := o.checkForHiveNameTag(accountID) + if test.expectErr != err { + t.Errorf("expected error %s and got %s", test.expectErr, err) + } + if returnVal != test.expectedUsername { + t.Errorf("expected %s is %s", test.expectedUsername, returnVal) + } + }) + } +} + +func TestUnassignMoveAccount(t *testing.T) { + + mocks := setupDefaultMocks(t, []runtime.Object{}) + + mockAWSClient := mock.NewMockClient(mocks.mockCtrl) + + accountId := "111111111111" + destOu := "abc-vnjfdshs" + rootOu := "abc" + + awsOutputMove := &organizations.MoveAccountOutput{} + + mockAWSClient.EXPECT().MoveAccount(gomock.Any()).Return( + awsOutputMove, + nil, + ) + + o := &accountUnassignOptions{} + o.awsClient = mockAWSClient + err := o.moveAccount(accountId, rootOu, destOu) + if err != nil { + t.Errorf("failed to move account") + } +} + +func TestListAccountsFromUser(t *testing.T) { + + var genericAWSError error = fmt.Errorf("Generic AWS Error") + + testData := []struct { + name string + expectedAccountList []string + resources []string + expectErr error + expectedAWSError error + }{ + { + name: "test for resources present", + expectedAccountList: []string{"111111111111"}, + expectErr: nil, + expectedAWSError: nil, + resources: []string{"randomresourcearn"}, + }, + { + name: "test for no resources present", + expectedAccountList: nil, + expectErr: ErrNoAccountsForUser, + expectedAWSError: nil, + resources: []string{}, + }, + { + name: "test for AWS error catching", + expectedAccountList: nil, + expectErr: genericAWSError, + expectedAWSError: genericAWSError, + resources: []string{}, + }, + } + + for _, test := range testData { + t.Run(test.name, func(t *testing.T) { + mocks := setupDefaultMocks(t, []runtime.Object{}) + + mockAWSClient := mock.NewMockClient(mocks.mockCtrl) + + userName := "auser" + + awsOutput := &resourcegroupstaggingapi.GetResourcesOutput{} + if test.expectedAWSError == nil { + resources := []*resourcegroupstaggingapi.ResourceTagMapping{} + for _, r := range test.resources { + resource := &resourcegroupstaggingapi.ResourceTagMapping{ + ResourceARN: aws.String(r), + } + resources = append(resources, resource) + } + awsOutput.ResourceTagMappingList = resources + } + + mockAWSClient.EXPECT().GetResources(gomock.Any()).Return( + awsOutput, + test.expectedAWSError, + ) + + o := &accountUnassignOptions{} + o.awsClient = mockAWSClient + returnValue, err := o.listAccountsFromUser(userName) + if test.expectErr != err { + t.Errorf("expected error %s and got %s", test.expectErr, err) + } + if len(returnValue) != len(test.expectedAccountList) { + t.Errorf("expected length of accounts list is %s instead of %s", test.expectedAccountList, returnValue) + } + }) + } +} + +func TestDeleteProfile(t *testing.T) { + + mocks := setupDefaultMocks(t, []runtime.Object{}) + + mockAWSClient := mock.NewMockClient(mocks.mockCtrl) + userName := "randuser" + awsOutput := &iam.DeleteLoginProfileOutput{} + mockAWSClient.EXPECT().DeleteLoginProfile(gomock.Any()).Return( + awsOutput, + nil, + ) + + o := &accountUnassignOptions{} + o.awsClient = mockAWSClient + err := o.deleteLoginProfile(userName) + if err != nil { + t.Errorf("failed to delete login profile") + } +} + +func TestDeleteAccessKey(t *testing.T) { + + mocks := setupDefaultMocks(t, []runtime.Object{}) + + mockAWSClient := mock.NewMockClient(mocks.mockCtrl) + userName := "randuser" + + expectedAccessKeyID := aws.String("expectedAccessKeyID") + + mockAWSClient.EXPECT().ListAccessKeys(&iam.ListAccessKeysInput{UserName: &userName}).Return( + &iam.ListAccessKeysOutput{ + AccessKeyMetadata: []*iam.AccessKeyMetadata{ + { + AccessKeyId: expectedAccessKeyID, + }, + }, + }, + nil, + ) + mockAWSClient.EXPECT().DeleteAccessKey( + &iam.DeleteAccessKeyInput{ + AccessKeyId: expectedAccessKeyID, + UserName: &userName, + }).Return( + &iam.DeleteAccessKeyOutput{}, + nil, + ) + + o := &accountUnassignOptions{} + o.awsClient = mockAWSClient + err := o.deleteAccessKeys(userName) + if err != nil { + t.Errorf("failed to delete access keys") + } +} + +func TestDeleteSigningCert(t *testing.T) { + + mocks := setupDefaultMocks(t, []runtime.Object{}) + + mockAWSClient := mock.NewMockClient(mocks.mockCtrl) + userName := "randuser" + + expectedCertificateId := aws.String("expectedCertificateId") + + mockAWSClient.EXPECT().ListSigningCertificates(&iam.ListSigningCertificatesInput{UserName: &userName}).Return( + &iam.ListSigningCertificatesOutput{ + Certificates: []*iam.SigningCertificate{ + { + CertificateId: expectedCertificateId, + }, + }, + }, + nil, + ) + + mockAWSClient.EXPECT().DeleteSigningCertificate( + &iam.DeleteSigningCertificateInput{ + CertificateId: expectedCertificateId, + UserName: &userName, + }, + ).Return( + &iam.DeleteSigningCertificateOutput{}, + nil, + ) + o := &accountUnassignOptions{} + o.awsClient = mockAWSClient + err := o.deleteSigningCert(userName) + if err != nil { + t.Errorf("failed to delete signing certificates") + } +} + +func TestDeletePolicies(t *testing.T) { + + mocks := setupDefaultMocks(t, []runtime.Object{}) + + mockAWSClient := mock.NewMockClient(mocks.mockCtrl) + userName := "randuser" + + expectedPolicyName := "ExpectedPolicyName" + mockAWSClient.EXPECT().ListUserPolicies( + &iam.ListUserPoliciesInput{UserName: &userName}, + ).Return( + &iam.ListUserPoliciesOutput{ + PolicyNames: []*string{ + &expectedPolicyName, + }, + }, + nil, + ) + mockAWSClient.EXPECT().DeleteUserPolicy( + &iam.DeleteUserPolicyInput{ + UserName: &userName, + PolicyName: &expectedPolicyName, + }, + ).Return( + nil, nil, + ) + + o := &accountUnassignOptions{} + o.awsClient = mockAWSClient + err := o.deletePolicies(userName) + if err != nil { + t.Errorf("failed to delete user policies") + } +} + +func TestDeleteAttachedPolicies(t *testing.T) { + + mocks := setupDefaultMocks(t, []runtime.Object{}) + + mockAWSClient := mock.NewMockClient(mocks.mockCtrl) + userName := "randuser" + + expectedPolicyArn := "ExpectedPolicyArn" + mockAWSClient.EXPECT().ListAttachedUserPolicies( + &iam.ListAttachedUserPoliciesInput{UserName: &userName}, + ).Return( + &iam.ListAttachedUserPoliciesOutput{ + AttachedPolicies: []*iam.AttachedPolicy{ + { + PolicyArn: &expectedPolicyArn, + PolicyName: aws.String("ExpectedPolicyName"), + }, + }, + }, + nil, + ) + mockAWSClient.EXPECT().DetachUserPolicy( + &iam.DetachUserPolicyInput{ + UserName: &userName, + PolicyArn: &expectedPolicyArn, + }, + ).Return( + nil, nil, + ) + + o := &accountUnassignOptions{} + o.awsClient = mockAWSClient + err := o.deleteAttachedPolicies(userName) + if err != nil { + t.Errorf("failed to detach policies") + } +} + +func TestDeleteGroups(t *testing.T) { + + mocks := setupDefaultMocks(t, []runtime.Object{}) + + mockAWSClient := mock.NewMockClient(mocks.mockCtrl) + userName := "randuser" + + expectedGroupName := "expectedGroupName" + + mockAWSClient.EXPECT().ListGroupsForUser( + &iam.ListGroupsForUserInput{UserName: &userName}, + ).Return( + &iam.ListGroupsForUserOutput{ + Groups: []*iam.Group{ + { + GroupName: &expectedGroupName, + }, + }, + }, + nil, + ) + + mockAWSClient.EXPECT().RemoveUserFromGroup( + &iam.RemoveUserFromGroupInput{ + GroupName: &expectedGroupName, + UserName: &userName, + }, + ).Return( + nil, nil, + ) + + o := &accountUnassignOptions{} + o.awsClient = mockAWSClient + err := o.deleteGroups(userName) + if err != nil { + t.Errorf("failed to delete groups") + } +} + +func TestDeleteUser(t *testing.T) { + + mocks := setupDefaultMocks(t, []runtime.Object{}) + + mockAWSClient := mock.NewMockClient(mocks.mockCtrl) + userName := "randuser" + + awsOutput := &iam.DeleteUserOutput{} + mockAWSClient.EXPECT().DeleteUser(gomock.Any()).Return( + awsOutput, + nil, + ) + + o := &accountUnassignOptions{} + o.awsClient = mockAWSClient + err := o.deleteUser(userName) + if err != nil { + t.Errorf("failed to delete iam user") + } +} + +func TestUntagAccount(t *testing.T) { + + mocks := setupDefaultMocks(t, []runtime.Object{}) + + mockAWSClient := mock.NewMockClient(mocks.mockCtrl) + + accountId := "111111111111" + + mockAWSClient.EXPECT().UntagResource(gomock.Any()).Return( + &organizations.UntagResourceOutput{}, + nil, + ) + + o := &accountUnassignOptions{} + o.awsClient = mockAWSClient + err := o.untagAccount(accountId) + if err != nil { + t.Errorf("failed to untag aws account") + } +} diff --git a/cmd/account/mgmt/cmd.go b/cmd/account/mgmt/cmd.go index d9aea55d..861f18ef 100644 --- a/cmd/account/mgmt/cmd.go +++ b/cmd/account/mgmt/cmd.go @@ -17,6 +17,7 @@ func NewCmdMgmt(streams genericclioptions.IOStreams, flags *genericclioptions.Co mgmtCmd.AddCommand(newCmdAccountList(streams, flags)) mgmtCmd.AddCommand(newCmdAccountAssign(streams, flags)) + mgmtCmd.AddCommand(newCmdAccountUnassign(streams, flags)) return mgmtCmd } diff --git a/pkg/provider/aws/client.go b/pkg/provider/aws/client.go index d4b9fb1d..444947f3 100644 --- a/pkg/provider/aws/client.go +++ b/pkg/provider/aws/client.go @@ -66,6 +66,18 @@ type Client interface { AttachRolePolicy(*iam.AttachRolePolicyInput) (*iam.AttachRolePolicyOutput, error) DetachRolePolicy(*iam.DetachRolePolicyInput) (*iam.DetachRolePolicyOutput, error) ListAttachedRolePolicies(*iam.ListAttachedRolePoliciesInput) (*iam.ListAttachedRolePoliciesOutput, error) + DeleteLoginProfile(*iam.DeleteLoginProfileInput) (*iam.DeleteLoginProfileOutput, error) + ListSigningCertificates(*iam.ListSigningCertificatesInput) (*iam.ListSigningCertificatesOutput, error) + DeleteSigningCertificate(*iam.DeleteSigningCertificateInput) (*iam.DeleteSigningCertificateOutput, error) + ListUserPolicies(*iam.ListUserPoliciesInput) (*iam.ListUserPoliciesOutput, error) + DeleteUserPolicy(*iam.DeleteUserPolicyInput) (*iam.DeleteUserPolicyOutput, error) + ListAttachedUserPolicies(*iam.ListAttachedUserPoliciesInput) (*iam.ListAttachedUserPoliciesOutput, error) + DetachUserPolicy(*iam.DetachUserPolicyInput) (*iam.DetachUserPolicyOutput, error) + ListGroupsForUser(*iam.ListGroupsForUserInput) (*iam.ListGroupsForUserOutput, error) + RemoveUserFromGroup(*iam.RemoveUserFromGroupInput) (*iam.RemoveUserFromGroupOutput, error) + ListRoles(*iam.ListRolesInput) (*iam.ListRolesOutput, error) + DeleteRole(*iam.DeleteRoleInput) (*iam.DeleteRoleOutput, error) + DeleteUser(*iam.DeleteUserInput) (*iam.DeleteUserOutput, error) //ec2 DescribeInstances(*ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) @@ -247,6 +259,54 @@ func (c *AwsClient) ListAttachedRolePolicies(input *iam.ListAttachedRolePolicies return c.iamClient.ListAttachedRolePolicies(input) } +func (c *AwsClient) DeleteLoginProfile(input *iam.DeleteLoginProfileInput) (*iam.DeleteLoginProfileOutput, error) { + return c.iamClient.DeleteLoginProfile(input) +} + +func (c *AwsClient) ListSigningCertificates(input *iam.ListSigningCertificatesInput) (*iam.ListSigningCertificatesOutput, error) { + return c.iamClient.ListSigningCertificates(input) +} + +func (c *AwsClient) DeleteSigningCertificate(input *iam.DeleteSigningCertificateInput) (*iam.DeleteSigningCertificateOutput, error) { + return c.iamClient.DeleteSigningCertificate(input) +} + +func (c *AwsClient) ListUserPolicies(input *iam.ListUserPoliciesInput) (*iam.ListUserPoliciesOutput, error) { + return c.iamClient.ListUserPolicies(input) +} + +func (c *AwsClient) DeleteUserPolicy(input *iam.DeleteUserPolicyInput) (*iam.DeleteUserPolicyOutput, error) { + return c.iamClient.DeleteUserPolicy(input) +} + +func (c *AwsClient) ListAttachedUserPolicies(input *iam.ListAttachedUserPoliciesInput) (*iam.ListAttachedUserPoliciesOutput, error) { + return c.iamClient.ListAttachedUserPolicies(input) +} + +func (c *AwsClient) DetachUserPolicy(input *iam.DetachUserPolicyInput) (*iam.DetachUserPolicyOutput, error) { + return c.iamClient.DetachUserPolicy(input) +} + +func (c *AwsClient) ListGroupsForUser(input *iam.ListGroupsForUserInput) (*iam.ListGroupsForUserOutput, error) { + return c.iamClient.ListGroupsForUser(input) +} + +func (c *AwsClient) RemoveUserFromGroup(input *iam.RemoveUserFromGroupInput) (*iam.RemoveUserFromGroupOutput, error) { + return c.iamClient.RemoveUserFromGroup(input) +} + +func (c *AwsClient) ListRoles(input *iam.ListRolesInput) (*iam.ListRolesOutput, error) { + return c.iamClient.ListRoles(input) +} + +func (c *AwsClient) DeleteRole(input *iam.DeleteRoleInput) (*iam.DeleteRoleOutput, error) { + return c.iamClient.DeleteRole(input) +} + +func (c *AwsClient) DeleteUser(input *iam.DeleteUserInput) (*iam.DeleteUserOutput, error) { + return c.iamClient.DeleteUser(input) +} + func (c *AwsClient) ListAccounts(input *organizations.ListAccountsInput) (*organizations.ListAccountsOutput, error) { return c.orgClient.ListAccounts(input) } @@ -274,22 +334,23 @@ func (c *AwsClient) DescribeOrganizationalUnit(input *organizations.DescribeOrga func (c *AwsClient) TagResource(input *organizations.TagResourceInput) (*organizations.TagResourceOutput, error) { return c.orgClient.TagResource(input) } -func (c *AwsClient) ListTagsForResource(input *organizations.ListTagsForResourceInput) (*organizations.ListTagsForResourceOutput, error) { - return c.orgClient.ListTagsForResource(input) -} - -func (c *AwsClient) GetResources(input *resourcegroupstaggingapi.GetResourcesInput) (*resourcegroupstaggingapi.GetResourcesOutput, error) { - return c.resClient.GetResources(input) -} func (c *AwsClient) UntagResource(input *organizations.UntagResourceInput) (*organizations.UntagResourceOutput, error) { return c.orgClient.UntagResource(input) } +func (c *AwsClient) ListTagsForResource(input *organizations.ListTagsForResourceInput) (*organizations.ListTagsForResourceOutput, error) { + return c.orgClient.ListTagsForResource(input) +} + func (c *AwsClient) MoveAccount(input *organizations.MoveAccountInput) (*organizations.MoveAccountOutput, error) { return c.orgClient.MoveAccount(input) } +func (c *AwsClient) GetResources(input *resourcegroupstaggingapi.GetResourcesInput) (*resourcegroupstaggingapi.GetResourcesOutput, error) { + return c.resClient.GetResources(input) +} + func (c *AwsClient) GetCostAndUsage(input *costexplorer.GetCostAndUsageInput) (*costexplorer.GetCostAndUsageOutput, error) { return c.ceClient.GetCostAndUsage(input) } diff --git a/pkg/provider/aws/mock/client.go b/pkg/provider/aws/mock/client.go index d07ce2f1..7de44c90 100644 --- a/pkg/provider/aws/mock/client.go +++ b/pkg/provider/aws/mock/client.go @@ -325,6 +325,186 @@ func (mr *MockClientMockRecorder) ListAttachedRolePolicies(arg0 interface{}) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAttachedRolePolicies", reflect.TypeOf((*MockClient)(nil).ListAttachedRolePolicies), arg0) } +// DeleteLoginProfile mocks base method +func (m *MockClient) DeleteLoginProfile(arg0 *iam.DeleteLoginProfileInput) (*iam.DeleteLoginProfileOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteLoginProfile", arg0) + ret0, _ := ret[0].(*iam.DeleteLoginProfileOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteLoginProfile indicates an expected call of DeleteLoginProfile +func (mr *MockClientMockRecorder) DeleteLoginProfile(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteLoginProfile", reflect.TypeOf((*MockClient)(nil).DeleteLoginProfile), arg0) +} + +// ListSigningCertificates mocks base method +func (m *MockClient) ListSigningCertificates(arg0 *iam.ListSigningCertificatesInput) (*iam.ListSigningCertificatesOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListSigningCertificates", arg0) + ret0, _ := ret[0].(*iam.ListSigningCertificatesOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListSigningCertificates indicates an expected call of ListSigningCertificates +func (mr *MockClientMockRecorder) ListSigningCertificates(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSigningCertificates", reflect.TypeOf((*MockClient)(nil).ListSigningCertificates), arg0) +} + +// DeleteSigningCertificate mocks base method +func (m *MockClient) DeleteSigningCertificate(arg0 *iam.DeleteSigningCertificateInput) (*iam.DeleteSigningCertificateOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteSigningCertificate", arg0) + ret0, _ := ret[0].(*iam.DeleteSigningCertificateOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteSigningCertificate indicates an expected call of DeleteSigningCertificate +func (mr *MockClientMockRecorder) DeleteSigningCertificate(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSigningCertificate", reflect.TypeOf((*MockClient)(nil).DeleteSigningCertificate), arg0) +} + +// ListUserPolicies mocks base method +func (m *MockClient) ListUserPolicies(arg0 *iam.ListUserPoliciesInput) (*iam.ListUserPoliciesOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListUserPolicies", arg0) + ret0, _ := ret[0].(*iam.ListUserPoliciesOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListUserPolicies indicates an expected call of ListUserPolicies +func (mr *MockClientMockRecorder) ListUserPolicies(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListUserPolicies", reflect.TypeOf((*MockClient)(nil).ListUserPolicies), arg0) +} + +// DeleteUserPolicy mocks base method +func (m *MockClient) DeleteUserPolicy(arg0 *iam.DeleteUserPolicyInput) (*iam.DeleteUserPolicyOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteUserPolicy", arg0) + ret0, _ := ret[0].(*iam.DeleteUserPolicyOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteUserPolicy indicates an expected call of DeleteUserPolicy +func (mr *MockClientMockRecorder) DeleteUserPolicy(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUserPolicy", reflect.TypeOf((*MockClient)(nil).DeleteUserPolicy), arg0) +} + +// ListAttachedUserPolicies mocks base method +func (m *MockClient) ListAttachedUserPolicies(arg0 *iam.ListAttachedUserPoliciesInput) (*iam.ListAttachedUserPoliciesOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListAttachedUserPolicies", arg0) + ret0, _ := ret[0].(*iam.ListAttachedUserPoliciesOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListAttachedUserPolicies indicates an expected call of ListAttachedUserPolicies +func (mr *MockClientMockRecorder) ListAttachedUserPolicies(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListAttachedUserPolicies", reflect.TypeOf((*MockClient)(nil).ListAttachedUserPolicies), arg0) +} + +// DetachUserPolicy mocks base method +func (m *MockClient) DetachUserPolicy(arg0 *iam.DetachUserPolicyInput) (*iam.DetachUserPolicyOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DetachUserPolicy", arg0) + ret0, _ := ret[0].(*iam.DetachUserPolicyOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DetachUserPolicy indicates an expected call of DetachUserPolicy +func (mr *MockClientMockRecorder) DetachUserPolicy(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DetachUserPolicy", reflect.TypeOf((*MockClient)(nil).DetachUserPolicy), arg0) +} + +// ListGroupsForUser mocks base method +func (m *MockClient) ListGroupsForUser(arg0 *iam.ListGroupsForUserInput) (*iam.ListGroupsForUserOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListGroupsForUser", arg0) + ret0, _ := ret[0].(*iam.ListGroupsForUserOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListGroupsForUser indicates an expected call of ListGroupsForUser +func (mr *MockClientMockRecorder) ListGroupsForUser(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListGroupsForUser", reflect.TypeOf((*MockClient)(nil).ListGroupsForUser), arg0) +} + +// RemoveUserFromGroup mocks base method +func (m *MockClient) RemoveUserFromGroup(arg0 *iam.RemoveUserFromGroupInput) (*iam.RemoveUserFromGroupOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveUserFromGroup", arg0) + ret0, _ := ret[0].(*iam.RemoveUserFromGroupOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RemoveUserFromGroup indicates an expected call of RemoveUserFromGroup +func (mr *MockClientMockRecorder) RemoveUserFromGroup(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveUserFromGroup", reflect.TypeOf((*MockClient)(nil).RemoveUserFromGroup), arg0) +} + +// ListRoles mocks base method +func (m *MockClient) ListRoles(arg0 *iam.ListRolesInput) (*iam.ListRolesOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListRoles", arg0) + ret0, _ := ret[0].(*iam.ListRolesOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListRoles indicates an expected call of ListRoles +func (mr *MockClientMockRecorder) ListRoles(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRoles", reflect.TypeOf((*MockClient)(nil).ListRoles), arg0) +} + +// DeleteRole mocks base method +func (m *MockClient) DeleteRole(arg0 *iam.DeleteRoleInput) (*iam.DeleteRoleOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteRole", arg0) + ret0, _ := ret[0].(*iam.DeleteRoleOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteRole indicates an expected call of DeleteRole +func (mr *MockClientMockRecorder) DeleteRole(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRole", reflect.TypeOf((*MockClient)(nil).DeleteRole), arg0) +} + +// DeleteUser mocks base method +func (m *MockClient) DeleteUser(arg0 *iam.DeleteUserInput) (*iam.DeleteUserOutput, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteUser", arg0) + ret0, _ := ret[0].(*iam.DeleteUserOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteUser indicates an expected call of DeleteUser +func (mr *MockClientMockRecorder) DeleteUser(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUser", reflect.TypeOf((*MockClient)(nil).DeleteUser), arg0) +} + // DescribeInstances mocks base method func (m *MockClient) DescribeInstances(arg0 *ec2.DescribeInstancesInput) (*ec2.DescribeInstancesOutput, error) { m.ctrl.T.Helper() From dd396082f9eb7088965a3f02ff6f7d2026a5d31b Mon Sep 17 00:00:00 2001 From: Katherine Lin Date: Thu, 12 Aug 2021 09:34:16 -0400 Subject: [PATCH 2/2] Add space for delete success msg --- cmd/account/mgmt/account-unassign.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/account/mgmt/account-unassign.go b/cmd/account/mgmt/account-unassign.go index 8e590df4..c3036744 100644 --- a/cmd/account/mgmt/account-unassign.go +++ b/cmd/account/mgmt/account-unassign.go @@ -405,6 +405,6 @@ func (o *accountUnassignOptions) deleteUser(user string) error { return err } - fmt.Printf("user %s successfully deleted", user) + fmt.Printf("user %s successfully deleted\n", user) return nil }