@@ -11,98 +11,153 @@ import (
11
11
iamv1beta1 "github.com/ihoegen/iam-role-manager/pkg/apis/iam/v1beta1"
12
12
)
13
13
14
+ // IAMClient provides an interface with interacting with AWS
15
+ type IAMClient struct {
16
+ Client * iam.IAM
17
+ Role * iamv1beta1.IAMRole
18
+ }
19
+
20
+ // NewIAMClient returns a new client for interacting with AWS IAM
21
+ func NewIAMClient (client * iam.IAM , role * iamv1beta1.IAMRole ) IAMClient {
22
+ return IAMClient {
23
+ Client : client ,
24
+ Role : role ,
25
+ }
26
+ }
27
+
14
28
//CreateIAMRole creates an IAM role in AWS, based on a spec
15
- func CreateIAMRole ( iamClient * iam. IAM , iamRole * iamv1beta1. IAMRole ) error {
16
- roleName := iamRole .ObjectMeta .GetName ()
17
- createRoleOutput , err := iamClient .CreateRole (& iam.CreateRoleInput {
18
- AssumeRolePolicyDocument : & iamRole .Spec .TrustRelationship ,
19
- Description : & iamRole .Spec .Description ,
20
- Path : & iamRole .Spec .Path ,
29
+ func ( i * IAMClient ) CreateIAMRole ( ) error {
30
+ roleName := i . Role .ObjectMeta .GetName ()
31
+ createRoleOutput , err := i . Client .CreateRole (& iam.CreateRoleInput {
32
+ AssumeRolePolicyDocument : & i . Role .Spec .TrustRelationship ,
33
+ Description : & i . Role .Spec .Description ,
34
+ Path : & i . Role .Spec .Path ,
21
35
RoleName : & roleName ,
22
- MaxSessionDuration : & iamRole .Spec .MaxSessionDuration ,
36
+ MaxSessionDuration : & i . Role .Spec .MaxSessionDuration ,
23
37
})
24
38
if err != nil {
25
39
return err
26
40
}
27
- iamRole .Status .ARN = * createRoleOutput .Role .Arn
28
- iamRole .Status .RoleID = * createRoleOutput .Role .RoleId
29
- err = createInlinePolicies (iamClient , iamRole )
41
+ i . Role .Status .ARN = * createRoleOutput .Role .Arn
42
+ i . Role .Status .RoleID = * createRoleOutput .Role .RoleId
43
+ err = i . createInlinePolicies ()
30
44
if err != nil {
31
45
return err
32
46
}
33
- err = attachPolicies (iamClient , iamRole )
47
+ err = i . attachPolicies ()
34
48
if err != nil {
35
49
return err
36
50
}
37
51
return nil
38
52
}
39
53
40
- //DeleteIAMRole deletes an IAM role with a matching name
41
- func DeleteIAMRole (iamClient * iam.IAM , iamRole * iamv1beta1.IAMRole ) error {
42
- var errors []error
43
- roleName := iamRole .ObjectMeta .GetName ()
44
- err := removeInlinePolicies (iamClient , iamRole )
45
- attachedPolicies , err := iamClient .ListAttachedRolePolicies (& iam.ListAttachedRolePoliciesInput {
46
- RoleName : & roleName ,
47
- })
54
+ //DeleteIAMRole deletes an IAM role
55
+ func (i * IAMClient ) DeleteIAMRole () error {
56
+ roleName := i .Role .ObjectMeta .GetName ()
57
+ currentPolicies , err := i .listInlinePolicies (roleName )
48
58
if err != nil {
49
59
return err
50
60
}
51
- for _ , policy := range attachedPolicies .AttachedPolicies {
52
- _ , err = iamClient .DetachRolePolicy (& iam.DetachRolePolicyInput {
61
+ for _ , policy := range currentPolicies {
62
+ _ , err = i .Client .DeleteRolePolicy (& iam.DeleteRolePolicyInput {
63
+ PolicyName : & policy ,
64
+ RoleName : & roleName ,
65
+ })
66
+ if err != nil {
67
+ return err
68
+ }
69
+ }
70
+ attachedPolicies , err := i .listAttachedPolicies (roleName )
71
+ if err != nil {
72
+ return err
73
+ }
74
+ for _ , policy := range attachedPolicies {
75
+ _ , err = i .Client .DetachRolePolicy (& iam.DetachRolePolicyInput {
53
76
PolicyArn : policy .PolicyArn ,
54
77
RoleName : & roleName ,
55
78
})
56
79
if err != nil {
57
- errors = append ( errors , err )
80
+ return err
58
81
}
59
82
}
60
- _ , err = iamClient .DeleteRole (& iam.DeleteRoleInput {
83
+ _ , err = i . Client .DeleteRole (& iam.DeleteRoleInput {
61
84
RoleName : & roleName ,
62
85
})
63
- if len (errors ) > 0 {
64
- return fmt .Errorf ("Errors occurred while detaching policies: %v" , errors )
65
- }
66
86
return err
67
87
}
68
88
69
89
//SyncIAMRole synchronizes an AWS IAM Role to a spec
70
- func SyncIAMRole ( iamClient * iam. IAM , iamRole * iamv1beta1. IAMRole ) error {
90
+ func ( i * IAMClient ) SyncIAMRole ( ) error {
71
91
var errors []error
72
- roleName := iamRole .ObjectMeta .GetName ()
73
- _ , err := iamClient .UpdateRole (& iam.UpdateRoleInput {
74
- Description : & iamRole .Spec .Description ,
75
- MaxSessionDuration : & iamRole .Spec .MaxSessionDuration ,
76
- RoleName : & roleName ,
92
+ roleName := i .Role .ObjectMeta .GetName ()
93
+ getRoleOutput , err := i .Client .GetRole (& iam.GetRoleInput {
94
+ RoleName : & roleName ,
77
95
})
78
96
if err != nil {
79
97
return err
80
98
}
81
- _ , err = iamClient .UpdateAssumeRolePolicy (& iam.UpdateAssumeRolePolicyInput {
82
- RoleName : & roleName ,
83
- PolicyDocument : & iamRole .Spec .TrustRelationship ,
84
- })
85
- err = removeInlinePolicies (iamClient , iamRole )
99
+ awsRole := * getRoleOutput .Role
100
+ if * awsRole .Description != i .Role .Spec .Description {
101
+ _ , err = i .Client .UpdateRoleDescription (& iam.UpdateRoleDescriptionInput {
102
+ Description : & i .Role .Spec .Description ,
103
+ RoleName : & roleName ,
104
+ })
105
+ if err != nil {
106
+ return err
107
+ }
108
+ }
109
+ if * awsRole .MaxSessionDuration != i .Role .Spec .MaxSessionDuration {
110
+ _ , err = i .Client .UpdateRole (& iam.UpdateRoleInput {
111
+ RoleName : & roleName ,
112
+ MaxSessionDuration : & i .Role .Spec .MaxSessionDuration ,
113
+ })
114
+ if err != nil {
115
+ return err
116
+ }
117
+ }
118
+ if * awsRole .AssumeRolePolicyDocument != i .Role .Spec .TrustRelationship {
119
+ _ , err = i .Client .UpdateAssumeRolePolicy (& iam.UpdateAssumeRolePolicyInput {
120
+ RoleName : & roleName ,
121
+ PolicyDocument : & i .Role .Spec .TrustRelationship ,
122
+ })
123
+ if err != nil {
124
+ return err
125
+ }
126
+ }
127
+ err = i .createInlinePolicies ()
86
128
if err != nil {
87
129
return err
88
130
}
89
- err = createInlinePolicies ( iamClient , iamRole )
131
+ inlinePolicies , err := i . listInlinePolicies ( roleName )
90
132
if err != nil {
91
133
return err
92
134
}
93
- err = attachPolicies (iamClient , iamRole )
135
+ var requestedInlinePolicies []string
136
+ for _ , p := range i .Role .Spec .InlinePolicy {
137
+ requestedInlinePolicies = append (requestedInlinePolicies , p .Name )
138
+ }
139
+ for _ , policy := range inlinePolicies {
140
+ if ! in (requestedInlinePolicies , policy ) {
141
+ _ , err = i .Client .DeleteRolePolicy (& iam.DeleteRolePolicyInput {
142
+ PolicyName : & policy ,
143
+ RoleName : & roleName ,
144
+ })
145
+ if err != nil {
146
+ errors = append (errors , err )
147
+ }
148
+ }
149
+ }
150
+ err = i .attachPolicies ()
94
151
if err != nil {
95
152
errors = append (errors , err )
96
153
}
97
- attachedPolicies , err := iamClient .ListAttachedRolePolicies (& iam.ListAttachedRolePoliciesInput {
98
- RoleName : & roleName ,
99
- })
154
+ attachedPolicies , err := i .listAttachedPolicies (roleName )
100
155
if err != nil {
101
156
return err
102
157
}
103
- for _ , policy := range attachedPolicies . AttachedPolicies {
104
- if ! in (iamRole . Spec .Policies , * policy .PolicyArn ) && ! in (iamRole .Spec .Policies , * policy .PolicyName ) {
105
- _ , err = iamClient .DetachRolePolicy (& iam.DetachRolePolicyInput {
158
+ for _ , policy := range attachedPolicies {
159
+ if ! in (i . Role . Spec .Policies , * policy .PolicyArn ) && ! in (i . Role .Spec .Policies , * policy .PolicyName ) {
160
+ _ , err = i . Client .DetachRolePolicy (& iam.DetachRolePolicyInput {
106
161
PolicyArn : policy .PolicyArn ,
107
162
RoleName : & roleName ,
108
163
})
@@ -117,25 +172,24 @@ func SyncIAMRole(iamClient *iam.IAM, iamRole *iamv1beta1.IAMRole) error {
117
172
return nil
118
173
}
119
174
120
- // Checks to see if a named IAM Role exists in AWS
121
- // TODO: Enhance the logic
122
- func iamRoleExists (iamClient * iam.IAM , roleName string ) bool {
123
- _ , err := iamClient .GetRole (& iam.GetRoleInput {
175
+ // IAMRoleExists Checks to see if a named IAM Role exists in AWS
176
+ func (i * IAMClient ) IAMRoleExists (roleName string ) bool {
177
+ _ , err := i .Client .GetRole (& iam.GetRoleInput {
124
178
RoleName : & roleName ,
125
179
})
126
180
return err == nil
127
181
}
128
182
129
183
// Attaches policies found in the spec to a named IAM role
130
- func attachPolicies ( iamClient * iam. IAM , iamRole * iamv1beta1. IAMRole ) error {
131
- roleName := iamRole .ObjectMeta .GetName ()
184
+ func ( i * IAMClient ) attachPolicies ( ) error {
185
+ roleName := i . Role .ObjectMeta .GetName ()
132
186
var errors []error
133
- for _ , policy := range iamRole .Spec .Policies {
187
+ for _ , policy := range i . Role .Spec .Policies {
134
188
policyArn , err := getArn (policy )
135
189
if err != nil {
136
190
return err
137
191
}
138
- _ , err = iamClient .AttachRolePolicy (& iam.AttachRolePolicyInput {
192
+ _ , err = i . Client .AttachRolePolicy (& iam.AttachRolePolicyInput {
139
193
PolicyArn : & policyArn ,
140
194
RoleName : & roleName ,
141
195
})
@@ -150,11 +204,11 @@ func attachPolicies(iamClient *iam.IAM, iamRole *iamv1beta1.IAMRole) error {
150
204
}
151
205
152
206
// Creates inline polices defined in a spec and attaches it to a role
153
- func createInlinePolicies ( iamClient * iam. IAM , iamRole * iamv1beta1. IAMRole ) error {
207
+ func ( i * IAMClient ) createInlinePolicies ( ) error {
154
208
var errors []error
155
- roleName := iamRole .ObjectMeta .GetName ()
156
- for _ , inlinePolicy := range iamRole .Spec .InlinePolicy {
157
- _ , err := iamClient .PutRolePolicy (& iam.PutRolePolicyInput {
209
+ roleName := i . Role .ObjectMeta .GetName ()
210
+ for _ , inlinePolicy := range i . Role .Spec .InlinePolicy {
211
+ _ , err := i . Client .PutRolePolicy (& iam.PutRolePolicyInput {
158
212
PolicyDocument : & inlinePolicy .Value ,
159
213
RoleName : & roleName ,
160
214
PolicyName : & inlinePolicy .Name ,
@@ -169,31 +223,6 @@ func createInlinePolicies(iamClient *iam.IAM, iamRole *iamv1beta1.IAMRole) error
169
223
return nil
170
224
}
171
225
172
- // Removes inline policies from a role
173
- func removeInlinePolicies (iamClient * iam.IAM , iamRole * iamv1beta1.IAMRole ) error {
174
- var errors []error
175
- roleName := iamRole .ObjectMeta .GetName ()
176
- currentPolicies , err := iamClient .ListRolePolicies (& iam.ListRolePoliciesInput {
177
- RoleName : & roleName ,
178
- })
179
- if err != nil {
180
- return err
181
- }
182
- for _ , policy := range currentPolicies .PolicyNames {
183
- _ , err = iamClient .DeleteRolePolicy (& iam.DeleteRolePolicyInput {
184
- PolicyName : policy ,
185
- RoleName : & roleName ,
186
- })
187
- if err != nil {
188
- errors = append (errors , err )
189
- }
190
- }
191
- if len (errors ) > 0 {
192
- return fmt .Errorf ("Errors occurred while attaching policies: %v" , errors )
193
- }
194
- return nil
195
- }
196
-
197
226
// Returns the ARN of a policy; allows for simply naming policies
198
227
func getArn (policyName string ) (string , error ) {
199
228
if isArn (policyName ) {
@@ -208,7 +237,54 @@ func getArn(policyName string) (string, error) {
208
237
}
209
238
210
239
// Returns if a policy string is an ARN
211
- // TODO: Enhance the logic
212
240
func isArn (policy string ) bool {
213
241
return strings .Contains (policy , "arn:aws:iam" )
214
242
}
243
+
244
+ // Paginate over inline policies
245
+ func (i * IAMClient ) listInlinePolicies (roleName string ) ([]string , error ) {
246
+ var policyNamesPointers []* string
247
+ isTruncated := true
248
+ marker := "1"
249
+ for isTruncated {
250
+ currentPolicies , err := i .Client .ListRolePolicies (& iam.ListRolePoliciesInput {
251
+ RoleName : & roleName ,
252
+ Marker : & marker ,
253
+ })
254
+ if err != nil {
255
+ return nil , err
256
+ }
257
+ policyNamesPointers = append (policyNamesPointers , currentPolicies .PolicyNames ... )
258
+ marker = * currentPolicies .Marker
259
+ isTruncated = * currentPolicies .IsTruncated
260
+ }
261
+ var policyNameValues []string
262
+ for _ , val := range policyNamesPointers {
263
+ policyNameValues = append (policyNameValues , * val )
264
+ }
265
+ return policyNameValues , nil
266
+ }
267
+
268
+ // Paginate over attached policies
269
+ func (i * IAMClient ) listAttachedPolicies (roleName string ) ([]iam.AttachedPolicy , error ) {
270
+ var policyPointers []* iam.AttachedPolicy
271
+ isTruncated := true
272
+ marker := "1"
273
+ for isTruncated {
274
+ currentPolicies , err := i .Client .ListAttachedRolePolicies (& iam.ListAttachedRolePoliciesInput {
275
+ RoleName : & roleName ,
276
+ Marker : & marker ,
277
+ })
278
+ if err != nil {
279
+ return nil , err
280
+ }
281
+ policyPointers = append (policyPointers , currentPolicies .AttachedPolicies ... )
282
+ marker = * currentPolicies .Marker
283
+ isTruncated = * currentPolicies .IsTruncated
284
+ }
285
+ var policyNameValues []iam.AttachedPolicy
286
+ for _ , val := range policyPointers {
287
+ policyNameValues = append (policyNameValues , * val )
288
+ }
289
+ return policyNameValues , nil
290
+ }
0 commit comments