Skip to content

Oracle Cloud Infrastructure support: OCI GenAI provider profile, OCI request signing, principal refresh #3879

Description

@fede-kamel

User Story

As a platform engineer running agents on Oracle Cloud Infrastructure (OCI),
I want OpenShell sandboxes to reach OCI Generative AI and other OCI services through OpenShell's normal provider and policy model,
so that agents on OCI get the same "credential never enters the sandbox, endpoint-bound injection, hot-reloadable policy" guarantees that AWS and Google Cloud users already get.

Problem Statement

OpenShell ships example provider profiles, gateway credential refresh, and proxy-side request signing for AWS (aws, aws-s3, aws-bedrock, aws_sts_assume_role, SigV4) and Google Cloud (google-cloud, google-vertex-ai, google_service_account_jwt, GCE metadata emulation). There is no OCI coverage anywhere: no profile, no docs page, no refresh strategy, no signing scheme. Every "OCI" string in the repository refers to the Open Container Initiative.

OCI clients authenticate through five transports, and none of them is representable in OpenShell today except the first, which only works because it happens to be a bearer token:

OCI transport How it authenticates OpenShell gap
Generative AI API key Authorization: Bearer sk-... on the OpenAI-compatible /openai/v1 endpoint; key is compartment-scoped None once an example profile exists (implementation ready on a fork branch, see below)
API key (user principal) RSA-SHA256 HTTP Signature header over (request-target) host date plus body hash headers, keyId=tenancy/user/fingerprint No proxy-side signing scheme; credential_signing accepts only sigv4*
Security token (session) Same signature, keyId=ST$<token> with a short-lived token and ephemeral key Same signing gap, plus token refresh from a file (external)
Instance principal / resource principal Same signature with a federated short-lived token Same signing gap, plus a gateway refresh strategy that performs the federation
OKE workload identity Same signature with a token obtained from the OKE proxymux using the pod's service-account token Same signing gap, plus a Kubernetes-aware refresh strategy

Impact / Why This Matters

Without this, OCI users must either hand the sandbox a long-lived OCI API key and private key as plain environment values (defeating the point of OpenShell), or run a signing bridge per service and grant the sandbox egress to the bridge. Both are the workarounds the aws-bedrock profile header already warns against. Oracle Cloud Infrastructure is named as an infrastructure partner in the Open Agent Safety Platform launch, and OCI hosts a growing share of NVIDIA GPU capacity, so this is a real adoption barrier rather than a corner case.

Proposed Design

