Skip to content

[OCM-24570] feat: add external ID support when assuming customer support roles#937

Merged
openshift-merge-bot[bot] merged 1 commit intoopenshift:mainfrom
michaelryanmcneill:OCM-24570
May 7, 2026
Merged

[OCM-24570] feat: add external ID support when assuming customer support roles#937
openshift-merge-bot[bot] merged 1 commit intoopenshift:mainfrom
michaelryanmcneill:OCM-24570

Conversation

@michaelryanmcneill
Copy link
Copy Markdown
Contributor

@michaelryanmcneill michaelryanmcneill commented May 6, 2026

What type of PR is this?

  • fix (Bug Fix)
  • feat (New Feature)
  • docs (Documentation)
  • test (Test Coverage)
  • chore (Clean Up / Maintenance Tasks)
  • other (Anything that doesn't fit the above)

What this PR does / Why we need it?

For isolated AWS cloud credentials (assume-role sequence from Backplane API), the CLI now:

  • Parses optional externalId from the assume-role-sequence JSON.
  • Passes it into AWS STS via stscreds AssumeRoleOptions.ExternalID for Org and Target roles in the chain (not the jump-account SRE user role).

Non-isolated cloud credentials still rely on the API only; no user-facing flag changes. README documents both paths.

Which Jira/Github issue(s) does this PR fix?

Special notes for your reviewer

  • Backplane API must expose externalId for clusters that use it; missing field keeps previous behavior (empty ExternalID on RoleArnSession). API changes are included in OCM-24568.

Unit Test Coverage

Test coverage checks

  • Added unit tests
  • Created jira card to add unit test
  • This PR may not need unit tests

Pre-checks (if applicable)

  • Ran unit tests locally
  • Validated the changes in a cluster
  • Included documentation changes with PR
  • Backward compatible

/label tide/merge-method-squash

Summary by CodeRabbit

  • New Features

    • Support for supplying AWS External IDs during multi-step role assumption flows; External IDs are now conditionally applied to organizational and target roles when provided.
  • Tests

    • Added tests verifying External ID propagation and correct inclusion/omission in AWS role-assume requests and across assumption sequences.

@openshift-ci openshift-ci Bot added the tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges. label May 6, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 3f7fff2a-8032-4362-a5fc-5ab3d27a25c7

📥 Commits

Reviewing files that changed from the base of the PR and between d4efcd9 and c054bda.

⛔ Files ignored due to path filters (1)
  • README.md is excluded by !**/*.md
📒 Files selected for processing (4)
  • cmd/ocm-backplane/cloud/common.go
  • cmd/ocm-backplane/cloud/common_test.go
  • pkg/awsutil/sts.go
  • pkg/awsutil/sts_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • cmd/ocm-backplane/cloud/common.go
  • pkg/awsutil/sts.go
  • pkg/awsutil/sts_test.go
  • cmd/ocm-backplane/cloud/common_test.go

Walkthrough

Adds per-step ExternalID support for AWS STS role assumption: response parsing includes externalId, RoleArnSession carries ExternalID, AssumeRole accepts and applies it to STS requests, and getIsolatedCredentials applies the external ID to Org and Target role steps.

Changes

External ID Support in AWS Role Assumption Chain

Layer / File(s) Summary
Data Shape
cmd/ocm-backplane/cloud/common.go, pkg/awsutil/sts.go
assumeChainResponse gains ExternalID string 'json:"externalId,omitempty"'; RoleArnSession gains exported ExternalID string.
Core Implementation
pkg/awsutil/sts.go
AssumeRole(..., policyARNs []types.PolicyDescriptorType, externalID string) added; when externalID is non-empty, set options.ExternalID on STS requests.
Sequence Orchestration
pkg/awsutil/sts.go
AssumeRoleSequence forwards RoleArnSession.ExternalID into every AssumeRole call, including retry attempts after propagation waits.
Integration & Wiring
cmd/ocm-backplane/cloud/common.go
getIsolatedCredentials extracts ExternalID from assumeChainResponse and conditionally assigns it to RoleArnSession.ExternalID for Org-Role-Arn and Target-Role-Arn entries when non-empty.
Tests & Validation
cmd/ocm-backplane/cloud/common_test.go, pkg/awsutil/sts_test.go
Test helpers and unit tests updated: helpers populate/expose ExternalID in generated chains; tests verify ExternalID is set for Org/Target roles and propagated into STS AssumeRole requests; existing tests adjusted for new AssumeRole parameter.

Sequence Diagram

sequenceDiagram
    participant API as API Response
    participant Handler as getIsolatedCredentials
    participant Chain as AssumeRoleSequence
    participant STS as AWS STS

    API->>Handler: return assumeChainResponse (externalId)
    Handler->>Handler: parse externalId
    Handler->>Handler: set RoleArnSession.ExternalID for Org & Target roles
    Handler->>Chain: pass role-assumption chain (with ExternalID fields)
    Chain->>STS: AssumeRole(step N, ExternalID?)
    STS-->>Chain: credentials
    Chain->>STS: AssumeRole(next step, ExternalID?)
    STS-->>Chain: credentials
    Chain-->>Handler: final chained credentials
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding external ID support for assuming customer support roles, which aligns with the core functionality changes across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci openshift-ci Bot requested review from diakovnec and xiaoyu74 May 6, 2026 23:54
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
pkg/awsutil/sts_test.go (1)

820-860: ⚡ Quick win

Good targeted tests; consider one AssumeRoleSequence-level ExternalID test to close the wiring gap.

TestAssumeRole_externalID and TestAssumeRole_emptyExternalID correctly exercise the low-level AssumeRole function. However, the propagation path RoleArnSession.ExternalID → AssumeRole(..., roleArnSession.ExternalID) inside AssumeRoleSequence is untested. If that argument were accidentally dropped from either call site in the loop, no test would fail. Since ExternalID protects against confused-deputy attacks, this wiring is worth a direct test.

The stsAssumeRoleCapture helper you've added is already perfectly suited for this; it just needs to be wired into a TestAssumeRoleSequence case:

✅ Suggested additional test case for `TestAssumeRoleSequence`
// Add to the TestAssumeRoleSequence tests slice, or as a standalone test:
func TestAssumeRoleSequence_ExternalID(t *testing.T) {
    capture := &stsAssumeRoleCapture{}

    _, err := AssumeRoleSequence(
        capture, // seed client — captures the first AssumeRole call
        []RoleArnSession{
            {RoleArn: "arn:aws:iam::123:role/r", RoleSessionName: "sess", ExternalID: "my-ext-id"},
        },
        nil,
        func(optFns ...func(*config.LoadOptions) error) (stscreds.AssumeRoleAPIClient, error) {
            return capture, nil
        },
    )
    if err != nil {
        t.Fatal(err)
    }
    if capture.lastInput == nil || capture.lastInput.ExternalId == nil || *capture.lastInput.ExternalId != "my-ext-id" {
        t.Fatalf("AssumeRoleSequence did not propagate ExternalID to STS: %+v", capture.lastInput)
    }
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/awsutil/sts_test.go` around lines 820 - 860, Add a test that verifies
RoleArnSession.ExternalID is passed through AssumeRoleSequence into the STS
AssumeRole call: use the existing stsAssumeRoleCapture as the seed client, call
AssumeRoleSequence with a single RoleArnSession{RoleArn: "...", RoleSessionName:
"sess", ExternalID: "my-ext-id"}, and provide a loader function that returns the
capture; after the call assert capture.lastInput is non-nil and that
capture.lastInput.ExternalId != nil and equals "my-ext-id". This will exercise
the AssumeRoleSequence -> AssumeRole propagation without changing production
code.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/awsutil/sts_test.go`:
- Around line 820-860: Add a test that verifies RoleArnSession.ExternalID is
passed through AssumeRoleSequence into the STS AssumeRole call: use the existing
stsAssumeRoleCapture as the seed client, call AssumeRoleSequence with a single
RoleArnSession{RoleArn: "...", RoleSessionName: "sess", ExternalID:
"my-ext-id"}, and provide a loader function that returns the capture; after the
call assert capture.lastInput is non-nil and that capture.lastInput.ExternalId
!= nil and equals "my-ext-id". This will exercise the AssumeRoleSequence ->
AssumeRole propagation without changing production code.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: fc9630be-b4f6-426c-ace2-13ad73b414d6

📥 Commits

Reviewing files that changed from the base of the PR and between 1abfc95 and d4efcd9.

⛔ Files ignored due to path filters (1)
  • README.md is excluded by !**/*.md
📒 Files selected for processing (4)
  • cmd/ocm-backplane/cloud/common.go
  • cmd/ocm-backplane/cloud/common_test.go
  • pkg/awsutil/sts.go
  • pkg/awsutil/sts_test.go

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 7, 2026

Codecov Report

❌ Patch coverage is 83.33333% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 53.99%. Comparing base (1abfc95) to head (c054bda).

Files with missing lines Patch % Lines
pkg/awsutil/sts.go 75.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #937      +/-   ##
==========================================
+ Coverage   53.96%   53.99%   +0.02%     
==========================================
  Files          82       82              
  Lines        6319     6323       +4     
==========================================
+ Hits         3410     3414       +4     
  Misses       2463     2463              
  Partials      446      446              
Files with missing lines Coverage Δ
cmd/ocm-backplane/cloud/common.go 56.48% <100.00%> (+0.27%) ⬆️
pkg/awsutil/sts.go 62.77% <75.00%> (+0.55%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

…ort roles

Signed-off-by: michaelryanmcneill <michael@michaelryanmcneill.com>
@michaelryanmcneill
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 7, 2026

@michaelryanmcneill: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@smarthall
Copy link
Copy Markdown
Member

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label May 7, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 7, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: michaelryanmcneill, smarthall

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label May 7, 2026
@openshift-merge-bot openshift-merge-bot Bot merged commit 69547a7 into openshift:main May 7, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants