Identity and secret management
Use this reference to understand how the Identity Broker validates sign-in, issues Agentweaver tokens, checks secret grants, and keeps credentials behind owner-controlled boundaries. OpenID Connect (OIDC) adds identity claims to the OAuth authorization framework. The .NET 10 Agentweaver.Identity.Broker source uses OpenIddict and owns the identity_broker PostgreSQL schema. It remains a service candidate with no published image or deployment.
The broker accepts an external OIDC provider. It validates the upstream issuer, signature, audience, expiry, and nonce before it creates a local user.
OAuth authorization codes require registered clients, exact redirect URIs, registered scopes, and S256 PKCE. Consent requires the local cookie and antiforgery token. Refresh-token replay revokes the authorization and token family.
After upstream OIDC validation, the broker creates a local subject and issues access tokens with registered OAuth scopes and resources. It does not forward upstream tenant or role claims and does not assign application roles. Projects & Config is the sole live owner of issuer-and-subject project memberships and resource-role assignments. Other resource services obtain current effective permissions through GET /api/authorization/context instead of keeping duplicate membership or role records or caches. The route uses the validated caller and returns a versioned, no-store context; token claims and tenant selectors cannot create authority. Grant-validated project_id and run_id are included only for tokens bound to that exact project and run.
sequenceDiagram
actor User
participant IdP as Configured OIDC provider
participant Broker as Identity Broker
participant API as Resource API
participant Projects as Projects & Config authorization owner
User->>IdP: Authenticate
IdP-->>Broker: Validated upstream identity
Broker->>Broker: Replace upstream subject with local broker subject
opt Projects-owned project/run authorization
Broker->>Projects: Private TLS 1.2/1.3 signed proof request for actor and exact project/run
Projects-->>Broker: Current membership, Orchestrator assignment, and accepted-selection receipt
end
Broker->>Broker: Apply registered scopes and resource audience
Broker-->>API: Signed access token (sub, scope, audience, optional project/run binding)
API->>API: Validate issuer, signature, lifetime, and audience
API->>Projects: GET /api/authorization/context with caller token
Projects-->>API: Effective permissions, contract v1, Cache-Control: no-store
API->>API: Authorize this request; keep no membership or role cache
Note over API,Projects: Each privileged request obtains fresh owner context; no authorization pins are issued.
Note over Broker,Projects: Broker verifies the Projects chain, hostname, server purpose, validity, and exact leaf pin; redirects are disabled
Open full-size PNG · Open editable draw.io source
The broker issues project_id and run_id claims through one of two authorization paths. A secret-grant binding requires an active grant for the authenticated local user. A Projects-owned binding instead requires a private, no-store receipt for the active project, current actor membership, active Orchestrator assignment, and matching accepted run selection. The Projects proof is repeated when authorization resumes and during token exchange and refresh; the broker rejects a changed receipt. The secret-grant path separately rechecks its active run binding during token exchange and refresh. These paths are alternatives: a Projects-owned binding does not also require a secret grant. The short-lived service token uses a separate audience; its receipt does not become a role claim. Project/run claims constrain a request to the exact signed binding; they do not grant a project role. Projects & Config owns its issuer-and-subject memberships, resource-role assignments, and immutable authorization audit in projects_config. Its runtime database principal can read but cannot insert, update, or delete those records; provisioning and revocation use a separate privileged source path.
The Broker owner call uses IdentityBroker:RunBinding:ProjectsOwnerAddress and IdentityBroker:RunBinding:ProjectsAudience. The corresponding ProjectsConfig:Authentication:BrokerRunBindingAudience is a separate HTTPS audience. Configuring it maps only the private proof route; it does not replace the public Projects bearer audience.
Internal owner HTTPS clients validate server certificates against the read-only service-backend-ca mount at /var/run/service-backend-ca/ca.crt. RuntimeOwnerHttpTransport supplies the bounded owner-request handler; Environment's RuntimeSandboxHttpTransport retains direct-to-Pod-IP routing for bootstrap and sandbox calls while validating the TLS hostname and the same backend CA. RuntimeServiceTlsIdentity adds custom-root chain validation to pinned mTLS owner clients while retaining hostname checks, the configured peer leaf pin, server-authentication purpose, the client certificate, and online revocation checks. Public issuer discovery and external HTTPS providers continue to use normal system trust.
Projects & Config accepts hosted catalog publication only when the request carries both the caller's bearer and AgentHost's client certificate. Its optional ProjectsConfig:HostedModelCatalogPublication:AgentHostCertificateSha256 setting pins the AgentHost leaf; the listener validates its chain against the mounted backend CA, client-auth purpose, validity, and revocation. AgentHost sends its existing service certificate only on the publication client. Without the pin, publication is denied; a project reader's bearer alone cannot publish values.
When run binding is configured, Broker requires ProjectsTrustBundleSha256, the SHA-256 of the exact raw UTF-8 PEM bytes at /var/run/service-backend-ca/ca.crt. This path is fixed; the host accepts no configurable trust-bundle path. The bundle must contain CA certificates only. ProjectsServerCertificateSha256 pins the SHA-256 of the Projects leaf certificate DER bytes. Broker checks the custom-root chain, HTTPS hostname, current validity, server authentication purpose, and exact leaf pin; it rejects redirects. Projects requires absolute certificate and key paths and ProjectsConfig:Tls:ServerCertificateSha256 when its private audience is enabled. It accepts the private proof request only after a native TLS 1.2 or TLS 1.3 handshake. Forwarded HTTPS headers alone do not satisfy this check.
POST /secrets/redeem accepts a SecretRef identifier and exact version, purpose, and run ID. The bearer token supplies actor, project, and run claims. The broker does not accept caller-supplied identity claims.
AuthorizedSecretRedemption checks the exact grant before and after backend acquisition. A changed, expired, revoked, missing, or ambiguous grant denies redemption. The broker invalidates an acquired credential after the response.
The Key Vault adapter uses an injected credential or explicit WorkloadIdentityCredentialOptions. The AKS composition requires tenant ID, client ID, and an absolute projected token-file path. It has no DefaultAzureCredential fallback.
The adapter requests the exact Key Vault version. A returned credential expires within five minutes or at the earlier vault expiry. The grant store keeps references and binding snapshots, not secret values.
No secret-redemption grant-management HTTP endpoint exists. Read contracts and endpoints for the implemented route list and Identity host configuration for host keys. See the planned runtime configuration reference for runtime setting guidance.
Remote MCP OAuth source boundary
The Broker source candidate defines an Identity-owned connection binding. The binding includes the authenticated human, tenant, project, stable connection ID, Environment configuration revision and digest, and opaque Identity binding reference. It also includes the canonical HTTPS endpoint and resource, issuer, client ID, redirect URI, installed MCP transport profile, and canonical scopes. Each provider configuration also names the exact approved resource URIs, OAuth endpoints, and scopes. Consent state binds that snapshot and its connection revision to a short-lived correlation ID. It stores only a hash of the random state, the S256 challenge, and a protected verifier SecretRef identifier/version. It does not persist the raw state, verifier, access token, or refresh token. Connection credentials are represented only by protected secret references and provider expiry metadata.
The lifecycle state transitions cover single-use callback claiming and completion, binding and expiry checks, refresh-attempt and credential-revision compare-and-swap outcomes, and disconnect/revocation state. The Broker source implements these transitions through its bearer-authenticated, no-store status, consent-preparation, callback, refresh, and disconnect paths; the source does not establish deployment or a project-settings consent-start flow. These paths recheck the owner's current Projects authorization and the current Environment configuration. Consent preparation links Identity's opaque reference to the exact Environment revision and digest, re-reads that pin, then fetches metadata only for the exact configured resource and issuer. It rejects redirects, bounds metadata responses, and validates the resource, issuer, scopes, S256/code profile, and exact operator-approved OAuth endpoints. It returns a constructed authorization URI and stores only a protected verifier reference and correlation state. The web application uses a same-origin popup callback page to relay either the code or the bounded access_denied result to its opener. The Gateway forwards only that callback shape with the current user's bearer to Identity. Identity rechecks the current provider client, redirect, resource, and scope approvals, Projects authority, and Environment configuration, then claims the callback once and redeems the protected verifier. Identity exchanges only a code at the metadata-approved token endpoint and closes a provider-cancelled consent without treating it as authorization. It stores returned access and refresh tokens only as protected SecretRef versions and publishes them with connection and credential revision checks. A timeout or secret-store failure after a possible provider request resolves the callback claim as uncertain rather than making the code reusable. Projects authorization and Environment configuration use separate configured owner addresses; Environment requests are not routed through Projects. Status redacts credential references and always reports credential use unavailable. Disconnect requires the expected connection, credential, and configuration revisions; it clears the stored references through a revision-guarded update, but does not delete secret versions or revoke tokens at the provider.
Refresh requires expected connection, credential, and configuration revisions. Identity claims a durable refresh lease before redeeming the exact refresh-token version. It rechecks Projects authority and the Environment binding after each provider or secret-store wait, then commits new SecretRefs with a revision compare-and-swap. Provider rejection clears local credentials and marks the connection revoked. A timeout, store failure after provider exchange, or stale lease after restart marks the connection indeterminate. The provider's refresh token consumption status is unknown, so Identity does not retry the token.
The Identity package also validates supplied protected-resource and authorization-server metadata against the bound resource, issuer, requested scopes, S256/code profile, and an explicit endpoint list. It can construct the corresponding authorization URI from the bound redirect/resource/scopes and short-lived PKCE material. These helpers perform no discovery HTTP, do not grant authority to the endpoint list, and are not called by a browser redirect route.
The web client has a typed management API and a callback relay, but no project settings flow yet starts consent or owns the pending connection state. Provider revocation and purpose-bound credential delivery to MCP requests are not wired in this source slice. The separate IdentityBroker:RemoteMcpCredentialUse:Tls source profile is disabled when absent. When configured, it requires the RemoteMcpCredentialUse Kestrel HTTPS listener with its own port. It uses the existing RuntimeServiceTlsOptions and RuntimeServiceTlsIdentity types, with local service IdentityBroker and peer service Environment. Explicit existing principal IDs map these services to configured certificate hashes and peer pins. The profile requires existing absolute certificate and key paths; it does not issue certificates or create identities.
Kestrel requires a valid client certificate with chain and revocation checks. The recipient gate requires the native TLS handshake, exact listener port, Environment peer pin, certificate validity, and client authentication purpose. It runs before request-body or credential access. The profile uses the separate remote-mcp-credential-use-recipient service key; an ordinary HTTPS bearer or another service's TLS profile cannot select the Environment role. Incomplete configuration or a port shared with another endpoint prevents startup.
This listener source does not map a credential-use route or enable credential delivery. Current exact-call, journal, Identity revision, and applied-network checks remain required before that route can be connected. The existing Orchestrator and Events result profiles are unchanged.
Environment's inverse profile is Environment:RemoteMcpCredentialUse:IdentityTls, with local service Environment and peer IdentityBroker. It requires its own Kestrel:Endpoints:RemoteMcpCredentialUse:Url port and uses key remote-mcp-credential-use-identity. Client RemoteMcpCredentialUseIdentity pins Identity's owner address and has a 15-second timeout. The same native peer gate can protect a future read-only Environment verification route for Identity; this source does not map that route.
Hosted model catalog credential reads use a separate IdentityBroker:HostedModelCatalogCredentialUse:Tls profile and the HostedModelCatalogCredentialUse HTTPS listener on port 8444. The peer is AgentHost; the corresponding client profile is AgentHost:HostedModelCatalogCredentialUse:IdentityTls. Both services pin the other service's certificate and use distinct service principals. The AgentHost certificate must have client-auth and server-auth purposes; Identity requires a client-auth certificate from that exact AgentHost profile. The Identity listener certificate is mounted from the optional identity-broker-agenthost-tls Secret at /var/run/identity-broker-agenthost-tls; its address is https://identity-broker.agentweaver.svc.cluster.local:8444/. AgentHost uses its mounted /run/agenthost-tls certificate and the service backend CA at /var/run/service-backend-ca/ca.crt.
Only POST /internal/connections/copilot-user/{connectionId}/model-catalog-credential uses this channel. The route checks mTLS before reading the request or redeeming a connection credential, then applies the current caller, tenant, project, connection, and freshness checks. The caller's bearer token alone is not enough. Identity returns the short-lived user access token only to AgentHost; Gateway and browser routes do not proxy this response. When the profile is absent the listener cannot authorize credential use, and incomplete or shared-port configuration prevents startup. The Identity listener validates AgentHost's client certificate against the mounted backend CA before enforcing its configured leaf pin. Issue Sync, hosted catalog, and Remote MCP listeners load the shared Kestrel endpoint configuration once, then apply their separate certificate and mTLS settings.
Only Environment has the separately configured Orchestrator verifier client. Identity has no Orchestrator client. Current call and applied-network verification before and after credential reads remain required from the trusted Environment owner. These profile registrations do not establish that verification or enable credential use.
RemoteMcpOAuthCredentialUseBinding is a pure Identity row helper. It selects the current exact access-token SecretRef and fixes the purpose to remote-mcp-tools-call-access-token for the reviewed POST tools/call. It requires authorized state, valid revisions, an unexpired token, and exact owner, connection, configuration, resource, and binding-hash checks against the call proof. It compares current row authority before and after a wait and rejects changes. It does not authenticate a caller, read a secret, or grant credential delivery. The current Environment acknowledgment still has no forced-network evidence. No credential endpoint is connected; backend reads and delivery remain unavailable.
No deployed OAuth consent or remote MCP credential use is established. The following flow describes the implemented management and callback boundary:
sequenceDiagram
actor Human
participant Broker as Identity Broker
participant Projects as Projects authorization owner
participant Environment as Environment configuration owner
participant MCP as Remote MCP server
participant IdP as Configured OAuth issuer
Human->>Broker: GET status or POST consent/refresh/disconnect
Broker->>Broker: Resolve connection owned by authenticated subject
Broker->>Projects: Recheck current ReadProjects or WriteProjects authority
Projects-->>Broker: Current project authority
Broker->>Environment: Read current connection snapshot and immutable configuration
Environment-->>Broker: Current configuration revision and pins
alt Consent preparation
Broker->>Environment: Link opaque Identity reference with revision and digest CAS
Environment-->>Broker: Final immutable revision, digest, and receipt
Broker->>Environment: Re-read final revision and current head
Environment-->>Broker: Confirmed binding pins
Broker->>MCP: Fetch protected-resource metadata without redirects
MCP-->>Broker: Resource and approved authorization-server issuer
Broker->>IdP: Fetch issuer metadata without redirects
IdP-->>Broker: Exact approved endpoints and S256/code profile
Broker->>Broker: Build authorization URI; persist state hash and protected verifier reference
Broker-->>Human: Authorization URI; caller controls browser navigation
else Callback with code and state
Web-->>Web: Same-origin popup relay; clear callback query
Web->>Gateway: Send only code and state with current bearer
Gateway->>Broker: Forward exact callback body and bearer
Broker->>Broker: Claim correlation; recheck authority and configuration
Broker->>IdP: Exchange code with PKCE verifier and exact resource/redirect
IdP-->>Broker: Access and optional refresh token response
Broker->>Broker: Write protected secret versions; commit only current binding by CAS
Broker-->>Web: Redacted owner status
else Disconnect with expected revisions
Broker->>Broker: CAS connection and credential revisions; clear SecretRefs
Broker-->>Human: Disconnected status; no credential-use authority
else Refresh with expected revisions
Broker->>Broker: CAS durable refresh lease
Broker->>Projects: Recheck current WriteProjects authority
Broker->>Environment: Recheck exact configuration revision and resource
Broker->>IdP: Exchange refresh token at the approved token endpoint
IdP-->>Broker: New access and optional rotated refresh token
Broker->>Broker: Store protected SecretRefs and CAS current claim
Broker-->>Human: Authorized status or explicit indeterminate result
else Status
Broker-->>Human: Redacted status; credential use unavailable
end
Note over Broker,Environment: Optional separate TLS listener pins Environment as the recipient
Note over Broker,Environment: Inverse owner client pins Identity; only Environment has the separate Core verifier client
Note over Broker: The row helper selects an exact access-token reference; it does not read or deliver a token
Note over Broker,Environment: Credential-use route, provider revocation, and deployed behavior remain unavailableGitHub connections are separate integrations
Core sign-in, GitHub Copilot credentials, and GitHub App repository credentials have different owners and purposes. Broker OAuth refresh does not refresh a GitHub Copilot credential. A GitHub App installation token cannot authenticate the Copilot SDK.
| Integration | Current source boundary | Missing work |
|---|---|---|
| Core sign-in | Broker OIDC, OAuth, consent, refresh, and purpose-bound secret redemption exist. | These contracts do not supply either GitHub connection lifecycle. |
| GitHub Copilot | Identity implements owner-bound account linking, PKCE/cookie callbacks, exact-version writes, refresh rotation, and current binding checks in source. The SDK consumes only the current user access token. | Deployed OAuth, writer permissions, and live entitlement are not proven by source tests. |
| GitHub App | Identity owns the Repo App user connection, installation/repository selection, refresh, and exact-repository token mint for run operations and explicit project team sync. | A reachable settings UI and deployment are not part of this source. The Web and MCP connection surfaces are still missing. |
| Web and MCP | Existing core routes and tools are implemented. | Reachable retained settings and real GitHub connection and repository routes in Web and MCP. |
The compatible 0.x Copilot flow binds browser state, PKCE, cookies, and a single-use callback to the current subject. Its refresh path serializes redemption, rotates refresh tokens, and uses version checks. Provider rejection can require reconnect; a transient failure must not fabricate that result.
Identity implements the GitHub App producer in source. User authorization uses OAuth S256 PKCE, an owner-bound state and protected verifier, and a short-lived HttpOnly callback cookie. Installation setup uses its own owner-bound single-use callback. Identity discovers only installations and repositories visible to the connected user. A returned selection code is short-lived and is submitted either in the initial run-scoped Orchestrator /pin request or to the internal project team-sync token request. It is never stored in accepted Project/Run configuration or a durable Source Control pin. Identity stores only its hash and binds its first accepted use to one owner and project. Later run-bound minting is limited to that project and uses the stored hash; project team-sync minting rechecks the same project and repository binding.
The Copilot source flow is not deployed login, writer permission, or paid-execution authority. The separate GitHub App and browser integrations retain their own delivery and acceptance boundaries. Accepted narrow source contracts remain accepted. Automatic webhook delivery and workflow triggers also need a separate service-identity scope decision; the current human-authenticated relay does not prove that parity. Identity stores rotating OAuth token references and provider expiry metadata, not token values. Refresh is serialized by a database lease and credential-revision compare-and-swap. Provider rejection marks the connection revoked; an uncertain rotation locks the connection instead of retrying a possibly consumed refresh token. Before token mint, Identity rechecks the active actor/project/run grant, exact connection revision, installation and repository, and current provider discovery. It redeems the exact GitHub App private-key SecretRef for the bound run, signs the App JWT in memory, and requests an installation token for exactly one repository with contents:write and pull_requests:write. It requests issues:write only when the pinned provider needs issue creation. IssueWriteGranted is true only when GitHub's returned permission map confirms issues:write; a requested but ungranted permission fails closed, including an explicit provider rejection, without a narrower retry. Permission digests derive from the actual returned map, remints preserve the immutable pinned scope, and GitHub's expiry and returned permission set are authoritative. The private key and installation token are never stored in PostgreSQL. The Orchestrator receives the token only for the current operation and invalidates it afterward; later operations repeat Identity's binding and permission checks.
Explicit team sync uses a separate project-scoped mint path over the existing certificate-pinned service channel. Identity rechecks the current project-owner proof, Repo App connection, installation, repository, and selection before minting. The token has only contents:read for a repository read or contents:write for a reviewed commit; it does not include issue or pull-request permissions. The token is returned only to Orchestrator over the internal channel, is never returned to a caller, and is invalidated after the bounded GitHub operation.
The browser integration uses one configured HTTPS Web origin. When GitHub Repo App support is enabled, IdentityBroker:WebOrigin is required and is the only origin allowed to send credentialed requests to the Broker's browser OAuth and Repo App fetch routes. CORS preflight is handled before authentication; owner authentication, antiforgery, and callback-cookie checks remain unchanged. Internal token redemption, runtime, health, and diagnostics routes are not browser CORS surfaces. The Broker's GitHub callback URI stays on the Broker origin, and successful completion redirects to the fixed Web settings path. The Gateway uses the same explicit Web origin but remains bearer-only and does not accept cookie credentials.
These source routes and tests do not establish deployment of the Broker, settings surface, GitHub App, Key Vault writer permissions, or any cloud service. The connection does not create a Projects role, broaden OAuth authority, or enable paid execution. Automatic public webhook delivery and workflow triggers still require a separate service-identity scope decision; the current human-authenticated relay does not provide that authority.
Minimum Copilot credential writer source scope
The approved minimum source work adds protected secret-version writes inside the existing Key Vault adapter and trusted Identity lifecycle. It returns opaque SecretRef metadata, not token values. Identity stores connection identity, credential kind, owner and revision, freshness, state, and the current secret-version reference. Tokens remain in the protected secret store and runtime memory, never raw PostgreSQL columns.
The approved selection-contract repair uses explicit SourceMode and a stable ConnectionId for a hosted platform/project binding. The ID is a reference, not authority. Trusted Identity facts and the current Core selection must establish the owner, domain, credential kind, freshness, and revocation state under existing sharing rules. This adds no personal-provider precedence or blanket credential sharing.
Each ModelSession receipt and redemption pins the current connection revision, exact secret version, grant revision, and credential kind. Normal token rotation advances those owner-controlled revisions without changing the accepted selection or its hash. Fresh proof is required after remote waits and before SDK consumption. Stale receipts deny or require legitimate current refresh; caches cannot supply authority. A change of owner, kind, scope, or GitHub identity requires an authorized new binding or selection. Legacy stored selections remain unchanged, and unsupported hosted selections require an explicit migration-required or unavailable result until a new selection is authorized. No automatic migration or hash rewrite occurs. Exact CredentialReference remains BYOK-only.
The owner claims refresh before upstream rotation. After writing a new secret version, it rechecks current authority and publishes the reference through its PostgreSQL revision compare-and-swap. Azure secret writes are not an atomic connection-state CAS. A failed write, revoked authority, or lost CAS must not report a new current credential. Interrupted rotation requires an explicit recovery outcome; unreferenced versions are not permission for automatic cloud cleanup.
This source scope is not deployed writer authority. Existing P0 Key Vault Secrets User assignments remain read-only and unchanged. A deployed writer needs secret SET/new-version, exact-version GET, and metadata rights at the actual configured credential-store scope. The exact supported role or custom actions and bootstrap scope must be verified with the separately approved live proposal. Do not default to the broader Secrets Officer role or assume secret-prefix RBAC. Missing writer support or permissions must return an explicit unavailable or denied result before hosted SDK use, without raw token fallback.
Separate runtime credential candidate
Runtime configure and observe grants use a separate Identity-owned store. They do not widen secret redemption, OAuth claims, or project roles. The optional Broker owner routes require a validated bearer and an independent cryptographic nonce bound to the exact runtime registration, purpose, audience, and expiry. OpenIddict supplies expiry through its validated principal metadata.
Identity captures only a verifier before database waits. After the grant lock is acquired, it checks the exact stored binding and fresh owner authority. Expiry or authority loss after that verified proof records immutable revocation before denial. An already-expired input is rejected without claiming a verified nonce or durable cleanup. Audit tables permit only SELECT and INSERT; grant heads also permit CAS updates.
The auth-first SDK hook consumes a delivered configure nonce before session creation. It takes the model reference from the current registration and rechecks source and owner authority after SDK awaits. The registration candidate also pins the exact Environment provider, lifecycle generation, lease revision, and lease-bounded expiry. After SDK preparation, the hook compares the current registration, verifies the observe grant, and checks lifetimes and cancellation immediately before session.create. The hook performs no asynchronous owner lookup after that final grant verification. These pins do not give a run-bound token public project-write authority.
The combined local harness uses actual Broker OAuth, current Core membership and roles, accepted Projects selection, Environment lease/profile, native SDK callbacks, and Events accounting. It controls only external placement and SDK transport, catalog, and pricing inputs. Revocation before SDK preparation produces zero SDK requests and source records. Grant revocation, expiry, or Environment retirement during SDK preparation produces zero native session creations, source records, and accounting entries. Authority loss during source transaction waits denies the observation without accounting. This evidence does not prove cloud deployment or paid model execution. See the runtime credential source contract.
Credential-less Sandbox proposal
Status: proposed design, not implemented or deployed. Credential-less means that untrusted sandbox code cannot obtain real upstream credentials. Examples include model keys, Copilot access tokens, Git credentials, Azure bearer tokens, refresh tokens, private keys, and equivalent exchangeable cloud assertions. A SecretRef that the guest can redeem is not credential-less. Neither is federation that gives the guest an upstream bearer token without a stored secret.
The current AgentHost consumes a model credential in the native SDK inside the Sandbox. That source remains a separate legacy credential-delivery path; its guarded tools, private state, and credential-free process environment do not establish this stronger boundary. The existing diagrams describe the Identity source, not the proposed guest boundary.
Trust boundary and placement
The trusted outbound gateway is an implementation of the existing L7 Network Policy layer and Tool & MCP mediation role, not a new identity service or the browser Gateway/BFF's arbitrary upstream proxy. Identity still owns credential sourcing, connection lifecycle, and exact-version redemption through ISecretRedemption / AuthorizedSecretRedemption. Projects & Config owns live membership and roles; Orchestrator owns current actions, Policy receipts, runtime registration, and execution fences. Environment owns placement, network intent, leases, and readiness. Credential sourcing and permission to perform an outbound effect are separate checks.
Untrusted code includes guest shell commands, tools, dependencies, repository content, and any guest SDK process. The trusted gateway, Identity clients, token caches, and any credential-consuming native runtime must be outside that guest's security boundary. Use the existing remote-service or in-process provider hosting patterns in a trusted host. A sidecar is acceptable only where the provider proves independent isolation from guest code. Two containers in one Kata Pod normally share one guest VM; a second container is not a second VM. Container names, different UIDs, private HOME, or read-only mounts alone do not prove that credentials are inaccessible.
Environment admission must prove that the guest cannot read trusted host/gateway state. This includes process memory, private HOME, token caches, credentials, signing or TLS private keys, service sockets, host paths, shared private volumes, and snapshots of that state. Do not expose workload-identity projected assertions, Kubernetes service account tokens/API access, IMDS/metadata endpoints, or cloud token exchange to the guest. A workspace shared for authorized file operations carries data only, never host state or credential helpers. Treat its contents as hostile on the trusted side. Snapshots and SDK-cache export cannot include credential-bearing state; disable that export for a mode that cannot prove safe separation.
The guest uses a low-authority gateway identity, separate from owner/service tokens and upstream credentials. Bind it to one current runtime registration, tenant/project/run/session, placement generation, execution fence, gateway audience, expiry, and allowed operation profile. Prefer provider-attested transport identity or sender-bound proof verified outside the guest; the gateway does not trust a source IP or guest-supplied identity header. A guest-held proof can be copied by hostile guest code, so sender binding is not a claim that a guest private key is unextractable. Enforce the registered placement/channel, replay protection, and current authority as well. The proof cannot authenticate to upstreams, redeem secrets, exchange for owner tokens, configure another runtime, or gain public WriteProjects. Replaying it from another placement or session must fail. It still permits misuse of operations actually authorized to that guest; it is not a secret-free assertion that the guest has no authority.
Authorized request flow
Prefer a structured gateway operation for a bound model, repository, Azure resource, or connection over accepting an arbitrary URL. The gateway resolves the upstream route and credential from trusted owner state.
sequenceDiagram
participant Guest as Untrusted guest
participant Gateway as Trusted outbound gateway outside guest
participant Owners as Projects / Orchestrator / Environment
participant Identity as Identity and Secrets provider
participant Upstream as Approved upstream
Guest->>Gateway: Bound operation, input, operation ID, gateway-only proof
Gateway->>Owners: Validate current actor, action, selection and placement fences
Owners-->>Gateway: Current authority and committed Policy admission
Gateway->>Gateway: Validate destination, request and upstream TLS peer
Gateway->>Identity: Acquire credential for exact accepted connection and purpose
Identity->>Identity: Check current grant before and after acquisition
Identity-->>Gateway: Short-lived credential for trusted use only
Gateway->>Owners: Recheck current authority and bindings after waits
Owners-->>Gateway: Same authorized action and current fences, or deny
Gateway->>Upstream: Insert authentication outside guest; send validated request
Upstream-->>Gateway: Response or bounded stream
Gateway->>Gateway: Apply response contract and remove credential exposure
Gateway-->>Guest: Authorized data and credential-free operation receipt
Note over Gateway,Identity: Any failed postcheck invalidates acquired credential and prevents dispatchAuthenticate first, then obtain fresh GET /api/authorization/context and the current Orchestrator action/registration and Environment lease evidence through their existing owner contracts. The gateway uses an admitted trusted runtime/ actor delegation derived from authenticated enrollment, not its administrator identity or a guest-supplied subject. That delegation stays outside the guest; missing owner-route support fails explicitly without impersonation or broader service grants. Validate input and destination before acquiring credentials. Resolve and validate the upstream TLS connection; any connection, DNS, credential, policy, or owner wait requires fresh binding/authority checks before authentication insertion and dispatch. Identity's post-acquisition grant check does not replace the gateway's action and placement postcheck. No saved allow list, admission receipt, or token cache is fresh authorization by itself.
Freeze the validated method, route, resource, body hash, operation ID, and binding for dispatch. Do not accept new bytes or follow a new destination after the final check. Fail closed on missing, ambiguous, changed, revoked, expired, or unavailable authority. This follows existing owner/action fencing, not a new cross-service atomic transaction: revocation cannot undo an upstream effect already sent. On reconnect, retry, each new WebSocket operation, and each model turn, repeat authorization. Long streams have bounded lifetimes and current grant/lease checks; revoke, expiry, cancellation, or failed checks stop forwarding and close the channel. Do not claim instantaneous rollback of in-flight bytes.
Connection and action mapping
An accepted reference identifies a connection; it does not authorize one. The server-owned mapping must include the following facts, with revisions supplied by their current owners rather than trusted from guest JSON:
| Bound facts | Required decision |
|---|---|
| Actor issuer/subject, tenant, project, run, session, agent and turn | Intersect current Projects authority, registered session/work item, and signed run constraints. A tenant selector or guest action label cannot choose another user. |
| Accepted selection reference/hash and project/configuration/platform revisions | Use the immutable accepted model/repository/connection selection; do not rewrite hashes or choose a fallback credential. |
| Runtime instance/registration revision, execution fence, Environment lifecycle and provider/current fences, lease revision/expiry, placement/resource generations, applied network-intent generation | Require the exact current active resources and negotiated protocol profile before and after waits. A previous generation cannot dispatch through a replacement gateway or placement. |
| Connection ID/revision, credential kind, sourcing provider, exact SecretRef version where applicable | Identity resolves the current authorized connection under its existing sharing rules. The guest cannot choose an arbitrary secret or supply a token. Rotation follows the owner revision without silently changing accepted scope. |
| Upstream audience, minimum scopes/permissions, destination scheme/host/port, method, route/resource, operation and action purpose | Derive from a platform-enabled, project-narrowed operation profile. Validate request data as well as the URL: an allowed POST endpoint can still carry a forbidden resource or operation. |
| Delegated user identity versus application/workload identity | Require the configured mode and its separate consent/resource permissions. An app credential is not proof of user delegation; do not substitute a broader app identity when delegated access fails. |
Reuse RuntimeActionRequest / RuntimeActionAdmission and the current AGT guard for model.turn and existing tool/execution admissions. The current action ID set does not describe arbitrary GitHub or Azure effects. Extend the owning typed tool/Source Control operation contract only for an admitted operation and bind its resource, input hash and permission to the existing action/Policy receipt. An exec.shell grant alone must not authorize all upstream operations of a shell script. Source Control approval and merge guards still apply. Provider-returned permissions/audiences must match the request; unexpectedly broader tokens must not be used as a convenient fallback.
Supported protocols and SDK limits
These are proposed profiles, not a claim of current transparent-proxy support. One header-injection proxy cannot safely support every authentication protocol.
| Operation | Credential-less path and limits |
|---|---|
| Model HTTP, streaming and WebSocket | Bind the model, approved endpoint/API, input and model.turn admission. Inject headers only on the validated upstream connection; bound streaming frames, backpressure, cancellation, reconnect and lifetime. Each new operation on a socket needs its own action admission; opening a socket is not permission for later turns or tools. |
| Hosted Copilot SDK | SDK 1.0.18 currently receives the real token through Models.ListAsync(gitHubToken: ...) and SessionConfig.GitHubToken over native RPC. An authenticated UriRuntimeConnection.ConnectionToken secures SDK transport; it does not replace Copilot authentication. Empty mode disables ambient login, not session-token delivery. Do not pass an upstream token, redeemable reference, or pretend Copilot token into a guest runtime and call it injection. |
| BYOK SDK | RuntimeByokProvider.ToSdkProvider currently puts the key in ProviderConfig.ApiKey with explicit BaseUrl, wire API and optional headers. A gateway base URL alone does not prove that this SDK mode avoids credential consumption or direct egress. Validate the exact SDK/native pair's supported authentication and routing before admission. |
| Git smart HTTP/HTTPS | Map the exact repository and Git service: authorized info/refs service discovery, git-upload-pack reads, and separately admitted git-receive-pack writes. Check repository/ref/write restrictions through Source Control, not just HTTP method. Use an admitted gateway endpoint or protocol adapter; guest credential helpers must never receive a GitHub token. Handle challenges and redirects inside the trusted adapter, not via a raw redemption route. |
| GitHub API tools | Use typed, resource-bound tools through Source Control or the existing Tool & MCP role. Identity mints only the accepted installation/repository permissions. An API route that returns credentials or changes connection authority is not an ordinary repository tool. |
| Azure SDK HTTP | Bind the exact cloud, service audience and resource/action. ARM, Storage, Key Vault and other services have different token audiences; the guest cannot request arbitrary TokenCredential.GetToken scopes. SDKs that demand a real bearer token or signed request need trusted-side SDK execution or a specifically validated mediated transport, not a guest DefaultAzureCredential fallback. Challenge handling must stay within the admitted audience. |
| Generic HTTP broker-backed connection | A reviewed connection profile maps protocol, destination, authentication and operation semantics. Inject only its credential, with bounded request/response rules. Unknown endpoints, token-returning APIs, or opaque operations that cannot be checked are unsupported, not a blanket HTTP tunnel. |
| Git SSH, mTLS, pinned TLS, non-HTTP signing or authentication | Require a trusted protocol adapter holding keys and signing material outside the guest, with equivalent resource/action checks, or return explicit unsupported capability. A generic HTTP proxy cannot promise SSH signing, mTLS client-key isolation, TLS-pin compatibility, or safe credential injection into opaque encrypted traffic. |
For an incompatible SDK mode, admit a trusted model-runtime adapter outside the guest through the existing AgentHost library and the same Copilot harness, registration, action checks and observation contracts. It consumes credentials there and returns only authorized native responses, tool requests and result data. Guest file/shell operations cross a narrow guarded bridge; the trusted SDK must not execute hostile workspace code in its own credential-bearing process. This is a proposed placement/profile split, not current remote-runtime support. If the exact SDK mode cannot preserve that separation, admission returns CapabilityUnavailable (or an explicit unsupported runtime capability), with no credential-delivery downgrade.
Preserve native session/model identity, SDK/runtime versions, abort/idle behavior, typed tool results, usage events, and the existing receipt identities. Cancellation uses the native abort/idle contract. A failed abort prohibits another turn or cache capture. Events remains the sole financial ledger. Forward actual Copilot AI credits and SDK 1.0.18 TotalNanoAiu through Orchestrator source receipts and the existing Events acknowledgment. Do not multiply weighted nano-AIU again or infer cost from Gateway bytes. Do not add a Gateway ledger. Keep existing deny-new-dispatch behavior at the observed turn boundary and current delivery semantics. No all-future-source accounting-completeness gate is added here.
Network, TLS and hostile input
The selected L3/L4 provider must force credential-bearing traffic through the admitted L7 gateway: default deny, exact gateway/control-route access, controlled DNS and no direct protected upstream access, even without HTTP_PROXY. Enforce both IPv4 and IPv6, alternate ports, UDP/QUIC, IP literals, proxy chains and CONNECT tunnels. Unmediated credential-free destinations, if separately allowed, must not provide a route to a protected upstream or credential-returning broker. Direct credential acquisition endpoints stay denied. Guest DNS choices or NO_PROXY cannot change enforcement. No host networking, privileged guest network changes, escape sockets, or permissive fallback when a layer fails.
At the gateway, normalize URLs once; reject user-info, alternate encodings, ambiguous paths, duplicate/conflicting authentication headers, and mismatches between operation, URL, HTTP authority/Host and TLS SNI. Never trust a guest-supplied header as an identity assertion. Build upstream Host/SNI and authentication from the validated profile; reject guest Authorization, Proxy-Authorization, API-key, identity-forwarding and connection-specific credential headers instead of forwarding or merging them. Strip hop-by-hop headers and reject ambiguous HTTP framing/request smuggling. Bound bodies, headers, decompression, frames, concurrency and timeouts; parse resource/action selectors before a protected effect. Reuse upstream idempotency only where supported. An uncertain external write is an explicit unresolved outcome, not permission for a blind retry.
Resolve DNS on the trusted side and validate every resolved address against the profile and restricted ranges, including loopback, link-local, private networks, metadata and Kubernetes/control endpoints. A private upstream needs an explicit resource-specific mapping, not blanket private-CIDR access. Connect to the validated address while verifying TLS against the approved hostname; do not reresolve after validation without another check. Apply the same rules to reconnects. Reject redirects by default. Any profile that admits a redirect requires independent destination, audience and action validation, with fresh authentication for that target; never forward the old credential automatically.
Validate upstream certificates, hostname, and approved trust roots. Never disable TLS verification. Prefer structured endpoints to TLS interception. If a reviewed SDK/protocol profile requires interception, terminate only that profile's allowed hosts/protocols with a narrowly scoped trusted CA certificate installed in the guest. Keep its CA signing key and per-host private keys outside the guest. The guest authenticates the gateway separately, and the gateway independently validates upstream TLS. A broad trust root does not make arbitrary interception authorized. A pinned client must use a supported explicit endpoint/adapter or fail admission; mTLS client certificates and keys stay on the trusted upstream leg. This proposal does not select Nginx or any new proxy product.
Responses expose approved data, not upstream authentication state. Allow list response headers and operation schemas; do not return bearer challenges with secrets, auth cookies, signed credential URLs, token exchange results, or credential-minting responses. Reject known injected credential reflection in decoded bodies/stream frames and headers, including protocol-supported encoded forms; sanitize errors before forwarding. Text redaction alone cannot prove an arbitrary malicious upstream will never encode a token. Admission therefore requires a trusted upstream and a reviewed response contract; unsupported opaque or credential-returning operations fail closed. This boundary protects broker-managed credentials, not every secret a user puts into allowed data.
No credentials or request authentication bytes enter receipts, logs, traces, error strings, crash dumps, exported SDK caches, workspace files or snapshots. Record safe operation IDs, binding revisions, admitted resource references, Policy/source receipt references, outcomes and sanitized error codes through existing owners. Do not log entire URLs, headers or bodies as a shortcut. Streaming inspection must not buffer/log secrets or silently corrupt native results; reject an unsafe response explicitly.
Lifetime, revocation and trusted-host limits
Credential expiry is bounded by provider expiry and the current grant, connection and lease limits by relying on the existing lifetime-narrowing behavior. A static API key can remain valid beyond its wrapper's use window. Limiting that window does not shorten the real key's validity. Keep that value only in the protected store and trusted operation memory; use the narrowest provider credential available. Where a provider cannot downscope a key per operation, state that resource/action narrowing is gateway-enforced, not an upstream token-scope guarantee. Cache only in trusted memory; partition by issuer/subject, identity mode, tenant/project/run/ session, connection/revision/secret version, provider, audience/scopes, destination profile, registration/execution/placement fences and policy generation. Pooling connections or cached tokens must not mix users or sessions. Cache hits still need fresh owner/action authorization; old revision entries are unusable.
Refresh and rotation remain Identity-owned. Revocation or changed authority denies new dispatch, invalidates local cache entries and closes affected active channels when observed. Use upstream revocation where the provider supports it; otherwise an already-issued token can remain valid until its upstream expiry. SecretCredential.Invalidate clears one wrapper reference, not immutable string copies or provider tokens. Do not promise remote revocation by clearing a wrapper. Disable credential-bearing dumps and persistent caches, minimize copies, and invalidate on cancellation/error and after operation use.
Gateway administration, provider options, route profiles, trust roots and token issuance are trusted control-plane operations with separate owner/operator authorization, not guest-accessible routes. Use least-privilege service identities and protected host-to-Identity transport; never grant the L7 provider arbitrary Secrets access merely because it mediates traffic. The cluster/node runtime, network enforcer, trusted host and Identity service are trust assumptions. Compromise of those components can expose credentials. Isolation does not prevent an authorized guest from misusing allowed data/actions, nor erase effects already accepted upstream.
Minimal contract changes and admission
These are bounded follow-on design changes, not implemented fields or routes:
| Existing surface | Proposed change |
|---|---|
Projects accepted selection and RuntimeBinding | Add an explicit credential handling mode (legacy-delivery or credential-less) and versioned operation/runtime profile reference, separate from hosted/BYOK ModelSourceMode. Pin profile revision and resource generations without credentials or cached authority. Preserve old JSON/hashes; changing mode needs authorized new selection/registration. |
ProviderDescriptor, EffectiveProviderCandidate, ResourceNegotiation and ProviderResolver.PinNetworkPolicy | Use existing required/advertised/negotiated capability sets for guest credential isolation, forced mediation and exact protocol support. Define shared capability names only for the supported adapters; profile details remain versioned adapter options. Require L7 for this mode even though L7 remains optional for other selections. No new Identity or Model provider enum. |
ISandboxProvider, SandboxProvisionedResource, Environment lease/placement/profile reads | Return verified boundary/endpoint references and profile evidence, not credentials. Environment compares exact negotiated isolation, workspace separation, lease/fences and applied L3/L4 plus L7 generations after provisioning/readback. A descriptor or a second container is not proof. |
EnvironmentEgressManager and AgentHost /health/ready | Include the credential mode, reachable admitted gateway, current protocol/runtime profile and isolation/network enforcement evidence in readiness. Preserve existing configured/ready phases and measured budgets. Policy-object readback alone cannot establish forced mediation; require provider conformance and placement-specific datapath evidence before credential-less dispatch. |
/runtime/v1/configure, /runtime/v1/refresh and registration/profile contracts | In credential-less mode deliver only gateway-specific proof/reference and configuration, never model credentials or owner credentials usable at raw redemption endpoints. A trusted external model adapter keeps configure/observe/model credentials on its side and preserves the existing registration and source contracts. |
Identity /secrets/redeem, /internal/runtime/model-session/redeem, source exchange/rotate and connection/token-mint routes | Restrict raw credentials and credential exchange to authenticated trusted service consumers plus current actor/run purpose checks. A guest gateway proof is rejected even with a valid connection ID or SecretRef. Network denial complements, not replaces, this endpoint authorization. Do not change browser sign-in or widen runtime/public roles. |
| L7 adapter operation endpoint | Add a versioned bounded request, for example POST /egress/v1/operations, in the trusted adapter, not the BFF. Carry operation ID, registration/profile reference, typed operation/input and gateway proof; derive identity, route, audience and credential server-side. Return sanitized data/stream and existing owner receipt references, never a redeemable token. Do not expose unrestricted CONNECT or token endpoints. |
| Runtime/action and Source Control guards | Bind each supported upstream operation to existing current action/Policy admissions and exact input/resource identity; add narrowly typed operations where the existing IDs cannot express the effect. Preserve merge approvals, native result and usage receipts, and Events ownership. |
Before accepting this mode, resolve the selected adapters and exact SDK/profile, require the capabilities, provision, observe actual resource separation, verify the applied network generations, and negotiate the proved capabilities. Persist only the accepted evidence under the existing owner CAS/fences. Readiness and resume recheck the same current evidence. Missing L7, inaccessible Identity, unverified network enforcement, unsupported protocol/SDK mode or stale evidence returns an explicit unavailable/denied result; it never returns legacy readiness. The current Cilium-only implementation has no L7 adapter and cannot claim this mode. A ready legacy AgentHost also cannot claim it.
Existing selections without this proposed field remain historical/legacy, not silently compliant. Introduce the mode only through an explicit platform and project-compatible profile and newly accepted binding; no automatic secret movement, selection-hash migration or change to old accounting receipts. The follow-on slice is bounded: first one trusted L7 operation profile, forced placement/network admission, guest proof, and supported model-runtime integration; then separately admit Git/Azure/other profiles after each profile passes the planned acceptance matrix. Unknown SDK compatibility is a validation item for its profile, not a broad release blocker. This proposal is separate from the current P1 critical path and does not reopen accepted native accounting or add a new P1 acceptance prerequisite.
Planned acceptance matrix
Unexecuted requirements. Documentation checks do not prove runtime isolation, SDK compatibility, token-free deployment or permission for live testing.
| Case | Positive evidence | Negative evidence |
|---|---|---|
| Boundary and proof | Exact provider/placement proof reaches only the admitted gateway operation; upstream sees only the trusted-side credential. | Guest environment/files/process memory/caches/mounts/sockets/snapshots contain no upstream token or projected assertion; copied proof from another placement/session, raw redemption, IMDS, Kubernetes and token exchange all deny. |
| Current authorization | Exact user/app mode, connection, audience/scopes, resource/action and current registration/selection/lease/network generations pass before and after waits. | Change or revoke each binding during acquisition, DNS/TLS or owner waits; no authenticated upstream request follows a failed postcheck. Cache hits, allow lists, shell grants and forged owner headers cannot bypass action guards. |
| Forced mediation | Approved request succeeds via the selected L3/L4 and L7 providers with current enforcement evidence. | Direct IP/FQDN/IPv6, alternate ports, UDP/QUIC, CONNECT, proxy chains, guest DNS/NO_PROXY and gateway loss never reach protected upstreams directly. |
| HTTP/TLS safety | Approved route resolves to a validated peer, with exact Host/SNI, trusted TLS and outside-guest auth insertion. | DNS rebinding, private/metadata targets, redirects, forged auth/Host/SNI, malformed framing and invalid certificates deny; pins/mTLS do not trigger TLS-verification disablement or a guest key fallback. |
| Model/native behavior | Supported exact SDK/native/profile preserves model/session IDs, streaming, tool results, cancellation/abort-idle, actual AIUC/TotalNanoAiu and existing Orchestrator/Events receipts. | Unsupported SDK authentication or WebSocket operations deny admission; no raw token in guest RPC or cache, no new turn after failed abort, no duplicate pricing or proxy-byte ledger. |
| Git/GitHub | Exact repository smart-HTTP read and separately admitted write/API operation use least-privilege trusted tokens and Source Control guards. | Cross-repository/ref writes, unapproved merge, helper redemption, credential-returning API and unimplemented SSH/signing/mTLS modes deny explicitly. |
| Azure/generic | Exact resource/audience/action uses an admitted transport or trusted SDK adapter and reviewed response schema. | Arbitrary GetToken scope, broader app fallback, credential-mint/list-secret operation, opaque unsupported protocol and guest cloud identity acquisition deny. |
| Cache/response isolation | Partitioned cache reuse still rechecks authority; authorized data and safe receipt survive response loss under existing idempotency rules. | Cross-user/session/revision reuse, reflected/encoded credentials, auth cookies, signed secret URLs and log/trace/error/cache/snapshot leakage fail; uncertain writes are not blindly replayed. |
| Rollout and readiness | Newly accepted credential-less mode has actual negotiated isolation, L7/protocol support and current enforcement evidence. | Legacy/absent mode, two containers sharing an unprotected guest, descriptor-only proof, policy-object-only proof and missing adapters never report credential-less readiness. |
PostgreSQL authentication and workload boundary
Runtime PostgreSQL connections use the explicit WorkloadIdentityCredential, no password, and SslMode.VerifyFull. Npgsql acquires an Entra token asynchronously through UsePasswordProvider from the fixed scope https://ossrdbms-aad.database.windows.net/.default for each new physical connection. The runtime username is the separately bootstrapped Entra runtime role.
Ordinary host startup verifies that the identity_broker schema exists and that all migrations are applied; it never applies migrations or creates database roles. Only the explicit --migrate command runs migrations, in a separate one-shot Job with its own ServiceAccount, workload identity, connection-string key, token settings, and schema-owner role. See PostgreSQL configuration and roles.
That Job also applies the canonical table grants to its explicitly configured runtime role before reporting success. The runtime needs SELECT, not write access, on identity_broker.__ef_migrations_history for its EF pending-migration check. Read-only bootstrap verification rejects missing post-migration grants. See migration history and grants for the separately approved repair path.
The Kubernetes source defines an HTTPS Deployment behind an HTTPS ClusterIP Service. It defines no Ingress, Gateway, or ingress controller. The source has not been deployed. Operators must supply the real issuer and external OIDC authority/domain, client registrations, and credentials. They must also supply the approved immutable image, TLS certificate/key, signing PFX/password, and durable key-ring storage. Required database inputs include the approved PostgreSQL administrator and roles. Operators must also provide the exact read-only Key Vault fixture. These inputs are placeholders or external responsibilities. This page makes no deployed-readiness claim.
