Skip to content

Commit

Permalink
Delete aws iam user policies that are not attached.
Browse files Browse the repository at this point in the history
  • Loading branch information
genevieve committed Jan 6, 2020
1 parent acc62ad commit 34f9249
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 5 deletions.
22 changes: 22 additions & 0 deletions aws/iam/fakes/user_policies_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,18 @@ type UserPoliciesClient struct {
}
Stub func(*awsiam.ListAttachedUserPoliciesInput) (*awsiam.ListAttachedUserPoliciesOutput, error)
}
ListUserPoliciesCall struct {
sync.Mutex
CallCount int
Receives struct {
ListUserPoliciesInput *awsiam.ListUserPoliciesInput
}
Returns struct {
ListUserPoliciesOutput *awsiam.ListUserPoliciesOutput
Error error
}
Stub func(*awsiam.ListUserPoliciesInput) (*awsiam.ListUserPoliciesOutput, error)
}
}

func (f *UserPoliciesClient) DeleteUserPolicy(param1 *awsiam.DeleteUserPolicyInput) (*awsiam.DeleteUserPolicyOutput, error) {
Expand Down Expand Up @@ -75,3 +87,13 @@ func (f *UserPoliciesClient) ListAttachedUserPolicies(param1 *awsiam.ListAttache
}
return f.ListAttachedUserPoliciesCall.Returns.ListAttachedUserPoliciesOutput, f.ListAttachedUserPoliciesCall.Returns.Error
}
func (f *UserPoliciesClient) ListUserPolicies(param1 *awsiam.ListUserPoliciesInput) (*awsiam.ListUserPoliciesOutput, error) {
f.ListUserPoliciesCall.Lock()
defer f.ListUserPoliciesCall.Unlock()
f.ListUserPoliciesCall.CallCount++
f.ListUserPoliciesCall.Receives.ListUserPoliciesInput = param1
if f.ListUserPoliciesCall.Stub != nil {
return f.ListUserPoliciesCall.Stub(param1)
}
return f.ListUserPoliciesCall.Returns.ListUserPoliciesOutput, f.ListUserPoliciesCall.Returns.Error
}
30 changes: 27 additions & 3 deletions aws/iam/user_policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
//go:generate faux --interface userPoliciesClient --output fakes/user_policies_client.go
type userPoliciesClient interface {
ListAttachedUserPolicies(*awsiam.ListAttachedUserPoliciesInput) (*awsiam.ListAttachedUserPoliciesOutput, error)
ListUserPolicies(*awsiam.ListUserPoliciesInput) (*awsiam.ListUserPoliciesOutput, error)
DetachUserPolicy(*awsiam.DetachUserPolicyInput) (*awsiam.DetachUserPolicyOutput, error)
DeleteUserPolicy(*awsiam.DeleteUserPolicyInput) (*awsiam.DeleteUserPolicyOutput, error)
}
Expand All @@ -33,12 +34,12 @@ func NewUserPolicies(client userPoliciesClient, logger logger) UserPolicies {
}

func (o UserPolicies) Delete(userName string) error {
policies, err := o.client.ListAttachedUserPolicies(&awsiam.ListAttachedUserPoliciesInput{UserName: aws.String(userName)})
ap, err := o.client.ListAttachedUserPolicies(&awsiam.ListAttachedUserPoliciesInput{UserName: aws.String(userName)})
if err != nil {
return fmt.Errorf("List IAM User Policies: %s", err)
return fmt.Errorf("List Attached User Policies: %s", err)
}

for _, p := range policies.AttachedPolicies {
for _, p := range ap.AttachedPolicies {
n := *p.PolicyName

_, err = o.client.DetachUserPolicy(&awsiam.DetachUserPolicyInput{
Expand Down Expand Up @@ -70,5 +71,28 @@ func (o UserPolicies) Delete(userName string) error {
}
}

up, err := o.client.ListUserPolicies(&awsiam.ListUserPoliciesInput{UserName: aws.String(userName)})
if err != nil {
return fmt.Errorf("List User Policies: %s", err)
}

for _, p := range up.PolicyNames {
n := *p

_, err = o.client.DeleteUserPolicy(&awsiam.DeleteUserPolicyInput{
UserName: aws.String(userName),
PolicyName: p,
})
if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoSuchEntity" {
o.logger.Printf("[IAM User: %s] Deleted policy %s \n", userName, n)
} else {
o.logger.Printf("[IAM User: %s] Delete policy %s: %s \n", userName, n, err)
}
} else {
o.logger.Printf("[IAM User: %s] Deleted policy %s \n", userName, n)
}
}

return nil
}
52 changes: 50 additions & 2 deletions aws/iam/user_policies_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ var _ = Describe("UserPolicies", func() {
PolicyArn: aws.String("the-policy-arn"),
}},
}
client.ListUserPoliciesCall.Returns.ListUserPoliciesOutput = &awsiam.ListUserPoliciesOutput{
PolicyNames: []*string{},
}
})

It("detaches and deletes the policies", func() {
It("detaches attached policies and deletes them", func() {
err := policies.Delete("banana")
Expect(err).NotTo(HaveOccurred())

Expand All @@ -64,14 +67,43 @@ var _ = Describe("UserPolicies", func() {
}))
})

Context("when there are unattached user policies", func() {
BeforeEach(func() {
client.ListAttachedUserPoliciesCall.Returns.ListAttachedUserPoliciesOutput = &awsiam.ListAttachedUserPoliciesOutput{
AttachedPolicies: []*awsiam.AttachedPolicy{},
}
client.ListUserPoliciesCall.Returns.ListUserPoliciesOutput = &awsiam.ListUserPoliciesOutput{
PolicyNames: []*string{aws.String("the-other-policy")},
}
})

It("deletes them", func() {
err := policies.Delete("banana")
Expect(err).NotTo(HaveOccurred())

Expect(client.ListUserPoliciesCall.CallCount).To(Equal(1))
Expect(client.ListUserPoliciesCall.Receives.ListUserPoliciesInput.UserName).To(Equal(aws.String("banana")))

Expect(client.DetachUserPolicyCall.CallCount).To(Equal(0))

Expect(client.DeleteUserPolicyCall.CallCount).To(Equal(1))
Expect(client.DeleteUserPolicyCall.Receives.DeleteUserPolicyInput.UserName).To(Equal(aws.String("banana")))
Expect(client.DeleteUserPolicyCall.Receives.DeleteUserPolicyInput.PolicyName).To(Equal(aws.String("the-other-policy")))

Expect(messages).To(Equal([]string{
"[IAM User: banana] Deleted policy the-other-policy \n",
}))
})
})

Context("when the client fails to list attached user policies", func() {
BeforeEach(func() {
client.ListAttachedUserPoliciesCall.Returns.Error = errors.New("some error")
})

It("returns the error and does not try deleting them", func() {
err := policies.Delete("banana")
Expect(err).To(MatchError("List IAM User Policies: some error"))
Expect(err).To(MatchError("List Attached User Policies: some error"))

Expect(client.DetachUserPolicyCall.CallCount).To(Equal(0))
Expect(client.DeleteUserPolicyCall.CallCount).To(Equal(0))
Expand Down Expand Up @@ -145,5 +177,21 @@ var _ = Describe("UserPolicies", func() {
}))
})
})

Context("when the client fails to list user policies", func() {
BeforeEach(func() {
client.ListAttachedUserPoliciesCall.Returns.ListAttachedUserPoliciesOutput = &awsiam.ListAttachedUserPoliciesOutput{
AttachedPolicies: []*awsiam.AttachedPolicy{},
}
client.ListUserPoliciesCall.Returns.Error = errors.New("some error")
})

It("returns the error and does not try deleting them", func() {
err := policies.Delete("banana")
Expect(err).To(MatchError("List User Policies: some error"))

Expect(client.DeleteUserPolicyCall.CallCount).To(Equal(0))
})
})
})
})

0 comments on commit 34f9249

Please sign in to comment.