Skip to content

Commit 08748dc

Browse files
authored
Merge pull request #85 from a-hilaly/role-infinite-loop
Fix Role reconciliation logic for `AssumeRolePolicyDocument`
2 parents 4c6cfa9 + b94c178 commit 08748dc

File tree

8 files changed

+78
-16
lines changed

8 files changed

+78
-16
lines changed
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
ack_generate_info:
2-
build_date: "2023-10-04T06:33:03Z"
3-
build_hash: 7445de38211639a12e79992d154adab6e60f01fd
4-
go_version: go1.21.0
5-
version: v0.27.1-1-g7445de3
2+
build_date: "2023-11-21T06:03:03Z"
3+
build_hash: 1cc9b5172d3d1676af578a3411e8672698ec29ce
4+
go_version: go1.21.1
5+
version: v0.27.1-5-g1cc9b51
66
api_directory_checksum: 5f836e773a26000be60b198c9166f83ea86405e1
77
api_version: v1alpha1
88
aws_sdk_go_version: v1.44.93
99
generator_config_info:
10-
file_checksum: fe29e906cfb41430ae4df1e2dc17ea4a3fb0365f
10+
file_checksum: ee030a9c18c7fa34d8f7f4777997df355c029971
1111
original_file_name: generator.yaml
1212
last_modification:
1313
reason: API generation

apis/v1alpha1/generator.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ resources:
174174
Role:
175175
hooks:
176176
delta_pre_compare:
177-
code: compareTags(delta, a, b)
177+
code: customPreCompare(delta, a, b)
178178
sdk_read_one_post_set_output:
179179
template_path: hooks/role/sdk_read_one_post_set_output.go.tpl
180180
sdk_create_post_set_output:
@@ -232,6 +232,9 @@ resources:
232232
# policy document.
233233
InlinePolicies:
234234
type: map[string]*string
235+
AssumeRolePolicyDocument:
236+
compare:
237+
is_ignored: true
235238
Tags:
236239
compare:
237240
is_ignored: true

generator.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ resources:
174174
Role:
175175
hooks:
176176
delta_pre_compare:
177-
code: compareTags(delta, a, b)
177+
code: customPreCompare(delta, a, b)
178178
sdk_read_one_post_set_output:
179179
template_path: hooks/role/sdk_read_one_post_set_output.go.tpl
180180
sdk_create_post_set_output:
@@ -232,6 +232,9 @@ resources:
232232
# policy document.
233233
InlinePolicies:
234234
type: map[string]*string
235+
AssumeRolePolicyDocument:
236+
compare:
237+
is_ignored: true
235238
Tags:
236239
compare:
237240
is_ignored: true

