forked from ekristen/aws-nuke
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathiam-user.go
158 lines (129 loc) · 3.61 KB
/
iam-user.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package resources
import (
"context"
"time"
"github.com/sirupsen/logrus"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/service/iam/iamiface"
"github.com/ekristen/libnuke/pkg/registry"
"github.com/ekristen/libnuke/pkg/resource"
"github.com/ekristen/libnuke/pkg/types"
"github.com/ekristen/aws-nuke/v3/pkg/nuke"
)
const IAMUserResource = "IAMUser"
func init() {
registry.Register(®istry.Registration{
Name: IAMUserResource,
Scope: nuke.Account,
Lister: &IAMUserLister{},
DependsOn: []string{
IAMUserAccessKeyResource,
IAMUserHTTPSGitCredentialResource,
IAMUserGroupAttachmentResource,
IAMUserPolicyAttachmentResource,
IAMVirtualMFADeviceResource,
},
DeprecatedAliases: []string{
"IamUser", // TODO(v4): remove
},
})
}
type IAMUser struct {
svc iamiface.IAMAPI
Name *string
Path *string
UserID *string
CreateDate *time.Time
PasswordLastUsed *time.Time
Tags []*iam.Tag
HasPermissionBoundary bool
PermissionBoundaryARN *string
PermissionBoundaryType *string
}
func (r *IAMUser) Remove(_ context.Context) error {
if r.HasPermissionBoundary {
_, err := r.svc.DeleteUserPermissionsBoundary(&iam.DeleteUserPermissionsBoundaryInput{
UserName: r.Name,
})
if err != nil {
return err
}
}
_, err := r.svc.DeleteUser(&iam.DeleteUserInput{
UserName: r.Name,
})
if err != nil {
return err
}
return nil
}
func (r *IAMUser) String() string {
return *r.Name
}
func (r *IAMUser) Properties() types.Properties {
return types.NewPropertiesFromStruct(r)
}
// --------------
type IAMUserLister struct {
mockSvc iamiface.IAMAPI
}
func (l *IAMUserLister) List(_ context.Context, o interface{}) ([]resource.Resource, error) {
opts := o.(*nuke.ListerOpts)
var resources []resource.Resource
var svc iamiface.IAMAPI
if l.mockSvc != nil {
svc = l.mockSvc
} else {
svc = iam.New(opts.Session)
}
allUsers, err := ListIAMUsers(svc)
if err != nil {
return resources, err
}
for _, out := range allUsers {
// Note: we have to do a GetIAMUser because the listing of users does not include all the information we need
user, getErr := GetIAMUser(svc, out.UserName)
if getErr != nil {
logrus.Errorf("failed to get user %s: %v", *out.UserName, err)
continue
}
resourceUser := &IAMUser{
svc: svc,
Name: user.UserName,
Path: user.Path,
UserID: user.UserId,
CreateDate: user.CreateDate,
PasswordLastUsed: user.PasswordLastUsed,
Tags: user.Tags,
}
if user.PermissionsBoundary != nil && user.PermissionsBoundary.PermissionsBoundaryArn != nil {
resourceUser.HasPermissionBoundary = true
resourceUser.PermissionBoundaryARN = user.PermissionsBoundary.PermissionsBoundaryArn
resourceUser.PermissionBoundaryType = user.PermissionsBoundary.PermissionsBoundaryType
}
resources = append(resources, resourceUser)
}
return resources, nil
}
// --------------
// GetIAMUser retries and returns just the *iam.User from the response
func GetIAMUser(svc iamiface.IAMAPI, userName *string) (*iam.User, error) {
resp, err := svc.GetUser(&iam.GetUserInput{
UserName: userName,
})
if err != nil {
return nil, err
}
return resp.User, err
}
// ListIAMUsers retrieves a base list of users
func ListIAMUsers(svc iamiface.IAMAPI) ([]*iam.User, error) {
var users []*iam.User
if err := svc.ListUsersPages(nil, func(page *iam.ListUsersOutput, lastPage bool) bool {
users = append(users, page.Users...)
return true
}); err != nil {
return nil, err
}
return users, nil
}