Repository navigation
feat: add identity.assumeRoleChainRef for a dynamic assume-role chain - #13
Merged
Merged
Conversation
Resolve the STS assume-role chain at runtime from a status./context./spec. path, alongside regionRef/filtersRef/parametersRef, so one Composition can target a different role per control plane (e.g. from an EnvironmentConfig). The resolved list replaces the static assumeRoleChain; an absent path keeps it. A malformed value is fatal and names the ref and the entry index. - input: Identity.AssumeRoleChainRef (+ generated deepcopy and CRD). - fn.go: resolveAssumeRoleChainRef + toAssumeRoleChain, called next to the other resolve*Ref calls; buildAWSConfig is unchanged. - tests: context-sourced chain overrides static, absent keeps static, malformed values are fatal. - docs: README input reference, dynamic queries, and a note on the shared base identity. Signed-off-by: Tobias Kässer <tobias.kasser@upbound.io>
Decode each resolved entry with the same strict JSON options the SDK uses for the static Input (exact field names, unknown fields rejected), so a typo like externalId fails instead of being accepted. Reject an empty list, which would otherwise drop the static chain and run the query as the base identity. Cover the spec. and status. sources in the override test. Signed-off-by: Tobias Kässer <tobias.kasser@upbound.io>
jakubramut
requested changes
Oct 22, 2026
…tic chain Previously, if assumeRoleChainRef's path didn't resolve and no static assumeRoleChain was set, the query silently ran as the function's base identity and reported success. A static chain is still used as the explicit fallback; without one the step is now fatal. Signed-off-by: Tobias Kässer <tobias.kasser@upbound.io>
Adds example/composition-assume-role-chain-ref.yaml (chain taken from the environment context, as an EnvironmentConfig would supply it), a `make render-assume-role ROLE_ARN=...` target kept out of `make render` like render-irsa, and docs in example/README.md, following #11 and #12. Signed-off-by: Tobias Kässer <tobias.kasser@upbound.io>
Contributor
Author
|
Thanks @jakubramut, both points addressed:
Verified with a real-AWS render: the cross-account role is assumed via the context value, and without the context value the step is fatal. |
jakubramut
self-requested a review
October 22, 2026 09:29
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
identity.assumeRoleChainRef, so the STS assume-role chain can be resolved at runtime from aspec./status./context.path, the same wayregionRef,filtersRefandparametersRefalready work.Why
identity.assumeRoleChainis static step input. When one Composition is deployed to many control planes and each control plane must query through a different role (e.g. one AWS account or business unit per control plane), the only option today is to bake the chain into the function pod's base identity (e.g. the Pod Identity association), which gives every composition on that control plane the same role. The ref lets platform-controlled config (an EnvironmentConfig) pick the role per control plane while the Composition stays identical.Behaviour
assumeRoleChain; path absent → static chain is kept.AssumeRolefield names (roleARNrequired;externalID,roleSessionName,tags,transitiveTagKeys). They are decoded as strictly as the Input itself (exact names, unknown fields rejected), so a typo likeexternalIdis fatal instead of silently accepted.roleARN, wrong field type.buildAWSConfigis unchanged; resolution happens next to the otherresolve*Refcalls.context.path fed from platform config over an XRspec.path, since the function's base identity is shared by every composition on the control plane.Testing
TestRunFunctionResolvesAssumeRoleChainRef— override from context, spec and status (all five fields), absent path keeps static, seven malformed cases are fatal and never reach the AWS query.crossplane renderagainst a local STS stub: two-hop chains from context and spec produce the expected AssumeRole calls in order with all parameters, hop 2 signed with hop 1's credentials.crossplane renderagainst real AWS (temporary IAM roles, since deleted), 7/7:transitiveTagKeys→UnauthorizedOperationas hop 2 (proves the tag is what made the positive case work)AccessDeniedon hop 1go test ./..., golangci-lint v2.8.0 (0 issues),go generate+go mod tidyproduce no diff.