Skip to content

feat(sandbox): add delegated identity for token exchange - #2772

Open
grs wants to merge 1 commit into
NVIDIA:mainfrom
grs:delegated-sandbox-identity
Open

feat(sandbox): add delegated identity for token exchange#2772
grs wants to merge 1 commit into
NVIDIA:mainfrom
grs:delegated-sandbox-identity

Conversation

@grs

@grs grs commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Add opt-in delegated OIDC identity support for sandboxes so token-exchange provider profiles can use the sandbox creator’s bounded identity instead of a stored provider subject credential. This adds gateway managed delegated credential storage, sandbox delegation lifecycle APIs, CLI commands for enabling, extending, withdrawing, and administering delegation.

Note this builds on PR #1970, which adds the basic token exchange capability.

Example CLI flow:

openshell sandbox create \
  --provider protected-services \
  --delegate-identity-for=8h

openshell sandbox delegated-identity status my-sandbox
openshell sandbox delegated-identity extend my-sandbox --for=12h
openshell sandbox delegated-identity withdraw my-sandbox

Related Issue

Fixes #1987

Changes

  • Added sandbox_delegated_identity as a token-exchange subject source.
  • Added sandbox delegation status, withdraw, and extend APIs.
  • Added platform-admin delegated credential list, status, revoke, and delete APIs.
  • Added openshell sandbox create --delegate-identity-for and related CLI commands.
  • Updated provider docs, sandbox architecture docs, tests, and generated Go proto bindings.

Testing

  • mise run pre-commit passes
  • Unit tests added/updated
  • E2E tests added/updated (if applicable)
  • Manual testing with different users/roles

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Architecture docs updated (if applicable)

@grs
grs requested review from a team, derekwaynecarr, mrunalp and sjenning as code owners August 17, 2026 11:01
@copy-pr-bot

copy-pr-bot Bot commented Aug 17, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@zanetworker

zanetworker commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

The --delegate-identity-for flag name makes this feel like infrastructure plumbing when it's really a trust decision. Something like --act-as-me (or something like that) immediately communicates what the user is agreeing to without requiring identity semantics knowledge.

# Current
openshell sandbox create --provider svc --delegate-identity-for=8h

# Options
openshell sandbox create --provider svc --act-as-me-for=8h
openshell sandbox create --provider svc --act-on-my-behalf-for=8h
...

@grs
grs force-pushed the delegated-sandbox-identity branch 2 times, most recently from 5cfca62 to 2c035e0 Compare August 26, 2026 14:53
Signed-off-by: Gordon Sim <gsim@redhat.com>
@grs
grs force-pushed the delegated-sandbox-identity branch from 2c035e0 to c82320f Compare August 29, 2026 13:43
@grs

grs commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

The --delegate-identity-for flag name makes this feel like infrastructure plumbing when it's really a trust decision. Something like --act-as-me (or something like that) immediately communicates what the user is agreeing to without requiring identity semantics knowledge.

@zanetworker while I understand that --act-as-me is more free of technical jargon, my concern is that the mental model it suggests is of general impersonation, while the implementation is the much narrower scoped identity delegation for token exchange (assuming that is configured separately in a provider profile in use).

Would --use-my-identity-for address your concerns? To me that feels a bit closer to the scope than --act-as-me, and could further be clarified in the help text for the flag.

@politerealism

Copy link
Copy Markdown
Contributor

Chiming in on the flag naming — "on-behalf-of" might be worth considering: --on-behalf-of-for=8h (or --on-behalf-of=8h, since it's always the creator's own identity being delegated). It's the established OAuth/enterprise-identity term for exactly this pattern (Microsoft's OBO flow, etc.), so it reads as precise and scoped to people who know the space, without implying the broader "full impersonation" connotation --act-as-me carries, or being as opaque as --delegate-identity-for/--use-my-identity-for about what's actually happening.

That said, I don't think the flag name alone can fully carry the "this is a trust decision" signal either way. Might be worth pairing whichever name wins with an interactive confirmation at creation time — something like "This lets <provider> present tokens on your behalf for 8h — continue? [y/N]" — so the caution is delivered where it actually lands, rather than trying to pack it all into the flag itself.

@grs

grs commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Chiming in on the flag naming — "on-behalf-of" might be worth considering: --on-behalf-of-for=8h (or --on-behalf-of=8h, since it's always the creator's own identity being delegated).

I do like that. It does feel as though the value should be who it's acting on behalf of though. --on-behalf-of-me-for would be clearer but perhaps a bit too long, or --on-my-behalf-for=8h maybe?

@lbelyaev

lbelyaev commented Sep 2, 2026

Copy link
Copy Markdown

