Skip to content

Normalize string role claims before claim-based role mapping evaluation - #6306

Open
Yanhaoxi wants to merge 2 commits into
stacklok:mainfrom
Yanhaoxi:fix/awssts-string-role-claim-fallback
Open

Normalize string role claims before claim-based role mapping evaluation#6306
Yanhaoxi wants to merge 2 commits into
stacklok:mainfrom
Yanhaoxi:fix/awssts-string-role-claim-fallback

Conversation

@Yanhaoxi

Copy link
Copy Markdown
Contributor

Summary

Fixes #6305. Claim-based role mappings are evaluated with the fixed CEL expression claim_value in claims[role_claim_key], whose semantics depend on the role claim value's runtime type. cel-go v0.30.0 defines in only for list/map operands, so a string-typed role claim raised a "no such overload" error that SelectRole swallowed and treated as a non-match — the user silently got FallbackRoleArn even when their claim exactly equaled the configured Claim. An object-typed role claim made in test map-key membership, spuriously matching when the configured value was a key.

WHAT changed:

  • Add normalizeRoleClaim, applied to the role claim value before evaluation: string → one-element list (exact membership restored); missing claim → empty list (fallback preserved); any other shape (object, number, bool, null) → rejected.
  • SelectRole now fails closed on unsupported claim shapes and claim-mapping evaluation errors (ErrNoRoleMapping, HTTP 403 via the aws_sts middleware) instead of silently granting FallbackRoleArn; matcher-expression errors keep their skip-and-fall-back behavior but log at Warn instead of Debug.
  • Add regression tests for string claims (exact match, substring non-match) and unsupported shapes (fail closed).

Type of change

  • Bug fix
  • New feature
  • Refactoring (no behavior change)
  • Dependency update
  • Documentation
  • Other (describe):

Test plan

  • Unit tests (task test)
  • E2E tests (task test-e2e)
  • Linting (task lint-fix)
  • Manual testing (describe below)

Run: go test ./pkg/auth/awssts/... ./pkg/vmcp/auth/strategies/.... New tests TestRoleMapper_SelectRole_StringRoleClaim and TestRoleMapper_SelectRole_UnsupportedRoleClaimShape FAIL without the source fix and PASS with it; full suites pass. go vet and gofmt clean; golangci-lint reports only 3 pre-existing gci issues in files this PR does not touch.

API Compatibility

  • This PR does not break the v1beta1 API. Configuration shape is unchanged.

Changes

File Change
pkg/auth/awssts/role_mapper.go Normalize role claim to a list before evaluation; fail closed on unsupported shapes and claim-mapping evaluation errors; matcher eval-error log Debug → Warn
pkg/auth/awssts/role_mapper_test.go Add string-claim and unsupported-shape regression tests

Does this introduce a user-facing change?

Yes. Two intentional behavior changes:

  1. A string-typed role claim exactly equal to the configured Claim now selects the mapped role (e.g. groups: "admins" with Claim: "admins"AdminRole); previously it silently fell back. Strings merely containing the value still do not match.
  2. A role claim value that is neither a string nor a list (object, number, bool, null) now fails closed (HTTP 403) instead of silently getting the fallback role — and instead of being spuriously matched as a map key for objects. Deployments must emit the role claim as a string or a list of strings.

Special notes for reviewers

  • A missing role claim still falls back (empty list), preserving the pre-existing behavior that relied on the swallowed CEL error.
  • Matcher-based expressions keep their skip-and-fall-back semantics; only the log level changes (Debug → Warn).
  • The fail-closed behavior for unsupported shapes is deliberate: it closes both the silent fallback (string) and the map-key spurious match (object) for the same expression.

@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.11111% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.83%. Comparing base (0302206) to head (4b24369).

Files with missing lines Patch % Lines
pkg/auth/awssts/role_mapper.go 86.11% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6306      +/-   ##
==========================================
- Coverage   72.85%   72.83%   -0.02%     
==========================================
  Files         742      742              
  Lines       77804    77836      +32     
==========================================
+ Hits        56683    56693      +10     
- Misses      17145    17168      +23     
+ Partials     3976     3975       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

String-typed role claims silently get the fallback role

1 participant