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-genai example profile (#3904) works today.
Every other OCI API is signed, not bearer-authenticated. OCI request signing is an RSA-SHA256 HTTP Signature over date (request-target) host, plus content-length content-type x-content-sha256 for requests with a body, with keyId either <tenancy>/<user>/<fingerprint> (API key) or ST$<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: oci is set on a REST endpoint (policy YAML or provider profile endpoint), the proxy:
- Terminates TLS as usual for
protocol: rest.
- Strips the client's
authorization, date, x-date, and x-content-sha256 headers before the fail-closed placeholder scan.
- Resolves
OCI_KEY_ID and OCI_PRIVATE_KEY (PEM, optional OCI_PRIVATE_KEY_PASSPHRASE) from the SecretResolver. OCI_KEY_ID is either the API-key triple or an ST$ token, so the same code path serves all OCI principals once the token is minted.
- Sets
date (RFC 7231) if absent, computes x-content-sha256 as base64 SHA-256 of the body for POST, PUT, and PATCH, and signs the header string with RSA PKCS#1 v1.5 SHA-256. ring is banned by deny.toml; aws-lc-rs already in the tree provides the primitive.
- Injects
Authorization: Signature version="1",keyId="...",algorithm="rsa-sha256",headers="...",signature="..." and forwards.
No signing_service or region parsing is needed: OCI signatures are host-independent, which makes this simpler than SigV4.
endpoints:
- host: "inference.generativeai.*.oci.oraclecloud.com"
port: 443
protocol: rest
credential_signing: oci
rules:
- allow: { method: POST, path: "/20231130/actions/chat" }
- host: "objectstorage.*.oraclecloud.com"
port: 443
protocol: rest
credential_signing: oci
access: read-write
Edge cases to cover: header casing and duplicate host; requests without content-type (OCI accepts application/json default only for JSON bodies; sign what is sent); streaming or chunked bodies must be buffered or rejected because x-content-sha256 needs the full body; OCI rejects date skew 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-bedrock profile 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
Alternatives Considered
- Bridge-fronted profile like
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.
- Sandbox-side signing with injected key material: OpenShell delivers env credentials as proxy-resolved placeholders by design, so an in-sandbox SDK cannot sign with them.
- Reuse
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 main at 5acaaba:
| Component |
Key files |
Role |
| Signing scheme enum |
crates/openshell-supervisor-network/src/l7/mod.rs:83 (CredentialSigning) |
Add Oci variant |
| Policy validation |
crates/openshell-policy/src/lib.rs:1222, :1529 |
Accept oci alongside sigv4, sigv4:body, sigv4:no_body |
| Profile schema |
crates/openshell-providers/src/profiles.rs:360-361, :420-422 (credential_signing, signing_service) |
signing_service stays optional and unused for oci |
| Proxy wiring |
crates/openshell-supervisor-network/src/l7/rest.rs:907 (strip), :985 (resolve keys), :1083, :1102 (apply) |
Mirror the SigV4 branches |
| Signer |
new crates/openshell-supervisor-network/src/oci_signature.rs, sibling of sigv4.rs (585 lines) |
Canonical string, body hash, RSA-SHA256, header assembly |
| Example profiles |
providers/oci-genai-native.yaml, providers/oci-object-storage.yaml |
Reviewable YAML only, per #3906 |
Related: #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.
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.