go.mod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ require (
66
github.com/aws-controllers-k8s/runtime v0.27.1
77
github.com/aws/aws-sdk-go v1.44.93
88
github.com/go-logr/logr v1.2.3
9+
github.com/google/go-cmp v0.5.9
10+
github.com/micahhausler/aws-iam-policy v0.4.2
911
github.com/samber/lo v1.37.0
1012
github.com/spf13/pflag v1.0.5
1113
k8s.io/api v0.26.8
@@ -14,6 +16,10 @@ require (
1416
sigs.k8s.io/controller-runtime v0.14.5
1517
)
1618

19+
// Temporary fix for github.com/micahhausler/aws-iam-policy. Awaiting for a-hilaly to send
20+
// a PR to micahhausler/aws-iam-policy to build Equal() method for PolicyDocument struct.
21+
replace github.com/micahhausler/aws-iam-policy => github.com/a-hilaly/aws-iam-policy v0.0.0-20231121054900-2c56e839ca53
22+
1723
require (
1824
github.com/beorn7/perks v1.0.1 // indirect
1925
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
@@ -30,7 +36,6 @@ require (
3036
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
3137
github.com/golang/protobuf v1.5.2 // indirect
3238
github.com/google/gnostic v0.5.7-v3refs // indirect
33-
github.com/google/go-cmp v0.5.9 // indirect
3439
github.com/google/gofuzz v1.1.0 // indirect
3540
github.com/google/uuid v1.3.0 // indirect
3641
github.com/imdario/mergo v0.3.12 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
3333
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
3434
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
3535
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
36+
github.com/a-hilaly/aws-iam-policy v0.0.0-20231121054900-2c56e839ca53 h1:2uNM0nR2WUDN88EYFxjEaroH+PZJ6k/h9kl+KO0dWVc=
37+
github.com/a-hilaly/aws-iam-policy v0.0.0-20231121054900-2c56e839ca53/go.mod h1:Ojgst9ZFn+VEEJpqtuw/LxVGqEf2+hwWBlkYWvF/XWM=
3638
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
3739
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
3840
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=

pkg/resource/role/delta.go

Lines changed: 1 addition & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/resource/role/hooks.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@ package role
1515

1616
import (
1717
"context"
18+
"encoding/json"
1819
"net/url"
20+
"reflect"
1921

2022
ackcompare "github.com/aws-controllers-k8s/runtime/pkg/compare"
2123
ackrtlog "github.com/aws-controllers-k8s/runtime/pkg/runtime/log"
2224
ackutil "github.com/aws-controllers-k8s/runtime/pkg/util"
2325
svcsdk "github.com/aws/aws-sdk-go/service/iam"
26+
awsiampolicy "github.com/micahhausler/aws-iam-policy/policy"
2427
"github.com/samber/lo"
2528

2629
svcapitypes "github.com/aws-controllers-k8s/iam-controller/apis/v1alpha1"
@@ -366,6 +369,17 @@ func (rm *resourceManager) putAssumeRolePolicy(
366369
return err
367370
}
368371

372+
// customPreCompare contains logic that help compare two iam Roles. This
373+
// function is injected in newResourceDelta function.
374+
func customPreCompare(
375+
delta *ackcompare.Delta,
376+
a *resource,
377+
b *resource,
378+
) {
379+
compareTags(delta, a, b)
380+
compareAssumeRolePolicyDocument(delta, a, b)
381+
}
382+
369383
// compareTags is a custom comparison function for comparing lists of Tag
370384
// structs where the order of the structs in the list is not important.
371385
func compareTags(
@@ -382,6 +396,42 @@ func compareTags(
382396
}
383397
}
384398

399+
// compareAssumeRolePolicyDocument is a custom comparison function for
400+
// assumeRolePolicyDocuments. The reason why we need a custom function for
401+
// this fields is the API logic that trims all the trailing while spaces
402+
// string of provided documents.
403+
func compareAssumeRolePolicyDocument(
404+
delta *ackcompare.Delta,
405+
a *resource,
406+
b *resource,
407+
) {
408+
// To handle the variability in shapes of JSON objects representing IAM policies,
409+
// especially when it comes to statements, actions, and other fields, we need
410+
// a custom json.Unmarshaller approach crafted to our specific needs. Luckily,
411+
// it happens that @micahhausler buildta library dedicated to this very special
412+
// need: github.com/micahhausler/aws-iam-policy.
413+
//
414+
// NOTE(a-hilaly): I'm pretty aware that there is an error that should be handled.
415+
// However, unfortunetly, the `newResourceDelta` cannot return errors (for now),
416+
// leaving us with only two solutions, panicking or ignoring the error. The first
417+
// solution is an overkill as it will interrupt all the goroutines from functioning
418+
// and causing the controller to enter in a 'CrashLoopBackOff' state, which is not
419+
// fair, given that it's also is responsible of managing multiple objects of other
420+
// different resources.
421+
//
422+
// TOOD(a-hilaly): To address this issue, concider changing the delta signature
423+
// to return an error or take a context.Context to use the runtime logger. Both
424+
// of these changes require runtime/code-generator changes.
425+
var policyDocumentA awsiampolicy.Policy
426+
_ = json.Unmarshal([]byte(*a.ko.Spec.AssumeRolePolicyDocument), &policyDocumentA)
427+
var policyDocumentB awsiampolicy.Policy
428+
_ = json.Unmarshal([]byte(*b.ko.Spec.AssumeRolePolicyDocument), &policyDocumentB)
429+
430+
if !reflect.DeepEqual(policyDocumentA, policyDocumentB) {
431+
delta.Add("Spec.AssumeRolePolicyDocument", a.ko.Spec.AssumeRolePolicyDocument, b.ko.Spec.AssumeRolePolicyDocument)
432+
}
433+
}
434+
385435
// syncTags examines the Tags in the supplied Role and calls the ListRoleTags,
386436
// TagRole and UntagRole APIs to ensure that the set of associated Tags stays
387437
// in sync with the Role.Spec.Tags

test/e2e/tests/test_role.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,9 @@ def test_crud(self, simple_role):
293293
k8s_assume_role_policy = json.loads(cr['spec']['assumeRolePolicyDocument'])
294294
assert assume_role_policy_as_obj == k8s_assume_role_policy
295295

296+
# make sure the resource is not in an "update infinite loop"
297+
condition.assert_synced(ref)
298+
296299
assume_role_policy_to_deny_doc = '''{
297300
"Version": "2012-10-17",
298301
"Statement": [
@@ -329,3 +332,6 @@ def test_crud(self, simple_role):
329332
assert latest_assume_role_policy_doc['Statement'][0]['Effect'] == k8s_assume_role_policy_deny['Statement'][0]['Effect']
330333

331334
# Assume role policies cannot be entirely deleted, so CRU is tested here.
335+
336+
# make sure the resource is not in an "update infinite loop"
337+
condition.assert_synced(ref)

0 commit comments

Comments
 (0)