Repository navigation
feat(sandbox): proxy-side OCI request signing for CONNECT tunnels (credential_signing: oci) #3960
Description
Activity
- addedstate:triage-neededOpened without agent diagnostics and needs triageOpened without agent diagnostics and needs triage
on Sep 30, 2026 Companion issue for the principal-based minting of the
ST$token and session key that this signing path consumes: #3961.Implementation: #3962. Live interop verified against Object Storage and the native Generative AI API in us-chicago-1 with an API-key principal; details in the PR.
📋 triage-agent
Triage Assessment
Classification: validated-feature
Summary
The problem statement matches current behavior on
main(7caff12). Placeholder substitution can't produce a valid OCI RSA-SHA256 signature.CredentialSigningsupports only the SigV4 variants, and policy validation rejects any other value. The proposed design (a sibling ofsigv4.rsin the supervisor proxy) is technically feasible. All file references in the Agent Investigation table are accurate.aws-lc-rsis in the tree and supports RSA PKCS#1 v1.5 SHA-256, andringis banned indeny.toml. The report has no explicit User Story section, but the persona and goal are clear from the problem statement.Investigation
Gaps in the proposed design:
- PEM keys can't pass through the resolver unchanged.
validate_resolved_secret(crates/openshell-core/src/secrets.rs:852) rejects any resolved value containing CR or LF, so a multi-line PEMOCI_PRIVATE_KEYneeds an encoding convention (base64, DER or escaped newlines). The design should specify which. signing_serviceis currently required.crates/openshell-policy/src/lib.rs:1538rejects anycredential_signingvalue withoutsigning_service, and the example YAML omits it. That check, and the runtime equivalent inl7/mod.rs, would need to be relaxed foroci. The credential-source precondition inopenshell-server/src/grpc/policy.rsalso hard-codes the AWS key names.- Large and streaming uploads. Hashing every PUT/PATCH body caps Object Storage uploads at
MAX_SIGV4_BODY_BYTES(10 MiB) and rejects chunked bodies. SigV4 has an unsigned-payload mode (sigv4:no_body) for this case. Whether Object Storage accepts PUT signed without the body headers would decide whether OCI needs an equivalent mode. - Passphrase-protected keys. The issue lists
OCI_PRIVATE_KEY_PASSPHRASEas optional, butaws-lc-rsdoesn't decrypt encrypted PEM, and feat(sandbox): proxy-side OCI request signing for CONNECT tunnels #3962 rejects encrypted keys. The issue and PR should agree. - Host binding. OCI signs the
hostheader, so the proxy must sign the exact host it forwards to. What the design avoids is region and service scoping, not host binding. - Test vectors. AC3 asks for signatures verified against the OCI Python SDK on fixed vectors, which needs a committed test key and SDK-generated expected values.
No duplicates found. Related: #3879 (umbrella), #3961 (
ST$principal refresh), #1631 (SigV4 precedent), #3904 (bearer-only profile). #2255 concerns the Open Container Initiative runtime, not Oracle Cloud.Impact Signals
- Affected users/scope: OpenShell users calling OCI APIs other than the OpenAI-compatible Generative AI endpoint from sandboxes
- Regression: no
- Workaround: available but insufficient (plaintext key injection, or a signing bridge outside the sandbox)
- Evidence quality: high for current behavior (verified in code); medium for the design details (live interop reported in feat(sandbox): proxy-side OCI request signing for CONNECT tunnels #3962, not independently verified)
Human Decision Required
Decide whether OpenShell should address this issue. If yes, apply
state:accepted, associate it with a roadmap item, or do both, and decide
whether the work remains human-owned. Either action records acceptance;
roadmap placement additionally records sequencing.
To queue investigation or planning for an unattended agent, also apply
agent:plan-requested. You can instead directly ask an agent to use
create-spikeorbuild-from-issueon this issue; the agent will warn about
missing expected workflow labels and continue without changing them. If no,
close it as not planned and record the rationale.- PEM keys can't pass through the resolver unchanged.
- addedarea:supervisorProxy and routing-path workProxy and routing-path worktopic:l7Application-layer policy and inspection workApplication-layer policy and inspection workand removedstate:triage-neededOpened without agent diagnostics and needs triageOpened without agent diagnostics and needs triage
on Oct 1, 2026 Thanks for proposing this, @fede-kamel, and #3961 as well. While I'm favorably inclined, we like this sort of provider-specific addition to be brought to the community for acceptance, either in CNCF Slack
#openshell-devor in the weekly community meeting (Tue 9a Pacific/noon Eastern). Can you please bring them to either venue for discussion?I'm going to note this on #3961 as well, and move the attached PRs on both to draft with a linked note.
Problem Statement
OpenShell replaces real secrets with opaque placeholders in sandbox environment variables and resolves them in HTTP headers (Bearer, Basic) before forwarding upstream. That is enough for the OCI Generative AI OpenAI-compatible endpoint, which is why the
oci-genaiexample profile (#3904) works today.Every other OCI API is signed, not bearer-authenticated. OCI request signing is an RSA-SHA256 HTTP
Signatureoverdate (request-target) host, pluscontent-length content-type x-content-sha256for requests with a body, withkeyIdeither<tenancy>/<user>/<fingerprint>(API key) orST$<security-token>(session, instance, resource, or workload principal). Like SigV4 (#1631), a placeholder value produces an invalid signature that header replacement cannot fix. Sandboxed agents therefore cannot reach the native Generative AI API (/20231130), Object Storage, or any other OCI service through the credential proxy.Proposed Design
Add proxy-side OCI signing in the sandbox supervisor's CONNECT tunnel path, as a sibling of SigV4. When
credential_signing: ociis set on a REST endpoint (policy YAML or provider profile endpoint), the proxy:protocol: rest.authorization,date,x-date, andx-content-sha256headers before the fail-closed placeholder scan.OCI_KEY_IDandOCI_PRIVATE_KEY(PEM, optionalOCI_PRIVATE_KEY_PASSPHRASE) from theSecretResolver.OCI_KEY_IDis either the API-key triple or anST$token, so the same code path serves all OCI principals once the token is minted.date(RFC 7231) if absent, computesx-content-sha256as base64 SHA-256 of the body for POST, PUT, and PATCH, and signs the header string with RSA PKCS#1 v1.5 SHA-256.ringis banned bydeny.toml;aws-lc-rsalready in the tree provides the primitive.Authorization: Signature version="1",keyId="...",algorithm="rsa-sha256",headers="...",signature="..."and forwards.No
signing_serviceor region parsing is needed: OCI signatures are host-independent, which makes this simpler than SigV4.Edge cases to cover: header casing and duplicate
host; requests withoutcontent-type(OCI acceptsapplication/jsondefault only for JSON bodies; sign what is sent); streaming or chunked bodies must be buffered or rejected becausex-content-sha256needs the full body; OCI rejectsdateskew beyond five minutes; passphrase-protected keys; non-commercial realms use other domains and need no code change.Impact / Why This Matters
Without this, OCI users must inject a long-lived API key and private key as plain values, run a signing bridge per service (the workaround the
aws-bedrockprofile header warns against), or stay on the bearer-only Generative AI endpoint. Oracle Cloud Infrastructure is named as an infrastructure partner of the Open Agent Safety Platform and hosts a growing share of NVIDIA GPU capacity; agents running there need the same governed path AWS got with SigV4.Acceptance Criteria
credential_signing: ociis accepted by policy and profile validation alongside thesigv4*values.POST /20231130/actions/chaton the Generative AI native API andGET/PUTobjects on Object Storage, with the real key never present in the sandbox.ST$key ids).authorization,date,x-date, andx-content-sha256are stripped before signing and never leak upstream.providers/with header notes, following Remove the inference provider table and provider profile telemetry buckets #3906.credential_signingfield listocinext tosigv4.Alternatives Considered
aws-bedrock: works today but moves the OCI credential into another workload and grants the sandbox egress to it. Documented as the interim path, not the goal.sigv4: different algorithm (RSA vs HMAC), different canonical string, different header set. A sibling module is cleaner than a shared abstraction over two schemes.Agent Investigation
Checked against
mainat 5acaaba:crates/openshell-supervisor-network/src/l7/mod.rs:83(CredentialSigning)Ocivariantcrates/openshell-policy/src/lib.rs:1222,:1529ocialongsidesigv4,sigv4:body,sigv4:no_bodycrates/openshell-providers/src/profiles.rs:360-361,:420-422(credential_signing,signing_service)signing_servicestays optional and unused forocicrates/openshell-supervisor-network/src/l7/rest.rs:907(strip),:985(resolve keys),:1083,:1102(apply)crates/openshell-supervisor-network/src/oci_signature.rs, sibling ofsigv4.rs(585 lines)providers/oci-genai-native.yaml,providers/oci-object-storage.yamlRelated: #3879 (umbrella), #3904 (bearer profile, merged), #1631 / #1638 (SigV4 precedent). Principal-based minting of the
ST$token and session key is a separate follow-up, filed alongside this issue, and consumes this signing path unchanged.