@@ -15,23 +15,26 @@ package group
15
15
16
16
import (
17
17
"context"
18
+ "net/url"
18
19
19
20
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
20
21
ackutil "github.com/aws-controllers-k8s/runtime/pkg/util"
21
22
svcsdk "github.com/aws/aws-sdk-go/service/iam"
23
+ "github.com/samber/lo"
22
24
)
23
25
24
- // syncPolicies examines the PolicyARNs in the supplied Group and calls the
25
- // ListGroupPolicies, AttachGroupPolicy and DetachGroupPolicy APIs to ensure
26
- // that the set of attached policies stays in sync with the Group.Spec.Policies
27
- // field, which is a list of strings containing Policy ARNs.
28
- func (rm * resourceManager ) syncPolicies (
26
+ // syncManagedPolicies examines the managed PolicyARNs in the supplied Group
27
+ // and calls the ListAttachedGroupPolicies, AttachGroupPolicy and
28
+ // DetachGroupPolicy APIs to ensure that the set of attached policies stays in
29
+ // sync with the Group.Spec.Policies field, which is a list of strings
30
+ // containing Policy ARNs.
31
+ func (rm * resourceManager ) syncManagedPolicies (
29
32
ctx context.Context ,
30
33
desired * resource ,
31
34
latest * resource ,
32
35
) (err error ) {
33
36
rlog := ackrtlog .FromContext (ctx )
34
- exit := rlog .Trace ("rm.syncPolicies " )
37
+ exit := rlog .Trace ("rm.syncManagedPolicies " )
35
38
defer func () { exit (err ) }()
36
39
toAdd := []* string {}
37
40
toDelete := []* string {}
@@ -51,29 +54,30 @@ func (rm *resourceManager) syncPolicies(
51
54
}
52
55
53
56
for _ , p := range toAdd {
54
- rlog .Debug ("adding policy to group" , "policy_arn" , * p )
55
- if err = rm .addPolicy (ctx , desired , p ); err != nil {
57
+ rlog .Debug ("adding managed policy to group" , "policy_arn" , * p )
58
+ if err = rm .addManagedPolicy (ctx , desired , p ); err != nil {
56
59
return err
57
60
}
58
61
}
59
62
for _ , p := range toDelete {
60
- rlog .Debug ("removing policy from group" , "policy_arn" , * p )
61
- if err = rm .removePolicy (ctx , desired , p ); err != nil {
63
+ rlog .Debug ("removing managed policy from group" , "policy_arn" , * p )
64
+ if err = rm .removeManagedPolicy (ctx , desired , p ); err != nil {
62
65
return err
63
66
}
64
67
}
65
68
66
69
return nil
67
70
}
68
71
69
- // getPolicies returns the list of Policy ARNs currently attached to the Group
70
- func (rm * resourceManager ) getPolicies (
72
+ // getManagedPolicies returns the list of managed Policy ARNs currently
73
+ // attached to the Group
74
+ func (rm * resourceManager ) getManagedPolicies (
71
75
ctx context.Context ,
72
76
r * resource ,
73
77
) ([]* string , error ) {
74
78
var err error
75
79
rlog := ackrtlog .FromContext (ctx )
76
- exit := rlog .Trace ("rm.getPolicies " )
80
+ exit := rlog .Trace ("rm.getManagedPolicies " )
77
81
defer func () { exit (err ) }()
78
82
79
83
input := & svcsdk.ListAttachedGroupPoliciesInput {}
@@ -95,14 +99,15 @@ func (rm *resourceManager) getPolicies(
95
99
return res , err
96
100
}
97
101
98
- // addPolicy adds the supplied Policy to the supplied Group resource
99
- func (rm * resourceManager ) addPolicy (
102
+ // addManagedPolicy adds the supplied managed Policy to the supplied Group
103
+ // resource
104
+ func (rm * resourceManager ) addManagedPolicy (
100
105
ctx context.Context ,
101
106
r * resource ,
102
107
policyARN * string ,
103
108
) (err error ) {
104
109
rlog := ackrtlog .FromContext (ctx )
105
- exit := rlog .Trace ("rm.addPolicy " )
110
+ exit := rlog .Trace ("rm.addManagedPolicy " )
106
111
defer func () { exit (err ) }()
107
112
108
113
input := & svcsdk.AttachGroupPolicyInput {}
@@ -113,14 +118,15 @@ func (rm *resourceManager) addPolicy(
113
118
return err
114
119
}
115
120
116
- // removePolicy removes the supplied Policy from the supplied Group resource
117
- func (rm * resourceManager ) removePolicy (
121
+ // removeManagedPolicy removes the supplied managed Policy from the supplied
122
+ // Group resource
123
+ func (rm * resourceManager ) removeManagedPolicy (
118
124
ctx context.Context ,
119
125
r * resource ,
120
126
policyARN * string ,
121
127
) (err error ) {
122
128
rlog := ackrtlog .FromContext (ctx )
123
- exit := rlog .Trace ("rm.removePolicy " )
129
+ exit := rlog .Trace ("rm.removeManagedPolicy " )
124
130
defer func () { exit (err ) }()
125
131
126
132
input := & svcsdk.DetachGroupPolicyInput {}
@@ -130,3 +136,156 @@ func (rm *resourceManager) removePolicy(
130
136
rm .metrics .RecordAPICall ("UPDATE" , "DetachGroupPolicy" , err )
131
137
return err
132
138
}
139
+
140
+ // syncInlinePolicies examines the InlinePolicies in the supplied Group and
141
+ // calls the ListGroupPolicies, PutGroupPolicy and DeleteGroupPolicy APIs to
142
+ // ensure that the set of attached policies stays in sync with the
143
+ // Group.Spec.InlinePolicies field, which is a map of policy names to policy
144
+ // documents.
145
+ func (rm * resourceManager ) syncInlinePolicies (
146
+ ctx context.Context ,
147
+ desired * resource ,
148
+ latest * resource ,
149
+ ) (err error ) {
150
+ rlog := ackrtlog .FromContext (ctx )
151
+ exit := rlog .Trace ("rm.syncInlinePolicies" )
152
+ defer func () { exit (err ) }()
153
+
154
+ existingPolicies := latest .ko .Spec .InlinePolicies
155
+
156
+ existingPairs := lo .ToPairs (existingPolicies )
157
+ desiredPairs := lo .ToPairs (desired .ko .Spec .InlinePolicies )
158
+
159
+ toDelete , toAdd := lo .Difference (existingPairs , desiredPairs )
160
+
161
+ for _ , pair := range toAdd {
162
+ polName := pair .Key
163
+ polDoc := pair .Value
164
+ rlog .Debug (
165
+ "adding inline policy to group" ,
166
+ "policy_name" , polName ,
167
+ )
168
+ err = rm .addInlinePolicy (ctx , desired , polName , polDoc )
169
+ if err != nil {
170
+ return err
171
+ }
172
+ }
173
+ for _ , pair := range toDelete {
174
+ polName := pair .Key
175
+ rlog .Debug (
176
+ "removing inline policy from group" ,
177
+ "policy_name" , polName ,
178
+ )
179
+ if err = rm .removeInlinePolicy (ctx , desired , polName ); err != nil {
180
+ return err
181
+ }
182
+ }
183
+
184
+ return nil
185
+ }
186
+
187
+ // getInlinePolicies returns a map of inline policy name and policy docs
188
+ // currently attached to the Group.
189
+ //
190
+ // NOTE(jaypipes): There's no way around the inefficiencies of this method
191
+ // without caching stuff, and I don't think it's useful to have an unbounded
192
+ // cache for these inline policy documents :( IAM's ListGroupPolicies API call
193
+ // only returns the *policy names* of inline policies. You need to call
194
+ // GetGroupPolicy API call for each inline policy name in order to get the
195
+ // policy document. Yes, they force an O(N) time complexity for this
196
+ // operation...
197
+ func (rm * resourceManager ) getInlinePolicies (
198
+ ctx context.Context ,
199
+ r * resource ,
200
+ ) (map [string ]* string , error ) {
201
+ var err error
202
+ rlog := ackrtlog .FromContext (ctx )
203
+ exit := rlog .Trace ("rm.getInlinePolicies" )
204
+ defer func () { exit (err ) }()
205
+
206
+ groupName := r .ko .Spec .Name
207
+
208
+ input := & svcsdk.ListGroupPoliciesInput {}
209
+ input .GroupName = groupName
210
+ res := map [string ]* string {}
211
+
212
+ err = rm .sdkapi .ListGroupPoliciesPagesWithContext (
213
+ ctx , input , func (page * svcsdk.ListGroupPoliciesOutput , _ bool ) bool {
214
+ if page == nil {
215
+ return true
216
+ }
217
+ for _ , p := range page .PolicyNames {
218
+ res [* p ] = nil
219
+ }
220
+ return page .IsTruncated != nil && * page .IsTruncated
221
+ },
222
+ )
223
+ rm .metrics .RecordAPICall ("READ_MANY" , "ListGroupPolicies" , err )
224
+
225
+ // Now we need to grab the policy documents for each policy name
226
+ for polName , _ := range res {
227
+ input := & svcsdk.GetGroupPolicyInput {}
228
+ input .GroupName = groupName
229
+ input .PolicyName = & polName
230
+ resp , err := rm .sdkapi .GetGroupPolicyWithContext (ctx , input )
231
+ rm .metrics .RecordAPICall ("READ_ONE" , "GetGroupPolicy" , err )
232
+ if err != nil {
233
+ return nil , err
234
+ }
235
+ cleanedDoc , err := decodeDocument (* resp .PolicyDocument )
236
+ if err != nil {
237
+ return nil , err
238
+ }
239
+ res [polName ] = & cleanedDoc
240
+
241
+ }
242
+ return res , nil
243
+ }
244
+
245
+ // addInlinePolicy adds the supplied inline Policy to the supplied Group
246
+ // resource
247
+ func (rm * resourceManager ) addInlinePolicy (
248
+ ctx context.Context ,
249
+ r * resource ,
250
+ policyName string ,
251
+ policyDoc * string ,
252
+ ) (err error ) {
253
+ rlog := ackrtlog .FromContext (ctx )
254
+ exit := rlog .Trace ("rm.addInlinePolicy" )
255
+ defer func () { exit (err ) }()
256
+
257
+ input := & svcsdk.PutGroupPolicyInput {}
258
+ input .GroupName = r .ko .Spec .Name
259
+ input .PolicyName = & policyName
260
+ cleanedDoc , err := decodeDocument (* policyDoc )
261
+ if err != nil {
262
+ return err
263
+ }
264
+ input .PolicyDocument = & cleanedDoc
265
+ _ , err = rm .sdkapi .PutGroupPolicyWithContext (ctx , input )
266
+ rm .metrics .RecordAPICall ("UPDATE" , "PutGroupPolicy" , err )
267
+ return err
268
+ }
269
+
270
+ // removeInlinePolicy removes the supplied inline Policy from the supplied
271
+ // Group resource
272
+ func (rm * resourceManager ) removeInlinePolicy (
273
+ ctx context.Context ,
274
+ r * resource ,
275
+ policyName string ,
276
+ ) (err error ) {
277
+ rlog := ackrtlog .FromContext (ctx )
278
+ exit := rlog .Trace ("rm.removeInlinePolicy" )
279
+ defer func () { exit (err ) }()
280
+
281
+ input := & svcsdk.DeleteGroupPolicyInput {}
282
+ input .GroupName = r .ko .Spec .Name
283
+ input .PolicyName = & policyName
284
+ _ , err = rm .sdkapi .DeleteGroupPolicyWithContext (ctx , input )
285
+ rm .metrics .RecordAPICall ("UPDATE" , "DeleteGroupPolicy" , err )
286
+ return err
287
+ }
288
+
289
+ func decodeDocument (encoded string ) (string , error ) {
290
+ return url .QueryUnescape (encoded )
291
+ }
0 commit comments