Skip to content

fix(uat): refresh the EKS STS session mid-gate on AWS - #1872

Merged
njhensley merged 5 commits into
NVIDIA:mainfrom
njhensley:ci/uat-aws-eks-token-refresh
Jul 23, 2026
Merged

njhensley merged 5 commits into
NVIDIA:mainfrom
njhensley:ci/uat-aws-eks-token-refresh

Conversation

@njhensley

Copy link
Copy Markdown
Member

Summary

Implement the cloud_refresh_credentials hook for AWS so the EKS install phase's readiness gate re-mints its STS session mid-gate, instead of running past the 1h session and failing ExpiredToken → Unauthorized.

Motivation / Context

The STS session configure-aws-credentials mints is a fixed ~1h (the role's default MaxSessionDuration) with no refresh token. The UAT - install step (90m budget) runs the helmfile apply and the readiness-gate loop as a single step, so on a slow GB200 run the gate outlived the session minted at the install step and every aws eks get-token then failed ExpiredToken → Unauthorized, dropping the whole validate mid-phase.

The shared readiness gate (tests/uat/lib/phases.sh) already calls a cloud_refresh_credentials hook every CLOUD_REFRESH_INTERVAL_SECONDS — Azure implements it (tests/uat/azure/run, federated relogin); AWS left it a no-op on the (now-disproven) assumption its session outlasts each phase.

Fixes: #1861
Related: N/A

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

Component(s) Affected

  • Other: UAT tooling (tests/uat/aws/run)

Implementation Notes

  • aws_sts_federated_refresh mints a fresh GitHub OIDC assertion and exchanges it via aws sts assume-role-with-web-identity — an unsigned call (ambient creds env -u'd), so it succeeds even after the current session has expired — then exports the new credentials so the subsequent same-shell aicr validate / kubectl get-token sign with them. Wired into the shared hook with CLOUD_REFRESH_INTERVAL_SECONDS=1200 (20m), which keeps every cached token comfortably inside the 1h session (the token is minted before helmfile apply, so the first mid-gate refresh lands ~40m in, ~20m before expiry).
  • Keeps the 1h session — no IAM MaxSessionDuration change, so no credential-lifetime increase and none of the terraform-apply rollout coordination an IAM bump would need. (An IAM-duration approach was prototyped and rejected in review for exactly those reasons.)
  • Mirrors the proven Azure pattern (az_federated_relogin); the gate treats a failed refresh as a warning and retries, so worst case it degrades to the pre-fix behavior with a diagnostic, never a new hard failure.
  • Secret hygiene: the mint/exchange/export runs with set -x forced off (restored at a single exit) and ::add-mask::-registers the OIDC token + STS keys, so they can never reach the public-repo job log even if xtrace is later enabled. (configure-aws-credentials auto-masks its own creds; these are hand-minted, so we mask them ourselves.)
  • Reviewed via a multi-persona + adversarial pass (correctness/bash, security, operability); the masking + xtrace guard are results of that pass, and an over-claimed "drop --duration-seconds" finding was refuted (STS MaxSessionDuration cannot be set below 1h, so requesting the 3600 floor is always safe).

Testing

shellcheck -x tests/uat/aws/run
bash -n tests/uat/aws/run
  • shellcheck clean, bash -n OK.
  • Functional smoke tests (faked aws/curl, real bash): no-op on missing identifiers; mint→parse→export on full env; secret never appears in a set -x trace; all four ::add-mask:: emitted; xtrace state correctly restored (on→on, off→off).

Risk Assessment

  • Low — Additive, one file, mirrors a merged sibling; inert on the fast path (h100 gates finish before the 20m interval); no IAM/cross-system coupling; trivially reversible (the shared default no-op is untouched).

Rollout notes: No IAM or infra change. Recommend a live validation: a GB200 EKS UAT run (from test/uat) that previously failed at the install/readiness-gate phase — confirm the install completes without ExpiredToken/Unauthorized, and an h100 run confirms no regression. Follow-up (not this PR): port the ::add-mask:: + xtrace guard hardening to the Azure sibling for parity.

Checklist

  • Tests pass locally (shellcheck + bash -n + functional smoke tests)
  • I did not skip/disable tests to make CI green
  • I added/updated tests for new functionality (functional smoke tests; no unit-test harness exists for this runner)
  • Changes follow existing patterns in the codebase (mirrors tests/uat/azure/run)
  • Commits are cryptographically signed (git commit -S)
The STS session minted by configure-aws-credentials is a fixed ~1h (the
role's default MaxSessionDuration) with no refresh token. The install
phase's readiness gate has a 90m budget, so on a slow GB200 run the gate
outlived the session minted at the install step and every EKS
`aws eks get-token` then failed ExpiredToken -> Unauthorized, dropping the
whole validate mid-phase.

The shared readiness gate (tests/uat/lib/phases.sh) already calls a
cloud_refresh_credentials hook every CLOUD_REFRESH_INTERVAL_SECONDS —
Azure implements it (federated relogin); AWS left it a no-op on the
assumption its session outlasts each phase. Implement it for AWS: re-mint
the STS session in place via a fresh GitHub OIDC assertion exchanged with
AssumeRoleWithWebIdentity (an unsigned call, so it works even after the
current session expired), exporting the new credentials so the subsequent
same-shell `aicr validate` / kubectl get-token sign with them. Interval
20m keeps every cached token comfortably inside the 1h session.

This keeps the 1h session (no IAM MaxSessionDuration change, so no
credential-lifetime increase and no terraform-apply rollout coupling) and
mirrors the proven Azure pattern. The secret-handling section forces
`set -x` off and ::add-mask::-registers the minted OIDC token and STS keys
so they can never reach the public-repo job log.

Fixes NVIDIA#1861

Signed-off-by: Nathan Hensley <nhensley@nvidia.com>
@njhensley
njhensley requested a review from a team as a code owner July 23, 2026 00:06
@njhensley njhensley added the theme/ci-dx CI pipelines, developer experience, and build tooling label Jul 23, 2026
@njhensley njhensley self-assigned this Jul 23, 2026
@coderabbitai

coderabbitai Bot commented Jul 23, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The AWS UAT runner adds periodic STS credential refresh during readiness-gate execution. In GitHub Actions, it obtains an OIDC token, exchanges it for AWS role credentials, masks sensitive values, and exports the refreshed credentials. The runner configures the shared cloud refresh interval and dispatches refresh calls through cloud_refresh_credentials().

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: kaynetu

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the AWS UAT STS refresh on the EKS readiness gate, which matches the main change.
Description check ✅ Passed The description directly describes the AWS readiness-gate credential refresh and matches the implemented fix.
Linked Issues check ✅ Passed The PR implements in-process AWS credential refresh during the readiness gate, addressing the token-expiry Unauthorized failure in #1861.
Out of Scope Changes check ✅ Passed The change appears focused on the AWS UAT runner refresh hook and introduces no unrelated scope.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@tests/uat/aws/run`:
- Around line 54-58: Update aws_sts_federated_refresh to distinguish non-GitHub
environments from misconfigured GitHub Actions runs using GITHUB_ACTIONS.
Preserve the successful no-op when outside CI, but when GITHUB_ACTIONS indicates
CI and any required OIDC or AWS configuration variable is missing, emit a
diagnostic and fail instead of returning success with no output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 895fc44e-dd30-4969-8396-a217e04e4f50

📥 Commits

Reviewing files that changed from the base of the PR and between c5d4ede and 90b7e44.

📒 Files selected for processing (1)
  • tests/uat/aws/run
Comment thread tests/uat/aws/run
Address CodeRabbit review on NVIDIA#1872: the guard silently returned 0 when the
OIDC/role identifiers were absent, so a CI misconfiguration (id-token: write
dropped, AWS_ACCOUNT_ID unset) would degrade to the non-refreshing session
and re-introduce NVIDIA#1861 with no diagnostic. Emit a ::warning:: in CI
(GITHUB_ACTIONS set) while keeping the local-dev no-op quiet.

Signed-off-by: Nathan Hensley <nhensley@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@tests/uat/aws/run`:
- Around line 54-65: Update aws_sts_federated_refresh so missing OIDC or role
identifiers return a non-zero status when GITHUB_ACTIONS is set, allowing
phases.sh to retry instead of recording success. Preserve the current warning
and keep returning success for quiet local-development no-op behavior outside
GitHub Actions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: c3793de2-b053-4fa9-855b-8175f48170d6

📥 Commits

Reviewing files that changed from the base of the PR and between 90b7e44 and aa78297.

📒 Files selected for processing (1)
  • tests/uat/aws/run
Comment thread tests/uat/aws/run
Follow-up to CodeRabbit on NVIDIA#1872: returning 0 when OIDC/role identifiers are
missing in CI let the readiness gate record the missed refresh as a success
(advancing last_cred_refresh, no retry). Return non-zero in GitHub Actions
(warn + return 1) so the gate keeps warning and retrying; local-dev no-op
stays a quiet return 0.

Signed-off-by: Nathan Hensley <nhensley@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
tests/uat/aws/run (2)

98-98: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Keep the web identity token out of argv. --web-identity-token "${oidc_token}" still exposes the bearer token to process inspection while the CLI runs. Use --web-identity-token file://... or web_identity_token_file with a 0600 temp file and cleanup trap instead.

🤖 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 `@tests/uat/aws/run` at line 98, Update the command invocation around the web
identity token option to avoid placing the bearer token directly in argv. Write
the token to a temporary file with 0600 permissions, pass its path using the
CLI’s file-based web identity token option, and add cleanup via a trap to remove
the file on exit.

Source: MCP tools


94-98: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Make the STS call explicitly unsigned.

env -u only drops the three environment variables here; the CLI can still pick up other configured credentials. Add --no-sign-request so this refresh always relies on the web-identity token alone.

Suggested fix
      aws sts assume-role-with-web-identity \
+      --no-sign-request \
      --role-arn "${role_arn}" \
🤖 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 `@tests/uat/aws/run` around lines 94 - 98, Update the aws sts
assume-role-with-web-identity invocation in the credential refresh flow to
include the --no-sign-request option, ensuring the call is explicitly unsigned
and relies only on the web-identity token rather than other configured
credentials.

Source: MCP tools

🤖 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.

Outside diff comments:
In `@tests/uat/aws/run`:
- Line 98: Update the command invocation around the web identity token option to
avoid placing the bearer token directly in argv. Write the token to a temporary
file with 0600 permissions, pass its path using the CLI’s file-based web
identity token option, and add cleanup via a trap to remove the file on exit.
- Around line 94-98: Update the aws sts assume-role-with-web-identity invocation
in the credential refresh flow to include the --no-sign-request option, ensuring
the call is explicitly unsigned and relies only on the web-identity token rather
than other configured credentials.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 3b54dbb7-ee1b-4842-b237-1a6d7981ba18

📥 Commits

Reviewing files that changed from the base of the PR and between aa78297 and 076ac25.

📒 Files selected for processing (1)
  • tests/uat/aws/run
@njhensley
njhensley enabled auto-merge (squash) July 23, 2026 01:49
@njhensley
njhensley merged commit 33f06c5 into NVIDIA:main Jul 23, 2026
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/tests size/M theme/ci-dx CI pipelines, developer experience, and build tooling

2 participants