Skip to content

Commit

Permalink
Merge pull request #318 from ekristen/iam-policy
Browse files Browse the repository at this point in the history
feat(iam-policy): add CreateDate property
  • Loading branch information
ekristen authored Sep 26, 2024
2 parents 9168df4 + a269870 commit 8b63225
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 94 deletions.
139 changes: 68 additions & 71 deletions resources/iam-policies.go → resources/iam-policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package resources

import (
"context"
"time"

"github.com/sirupsen/logrus"

Expand Down Expand Up @@ -34,27 +35,73 @@ func init() {
})
}

type IAMPolicyLister struct{}

func (l *IAMPolicyLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) {
opts := o.(*nuke.ListerOpts)

svc := iam.New(opts.Session)

params := &iam.ListPoliciesInput{
Scope: aws.String("Local"),
}

policies := make([]*iam.Policy, 0)

if err := svc.ListPoliciesPages(params,
func(page *iam.ListPoliciesOutput, lastPage bool) bool {
for _, listedPolicy := range page.Policies {
policy, err := GetIAMPolicy(svc, listedPolicy.Arn)
if err != nil {
logrus.Errorf("Failed to get listed policy %s: %v", *listedPolicy.PolicyName, err)
continue
}
policies = append(policies, policy)
}
return true
}); err != nil {
return nil, err
}

resources := make([]resource.Resource, 0)

for _, out := range policies {
resources = append(resources, &IAMPolicy{
svc: svc,
Name: out.PolicyName,
Path: out.Path,
ARN: out.Arn,
PolicyID: out.PolicyId,
CreateDate: out.CreateDate,
Tags: out.Tags,
})
}

return resources, nil
}

type IAMPolicy struct {
svc iamiface.IAMAPI
name string
policyID string
arn string
path string
tags []*iam.Tag
svc iamiface.IAMAPI
Name *string
PolicyID *string
ARN *string
Path *string
CreateDate *time.Time
Tags []*iam.Tag
}

