Skip to content

feat(go-lib): add shared NVCA token introspection client - #2069

Closed
shelleyshen-0 wants to merge 8 commits into
mainfrom
refactor/shared-nvca-introspection-client
Closed

shelleyshen-0 wants to merge 8 commits into
mainfrom
refactor/shared-nvca-introspection-client

Conversation

@shelleyshen-0

@shelleyshen-0 shelleyshen-0 commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

TL;DR

Event Ledger's internal/nvca introspection client (from #1960) duplicates the same RFC 7662/NVCA verification logic ReVal's ICMSIntrospect authorizer already has: request/result types, NVCA subject validation, token-size limits, and a hashed-token cache. Extracts the shared, stable primitive into go-lib/pkg/auth/nvcaintrospect so this security-sensitive code has one implementation instead of two.

Additional Details

  • Follows up on review feedback on feat(event-ledger): authorize NVCA writes via SIS PSAT introspection #1960 (feat(event-ledger): authorize NVCA writes via SIS PSAT introspection #1960 (comment)): "extract only the stable RFC 7662/NVCA client primitive... keep the shared surface deliberately narrow."
  • Shared: IntrospectRequest/IntrospectResult, IsValidNVCASubject, token-size limit, the hashed-token cache.
  • Cache policy matches ReVal's existing, tested behavior: cache both a valid-subject and an invalid-subject active result (a token's subject is fixed once issued, so either verdict is safe to reuse), never cache an inactive result (clock skew or an nbf window can make the same token valid moments later).
  • Two hardenings neither existing implementation had: a bounded response-body read (previously unbounded, letting a compromised or faulty endpoint stream an unlimited body), and CheckRedirect refusing to follow redirects (previously default Go behavior, which would resend the bearer token to whatever host a redirect names).
  • Stays service-local (not touched here): Event Ledger's cluster-binding logic and ReVal's Authorizer/AuthzContext adapter. NATS auth-callout's webhook contract is unrelated and untouched.
  • Cross-module note: helm-reval and event-ledger each pin go-lib to a published commit in their own go.mod. Adopting this package in either service is a follow-up PR once this merges and each pin is bumped past this commit.

For the Reviewer

  • pkg/auth/nvcaintrospect/introspect.go: the shared client.
  • Package sits under pkg/auth/ but as its own subpackage, not merged into the existing pkg/auth (which does unrelated outbound token-fetching), to avoid pulling NVCA-specific subject validation into every pkg/auth caller.

For QA

  • go test, go vet, and bazel test //src/libraries/go/lib/pkg/auth/nvcaintrospect/... all pass.
  • bazel test //src/libraries/go/lib:golangci_lint has 3 pre-existing failures in unrelated files (pkg/nvkit/servers/shutdown.go, pkg/nvkit/shutdown/shutdown.go, pkg/trustbundle/trust_bundle.go, a header-year check), confirmed identical on main, not touched by this change.

Issues

Relates to #1655

Checklist

  • I am familiar with the Contributing Guidelines.
  • I have signed off my commits for Developer Certificate of Origin (DCO) compliance.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

Summary by CodeRabbit

  • New Features
    • Added SIS token introspection as a fallback when local token verification fails, enabling eligible NVCA tokens to access write operations.
    • Added configurable introspection settings, with default timeout and cache values.
    • Event records now inherit the authenticated cluster ID when missing; mismatched IDs are rejected.
  • Bug Fixes
    • Improved authentication responses for inactive, invalid, or unverifiable tokens, while preserving existing behavior for other authorization paths.

shelleyshen-0 and others added 7 commits September 16, 2026 22:41
NVCA authenticates to Event Ledger with a Kubernetes projected
service-account token (PSAT), not an OpenBao-issued JWT, so it was
rejected by the existing OpenBao-only verification path.

Add an internal/nvca introspection client (mirrors ReVal's SIS/ICMS
introspection authorizer) and wire it into the auth middleware: a
JWT-shaped bearer token is verified locally against OpenBao first, and
only on failure is it retried against SIS's NVCA introspection
endpoint. A verified NVCA identity is trusted only on the write routes
it was scoped for, never as a stand-in for an arbitrary read scope.
The SIS-resolved clusterId is treated as authoritative over whatever
cluster_id a request payload claims, rejecting a mismatch or filling
in a missing value before the event context is built.