Orthogonal to the flag-naming thread, but on the same "this is a trust decision" theme — two questions on the withdrawal semantics, which are new here (the exchange flow in #1970 and the design in #1987 don't cover a delegation lifecycle). Both fit the least-privilege posture #1987 already commits to, so flagging where the current behavior loosens it.

First, withdraw gates the next resolve (resolve_subject_access_token checks withdrawn_at_ms before exchanging), but a token already exchanged and held by the sandbox keeps its own access_token_expires_at_ms — so withdraw means "mint no more," not "access stops now." For an 8h delegation the effective revocation lag is the outstanding token's lifetime. Is lazy-on-next-resolve the intended contract, or should withdraw also bound the outstanding token (a short exchanged-token TTL, or a downstream revoke)? There's a separate revoke for the credential, but a delegator reaching for withdraw may reasonably expect in-flight access to stop too.

Second, handle_extend resets withdrawn_at_ms = 0, so extend both prolongs and un-withdraws — a withdrawn delegation is revived by an extend call with no separate re-authorization. If withdraw is meant to read as a revocation act, should reviving a withdrawn delegation be an explicit re-delegate rather than an extend silently clearing the flag?

@grs

grs commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Orthogonal to the flag-naming thread, but on the same "this is a trust decision" theme — two questions on the withdrawal semantics, which are new here (the exchange flow in #1970 and the design in #1987 don't cover a delegation lifecycle). Both fit the least-privilege posture #1987 already commits to, so flagging where the current behavior loosens it.

First, withdraw gates the next resolve (resolve_subject_access_token checks withdrawn_at_ms before exchanging), but a token already exchanged and held by the sandbox keeps its own access_token_expires_at_ms — so withdraw means "mint no more," not "access stops now." For an 8h delegation the effective revocation lag is the outstanding token's lifetime. Is lazy-on-next-resolve the intended contract, or should withdraw also bound the outstanding token (a short exchanged-token TTL, or a downstream revoke)? There's a separate revoke for the credential, but a delegator reaching for withdraw may reasonably expect in-flight access to stop too.

It is deliberate, mainly to keep things simple without requiring a check on every invocation. However the max time a token can be cached for can be limited through the config independently of the actual expiration on the issued token, so the 'lag' can be restricted. If you allow a token to be cached for a max of 2 minutes, say, you still get the benefit of caching and not having to check the validity on every relevant request, but you don't need to wait long before you know there will be no more requests. (If instant termination of requests is desired, probably killing the sandbox would be the first lever).

Second, handle_extend resets withdrawn_at_ms = 0, so extend both prolongs and un-withdraws — a withdrawn delegation is revived by an extend call with no separate re-authorization. If withdraw is meant to read as a revocation act, should reviving a withdrawn delegation be an explicit re-delegate rather than an extend silently clearing the flag?

That was again intentional. Withdraw is not a revocation, just an 'undo' of a previous extend. You can extend if the previous delegation has expired. Redelegating after a withdraw seems possibly desirable and it didn't make a lot of sense to me to just have another verb for that. If the admin revokes, the user cannot extend until the admin deletes the record.

Does this make sense?

@lbelyaev

lbelyaev commented Sep 2, 2026

Copy link
Copy Markdown

Orthogonal to the flag-naming thread, but on the same "this is a trust decision" theme — two questions on the withdrawal semantics, which are new here (the exchange flow in #1970 and the design in #1987 don't cover a delegation lifecycle). Both fit the least-privilege posture #1987 already commits to, so flagging where the current behavior loosens it.
First, withdraw gates the next resolve (resolve_subject_access_token checks withdrawn_at_ms before exchanging), but a token already exchanged and held by the sandbox keeps its own access_token_expires_at_ms — so withdraw means "mint no more," not "access stops now." For an 8h delegation the effective revocation lag is the outstanding token's lifetime. Is lazy-on-next-resolve the intended contract, or should withdraw also bound the outstanding token (a short exchanged-token TTL, or a downstream revoke)? There's a separate revoke for the credential, but a delegator reaching for withdraw may reasonably expect in-flight access to stop too.

It is deliberate, mainly to keep things simple without requiring a check on every invocation. However the max time a token can be cached for can be limited through the config independently of the actual expiration on the issued token, so the 'lag' can be restricted. If you allow a token to be cached for a max of 2 minutes, say, you still get the benefit of caching and not having to check the validity on every relevant request, but you don't need to wait long before you know there will be no more requests. (If instant termination of requests is desired, probably killing the sandbox would be the first lever).

Second, handle_extend resets withdrawn_at_ms = 0, so extend both prolongs and un-withdraws — a withdrawn delegation is revived by an extend call with no separate re-authorization. If withdraw is meant to read as a revocation act, should reviving a withdrawn delegation be an explicit re-delegate rather than an extend silently clearing the flag?

That was again intentional. Withdraw is not a revocation, just an 'undo' of a previous extend. You can extend if the previous delegation has expired. Redelegating after a withdraw seems possibly desirable and it didn't make a lot of sense to me to just have another verb for that. If the admin revokes, the user cannot extend until the admin deletes the record.

Does this make sense?

Makes sense on both — thanks. The configurable cache cap was the piece I was missing; that bounds the lag independently of the token's own lifetime, and killing the sandbox covers the instant-stop case. And framing withdraw as the undo of extend, with revoke as the separate admin gate, is a clean split — I'd conflated the two. Appreciate the details.

@zanetworker

Copy link
Copy Markdown
Contributor

@grs given the long discussion, I am good with "--use-my-identity-for" as an improvement from delegate-identity-for as its clear on which identity is being consumed here (the user's).

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.

feat: support user-subject dynamic token grants for sandbox agents

4 participants