func (e *IAMPolicy) Remove(_ context.Context) error {
resp, err := e.svc.ListPolicyVersions(&iam.ListPolicyVersionsInput{
PolicyArn: &e.arn,
func (r *IAMPolicy) Remove(_ context.Context) error {
resp, err := r.svc.ListPolicyVersions(&iam.ListPolicyVersionsInput{
PolicyArn: r.ARN,
})
if err != nil {
return err
}

for _, version := range resp.Versions {
if !*version.IsDefaultVersion {
_, err = e.svc.DeletePolicyVersion(&iam.DeletePolicyVersionInput{
PolicyArn: &e.arn,
_, err = r.svc.DeletePolicyVersion(&iam.DeletePolicyVersionInput{
PolicyArn: r.ARN,
VersionId: version.VersionId,
})
if err != nil {
Expand All @@ -63,8 +110,8 @@ func (e *IAMPolicy) Remove(_ context.Context) error {
}
}

_, err = e.svc.DeletePolicy(&iam.DeletePolicyInput{
PolicyArn: &e.arn,
_, err = r.svc.DeletePolicy(&iam.DeletePolicyInput{
PolicyArn: r.ARN,
})
if err != nil {
return err
Expand All @@ -73,73 +120,23 @@ func (e *IAMPolicy) Remove(_ context.Context) error {
return nil
}

func (e *IAMPolicy) Properties() types.Properties {
properties := types.NewProperties()

properties.Set("Name", e.name)
properties.Set("ARN", e.arn)
properties.Set("Path", e.path)
properties.Set("PolicyID", e.policyID)
for _, tag := range e.tags {
properties.SetTag(tag.Key, tag.Value)
}
return properties
func (r *IAMPolicy) Properties() types.Properties {
return types.NewPropertiesFromStruct(r)
}

func (e *IAMPolicy) String() string {
return e.arn
func (r *IAMPolicy) String() string {
return *r.ARN
}

// -------------

func GetIAMPolicy(svc *iam.IAM, policyArn *string) (*iam.Policy, error) {
params := &iam.GetPolicyInput{
resp, err := svc.GetPolicy(&iam.GetPolicyInput{
PolicyArn: policyArn,
}
resp, err := svc.GetPolicy(params)
return resp.Policy, err
}

type IAMPolicyLister struct{}

func (l *IAMPolicyLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) {
opts := o.(*nuke.ListerOpts)

svc := iam.New(opts.Session)

params := &iam.ListPoliciesInput{
Scope: aws.String("Local"),
}

policies := make([]*iam.Policy, 0)

if err := svc.ListPoliciesPages(params,
func(page *iam.ListPoliciesOutput, lastPage bool) bool {
for _, listedPolicy := range page.Policies {
policy, err := GetIAMPolicy(svc, listedPolicy.Arn)
if err != nil {
logrus.Errorf("Failed to get listed policy %s: %v", *listedPolicy.PolicyName, err)
continue
}
policies = append(policies, policy)
}
return true
}); err != nil {
})
if err != nil {
return nil, err
}

resources := make([]resource.Resource, 0)

for _, out := range policies {
resources = append(resources, &IAMPolicy{
svc: svc,
name: *out.PolicyName,
path: *out.Path,
arn: *out.Arn,
policyID: *out.PolicyId,
tags: out.Tags,
})
}

return resources, nil
return resp.Policy, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package resources
import (
"context"
"testing"
"time"

"github.com/golang/mock/gomock"
"github.com/gotidy/ptr"
"github.com/stretchr/testify/assert"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/iam"

"github.com/ekristen/aws-nuke/v3/mocks/mock_iamiface"
Expand All @@ -22,24 +23,24 @@ func Test_Mock_IAMPolicy_Remove(t *testing.T) {

iamPolicy := IAMPolicy{
svc: mockIAM,
name: "foobar",
policyID: "foobar",
arn: "foobar",
Name: ptr.String("foobar"),
PolicyID: ptr.String("foobar"),
ARN: ptr.String("foobar"),
}

mockIAM.EXPECT().ListPolicyVersions(gomock.Eq(&iam.ListPolicyVersionsInput{
PolicyArn: aws.String(iamPolicy.arn),
PolicyArn: iamPolicy.ARN,
})).Return(&iam.ListPolicyVersionsOutput{
Versions: []*iam.PolicyVersion{
{
IsDefaultVersion: aws.Bool(true),
VersionId: aws.String("v1"),
IsDefaultVersion: ptr.Bool(true),
VersionId: ptr.String("v1"),
},
},
}, nil)

mockIAM.EXPECT().DeletePolicy(gomock.Eq(&iam.DeletePolicyInput{
PolicyArn: aws.String(iamPolicy.arn),
PolicyArn: iamPolicy.ARN,
})).Return(&iam.DeletePolicyOutput{}, nil)

err := iamPolicy.Remove(context.TODO())
Expand All @@ -55,44 +56,72 @@ func Test_Mock_IAMPolicy_WithVersions_Remove(t *testing.T) {

iamPolicy := IAMPolicy{
svc: mockIAM,
name: "foobar",
policyID: "foobar",
arn: "foobar",
Name: ptr.String("foobar"),
PolicyID: ptr.String("foobar"),
ARN: ptr.String("foobar"),
}

mockIAM.EXPECT().ListPolicyVersions(gomock.Eq(&iam.ListPolicyVersionsInput{
PolicyArn: aws.String(iamPolicy.arn),
PolicyArn: iamPolicy.ARN,
})).Return(&iam.ListPolicyVersionsOutput{
Versions: []*iam.PolicyVersion{
{
IsDefaultVersion: aws.Bool(false),
VersionId: aws.String("v1"),
IsDefaultVersion: ptr.Bool(false),
VersionId: ptr.String("v1"),
},
{
IsDefaultVersion: aws.Bool(false),
VersionId: aws.String("v2"),
IsDefaultVersion: ptr.Bool(false),
VersionId: ptr.String("v2"),
},
{
IsDefaultVersion: aws.Bool(true),
VersionId: aws.String("v3"),
IsDefaultVersion: ptr.Bool(true),
VersionId: ptr.String("v3"),
},
},
}, nil)

mockIAM.EXPECT().DeletePolicyVersion(gomock.Eq(&iam.DeletePolicyVersionInput{
PolicyArn: aws.String(iamPolicy.arn),
VersionId: aws.String("v1"),
PolicyArn: iamPolicy.ARN,
VersionId: ptr.String("v1"),
})).Return(&iam.DeletePolicyVersionOutput{}, nil)

mockIAM.EXPECT().DeletePolicyVersion(gomock.Eq(&iam.DeletePolicyVersionInput{
PolicyArn: aws.String(iamPolicy.arn),
VersionId: aws.String("v2"),
PolicyArn: iamPolicy.ARN,
VersionId: ptr.String("v2"),
})).Return(&iam.DeletePolicyVersionOutput{}, nil)

mockIAM.EXPECT().DeletePolicy(gomock.Eq(&iam.DeletePolicyInput{
PolicyArn: aws.String(iamPolicy.arn),
PolicyArn: iamPolicy.ARN,
})).Return(&iam.DeletePolicyOutput{}, nil)

err := iamPolicy.Remove(context.TODO())
a.Nil(err)
}

func Test_Mock_IAMPolicy_Properties(t *testing.T) {
a := assert.New(t)

now := time.Now().UTC()

iamPolicy := IAMPolicy{
Name: ptr.String("foobar"),
PolicyID: ptr.String("foobar"),
ARN: ptr.String("arn:foobar"),
Path: ptr.String("/foobar"),
CreateDate: ptr.Time(now),
Tags: []*iam.Tag{
{
Key: ptr.String("foo"),
Value: ptr.String("bar"),
},
},
}

a.Equal("foobar", iamPolicy.Properties().Get("Name"))
a.Equal("foobar", iamPolicy.Properties().Get("PolicyID"))
a.Equal("arn:foobar", iamPolicy.Properties().Get("ARN"))
a.Equal("/foobar", iamPolicy.Properties().Get("Path"))
a.Equal("bar", iamPolicy.Properties().Get("tag:foo"))
a.Equal(now.Format(time.RFC3339), iamPolicy.Properties().Get("CreateDate"))
a.Equal("arn:foobar", iamPolicy.String())
}

0 comments on commit 8b63225

Please sign in to comment.