Auth.Introspection is a new, separate runtime config from stack-level
deployment gating: enabling it without a URL fails startup rather than
silently accepting unverified NVCA callers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
newJWTWithPSATMiddleware still verifies an OpenBao JWT first; it only
falls back to SIS for a PSAT. Name it after the token type it accepts,
not the one caller (NVCA) that currently sends one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Wrap the nvca.Client's HTTP transport with otelhttp, matching the
shared-client pattern already used for JWKS fetching, so the SIS
introspection call gets a span and OpenTelemetry's standard HTTP
client metrics instead of running uninstrumented.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Don't cache an active, subject-valid SIS response that's missing
ClusterID: it's a failure outcome (the middleware 403s it same as an
inactive token), so caching it same as a success would pin that 403
for the full TTL even after SIS starts returning a complete response.

Bound the introspection cache at a fixed entry count with O(1) random
eviction on overflow, instead of an unbounded map scanned for expired
entries on every write while holding the lock.

Add cluster-binding test coverage for extractCloudEvent mirroring the
existing extractK8sEvent coverage, since bindNVCAClusterID is wired
into both.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Event Ledger's internal/nvca client and ReVal's ICMSIntrospect
authorizer duplicate the same RFC 7662/NVCA verification logic
(request/result types, subject validation, token-size limits, and a
hashed-token cache) as two separate implementations, so the same
security-sensitive code has to be reviewed and fixed twice.

Add pkg/auth/nvcaintrospect as the shared primitive: the HTTP call,
NVCA subject validation, and a cache that follows ReVal's existing
policy (cache both a valid-subject and an invalid-subject active
result, since a token's subject is fixed once issued; never cache an
inactive result, since clock skew or an nbf window can make the same
token valid moments later).

Adds two hardenings neither existing implementation had: a bounded
response body read (an unbounded read let a compromised or faulty
endpoint stream an unlimited body) and CheckRedirect refusing to
follow a redirect (which would otherwise resend the bearer token to
whatever host the redirect names).

Event Ledger's cluster-binding and ReVal's Authorizer adapter stay
service-local; adopting this package in each is a follow-up once
go-lib's pin is bumped past this commit.
@coderabbitai

coderabbitai Bot commented Sep 23, 2026

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Repository: NVIDIA/nvcf/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 897282a8-1e4c-4be1-82e2-7c2d42dc5f91

📥 Commits

Reviewing files that changed from the base of the PR and between 9dfda2e and f9271b2.

📒 Files selected for processing (17)
  • src/control-plane-services/event-ledger/cmd/api/service/v3.go
  • src/control-plane-services/event-ledger/cmd/api/service/v3_test.go
  • src/control-plane-services/event-ledger/cmd/api/startup/BUILD.bazel
  • src/control-plane-services/event-ledger/cmd/api/startup/run_service.go
  • src/control-plane-services/event-ledger/internal/config/auth_config_test.go
  • src/control-plane-services/event-ledger/internal/config/config.go
  • src/control-plane-services/event-ledger/internal/middleware/BUILD.bazel
  • src/control-plane-services/event-ledger/internal/middleware/jwt.go
  • src/control-plane-services/event-ledger/internal/middleware/nvca_introspect.go
  • src/control-plane-services/event-ledger/internal/middleware/policy.go
  • src/control-plane-services/event-ledger/internal/middleware/policy_test.go
  • src/control-plane-services/event-ledger/internal/nvca/BUILD.bazel
  • src/control-plane-services/event-ledger/internal/nvca/introspect.go
  • src/control-plane-services/event-ledger/internal/nvca/introspect_test.go
  • src/libraries/go/lib/pkg/auth/nvcaintrospect/BUILD.bazel
  • src/libraries/go/lib/pkg/auth/nvcaintrospect/introspect.go
  • src/libraries/go/lib/pkg/auth/nvcaintrospect/introspect_test.go
 ______________________________________
< My code review levels are over 9000! >
 --------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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

@shelleyshen-0

Copy link
Copy Markdown
Contributor Author

Closing: this branch was based on feat/event-ledger-nvca-psat-introspection instead of main, so it was showing PR #1960's commits as part of this diff. Replaced by #2070, which contains only the new pkg/auth/nvcaintrospect package on top of main.

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.

1 participant