Phase 1 (this issue; implementation ready at https://github.com/fede-kamel/OpenShell/tree/feat/oci-genai-provider, PR to follow once vouched): an example oci-genai inference profile plus a docs page. The profile declares the regional inference host pattern, restricts the credential to /openai/v1, and documents the OCI-side least-privilege setup (policy before key, one compartment, request.principal.type='generativeaiapikey'). It follows the deepinfra precedent: YAML example, telemetry bucket, overview table row, docs page. No new mechanism.

Phase 2: a credential_signing: oci scheme in the sandbox proxy, a sibling of sigv4. The profile declares oci_key_id and oci_private_key credentials; the proxy signs outbound requests to declared OCI hosts with the OCI HTTP Signature profile and the sandbox never holds the private key. This unlocks the native /20231130 Generative AI API, Object Storage, and every other OCI service with the API-key transport.

Phase 3: gateway refresh strategies oci_instance_principal, oci_resource_principal, and oci_oke_workload_identity that mint the short-lived token and ephemeral key pair the same way aws_sts_assume_role co-mints three AWS values, so principal-based transports work without any long-lived secret at the gateway either.

Happy to write the RFC for phases 2 and 3 if maintainers want one.

Acceptance Criteria

  • openshell provider profile import -f providers/oci-genai.yaml lints and imports; a sandbox with the provider attached can call https://inference.generativeai.<region>.oci.oraclecloud.com/openai/v1/chat/completions with OCI_GENAI_API_KEY and the real key never appears inside the sandbox.
  • A docs page under Providers explains the OCI transport matrix, the policy-before-key ordering, and the least-privilege IAM statement.
  • (Phase 2) An endpoint with credential_signing: oci is signed by the proxy and accepted by OCI for the native Generative AI API and Object Storage.
  • (Phase 3) A provider configured with an instance-principal or resource-principal refresh strategy rotates its token without operator action.

Alternatives Considered

  • Reuse the openai profile with a different host: rejected by the providers overview itself; each host needs its own profile so the credential cannot leak to api.openai.com.
  • Bridge-fronted profile like aws-bedrock: works today for the signed transports but moves the OCI credential into another workload the operator must secure and grants sandbox egress to it. Documented as the interim path.
  • Sandbox-side signing with injected key material: OpenShell delivers env credentials as placeholders resolved by the proxy, so an in-sandbox SDK cannot sign with them; this is by design and should stay that way.

Agent Investigation

Verified on the fork branch above against main at cf1bbb9: openshell provider profile lint passes, cargo test -p openshell-core --lib telemetry and cargo test -p openshell-server --lib grpc::provider::tests pass (167 tests), clippy with -D warnings, rustfmt, license headers, markdownlint, and fern check are clean. A sandbox with the provider attached receives only a placeholder in OCI_GENAI_API_KEY; the proxy forwards /openai/v1 requests to the regional OCI host and denies the native /20231130 path and other hosts.

Feasibility notes for phases 2 and 3:

  • Refresh strategies are a closed proto enum (ProviderCredentialRefreshStrategy) dispatched in crates/openshell-server/src/provider_refresh.rs; adding OCI principals is about five in-tree files.
  • Request signing is a closed enum (CredentialSigning) in crates/openshell-supervisor-network/src/l7/mod.rs with the only implementation in sigv4.rs; OCI signing would be a sibling module of similar size.
  • Compute and credential-store drivers are open gRPC boundaries, so an OCI Vault credential driver and an OKE-aware compute driver need no upstream change and are out of scope here.

Activity

  1. fede-kamel commented on Sep 29, 2026

    @fede-kamel
    ContributorAuthor

    Verification with a real OCI Generative AI API key (us-chicago-1), through an OpenShell 0.1.2 Docker gateway with the oci-genai profile from https://github.com/fede-kamel/OpenShell/tree/feat/oci-genai-provider attached to a quay.io/curl/curl sandbox:

    Check Result
    POST /openai/v1/chat/completions, meta.llama-3.3-70b-instruct 200, reply "OK from OCI"
    POST /openai/v1/responses, openai.gpt-oss-120b 200
    GET /openai/v1/models 404 from OCI (documented; not a health check)
    POST /20231130/actions/chat on the same host 403 policy_denied from the sandbox L7 proxy
    https://api.openai.com connection refused at connect
    OCI_GENAI_API_KEY inside the sandbox 61-character placeholder, not the key

    Unit suites on the branch: openshell-core, openshell-providers, openshell-policy, openshell-cli, openshell-server (lib) — 3409 passed, 0 failed, 14 ignored. Clippy -D warnings, rustfmt, license headers, markdownlint and fern check are clean.

  2. fede-kamel commented on Sep 29, 2026

    @fede-kamel
    ContributorAuthor

    Follow-up: full OpenAI-compatible surface exercised through the sandbox proxy with the oci-genai profile (real key, us-chicago-1, quay.io/curl/curl sandbox):

    Operation Result
    Chat completions stream: true 200, 12 SSE data: frames, [DONE] marker, tokens reassembled correctly
    Tool calling 200, tool_calls[0].function.name = get_weather, finish_reason = tool_calls
    Vision, 64x64 red PNG as data: URL 200 on meta.llama-4-maverick-17b-128e-instruct-fp8 ("Red.") and google.gemini-2.5-flash ("Red")
    Vision, 263 KB request body 200, body forwarded unchanged (sent=262911B)
    Embeddings openai.text-embedding-3-small 200, object: list
    Embeddings cohere.embed-multilingual-v3.0 400 Unsupported OpenAI operation from OCI (documented)
    Responses stream: true 200, 62 SSE frames, response.created … response.incomplete
    GET / DELETE /openai/v1/responses/{id} Allowed by the profile rules; OCI answered 400 asking for a conversation store
    PUT /openai/v1/responses/{id} 403 policy_denied from the proxy (not in the profile rules)
    meta.llama-3.2-90b-vision-instruct, xai.grok-4 404 Entity with key … not found from OCI (not exposed on this endpoint; documented)

    Docs page updated with a Verified Capabilities section and the two OCI error messages above.

  3. fede-kamel commented on Sep 29, 2026

    @fede-kamel
    ContributorAuthor

    Phase 1 implementation is now open as #3904 (supersedes #3885, which was auto-closed before the vouch landed).

  4. fede-kamel commented on Sep 30, 2026

    @fede-kamel
    ContributorAuthor

    Phase 1 landed: #3904 merged 2026-09-29. providers/oci-genai.yaml is importable from main. Phases 2 (proxy-side OCI request signing) and 3 (principal-based refresh) remain open for maintainer disposition here.

  5. fede-kamel commented on Sep 30, 2026

    @fede-kamel
    ContributorAuthor

    Split the remaining phases into focused issues, following the SigV4 (#1631) and STS (#1576) precedent: #3960 proxy-side OCI request signing (credential_signing: oci), #3961 OCI principal refresh strategies. This issue stays as the umbrella.

  6. fede-kamel commented on Sep 30, 2026

    @fede-kamel
    ContributorAuthor

    Closing to remove redundancy: phase 1 (bearer oci-genai profile) merged in #3904; phase 2 (proxy-side OCI request signing) is tracked in #3960 with implementation in #3962; phase 3 (principal-based refresh strategies) is tracked in #3961. Design discussion belongs on those two focused issues.

  7. removed
    state:triage-neededOpened without agent diagnostics and needs triage
    on Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions