feat(providers): gateway-minted OCI principal refresh strategies - #3975
Draft
fede-kamel wants to merge 4 commits into
Draft
fede-kamel wants to merge 4 commits into
fede-kamel wants to merge 4 commits into
Conversation
Add credential_signing: oci, a sibling of the SigV4 modes. When an endpoint sets it, the sandbox proxy strips the client's signing headers, resolves OCI_KEY_ID and OCI_PRIVATE_KEY from the endpoint-bound provider, and signs the request with Oracle Cloud Infrastructure's RSA-SHA256 HTTP Signature scheme before forwarding it. The sandbox never holds the key. OCI_KEY_ID is either an API-key triple or an ST$ security token, so one signing path serves every OCI principal type. The signer covers the SDK header set: date (request-target) host, plus content-length content-type x-content-sha256 for POST, PUT, and PATCH, whose bodies are buffered and hashed under the same 10 MiB ceiling as SigV4 body signing. Other methods stream their bodies through unsigned, as the OCI SDKs do. Provider credential values cannot contain newlines, so the private key is accepted as single-line base64 of the PEM, base64 DER, or \\n-escaped PEM; passphrase-protected keys are rejected with a clear message. Policy validation accepts oci and requires signing_service for the SigV4 modes only. The server's signing credential-source check picks the required keys by scheme. Three example profiles (oci, oci-object-storage, oci-genai-native) follow the aws.yaml and aws-s3.yaml shape with setup notes inlined per NVIDIA#3906. Verified against real OCI endpoints: a proxy-shaped signed GET on Object Storage and a signed POST on the native Generative AI chat API both return 200 (tests/oci_signature_live.rs, ignored by default). Closes NVIDIA#3960 Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
…ule in the OCI examples The read-write access preset excludes DELETE, so the Object Storage example says how to grant it. Two attached profiles may not both provide OCI_KEY_ID, so both signing examples point multi-service sandboxes at the endpointless oci profile bound from a sandbox policy. Both facts surfaced in the end-to-end run against real OCI. Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
Send a GENERIC chat with a base64 PNG image part through the OCI signer so the live suite covers body hashing on a multimodal payload, not only text. Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
Add oci_instance_principal, oci_resource_principal, and oci_oke_workload_identity to ProviderCredentialRefreshStrategy. Each mints OCI_KEY_ID as an ST$ security token and co-mints OCI_PRIVATE_KEY as the paired session key through additional_outputs, so sandboxes bound to the provider sign through credential_signing: oci without a long-lived key. - Instance principal federates the host's identity certificate from the instance metadata service at auth.<region>.<realm_domain>/v1/x509, signing under <tenancy>/fed-x509/<sha1 fingerprint> with an ephemeral RSA session key in the request. - Resource principal re-reads the platform-rotated RPST and private key on every refresh from files, literal material, or the OCI_RESOURCE_PRINCIPAL_* environment. - OKE workload identity exchanges the projected service-account token at the cluster proxymux (port 12250, TLS pinned to the projected CA) for a token bound to the session public key; 403 names the enhanced-cluster requirement. - Expiry is the token exp capped by max_lifetime_seconds; 401/403 and other 4xx map to fix_configuration, the rest retry. Identity endpoint overrides exist only under cfg(test) for loopback, and the configure API rejects metadata_base_url, federation_endpoint_url, and proxymux_endpoint_url material. Move the OCI signing primitives into openshell-core so the gateway and the sandbox proxy share one signer; the supervisor module keeps the HTTP framing. Add the profile plumbing (YAML names, mintable set, pinned OCI_KEY_ID/OCI_PRIVATE_KEY outputs), CLI and TUI names, Go SDK constants and converters with regenerated bindings, three endpointless example profiles, and the strategy, material, and mapping rows in the profiles docs. Re-pin the public and durable schema fingerprints for the additive enum values. Closes NVIDIA#3961 Signed-off-by: Federico Kamelhar <federico.kamelhar@oracle.com>
Contributor
Author
|
I have read the DCO document and I hereby sign the DCO. |
5 tasks
Collaborator
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add three gateway-minted credential refresh strategies for Oracle Cloud Infrastructure principals:
oci_instance_principal,oci_resource_principal, andoci_oke_workload_identity. Each one mintsOCI_KEY_IDas anST$<security token>and co-mintsOCI_PRIVATE_KEYas the paired session key throughadditional_outputs, so a sandbox bound to the provider signs OCI requests throughcredential_signing: ociwithout any long-lived key existing anywhere. This is the OCI counterpart ofaws_sts_assume_role(#1782): the gateway host's own platform identity becomes the credential source.Related Issue
Closes #3961. Phase 3 of the OCI integration; depends on #3962 (
credential_signing: oci), which contributes the signer this branch is stacked on. The bearer-onlyoci-genaiprofile landed in #3904.Changes
crates/openshell-core/src/oci_signature.rs(new): the OCI signing primitives shared by the proxy and the gateway.OciSigningKey,sign_headersover aSigningInput(withhostoptional so the gateway can sign federation requests the way the OCI SDKs do),SessionKeyPair::generate(RSA-2048 PKCS#8),sanitize_pem,security_token_expiry_ms(JWTexp), andimf_fixdate.crates/openshell-supervisor-network/src/oci_signature.rsbecomes the HTTP framing layer over it; the proxy behaviour and tests from feat(sandbox): proxy-side OCI request signing for CONNECT tunnels #3962 are unchanged.proto/openshell.proto: enum values 7–9 onProviderCredentialRefreshStrategy.crates/openshell-server/src/provider_refresh.rs: the three mint functions.Authorization: Bearer Oracle), computes the SHA-1 fingerprint, and posts a request signed under<tenancy>/fed-x509/<fingerprint>tohttps://auth.<region>.<realm_domain>/v1/x509carrying the sanitized certificate, the ephemeral session public key, and an optionalpurpose.rpst_file/private_key_file,rpst/private_key, or theOCI_RESOURCE_PRINCIPAL_*environment variables) on every refresh and republishes them in the single-line form the proxy accepts. Passphrase-protected keys are rejected with a configuration error.https://<KUBERNETES_SERVICE_HOST>:12250/resourcePrincipalSessionTokens(TLS pinned to the projectedca.crt) for a token bound to the session public key; a403names the OKE enhanced-cluster requirement.expcapped bymax_lifetime_seconds. Endpoint failures map tofix_configurationfor401/403/4xxand to retryable for everything else. Identity endpoint overrides exist only under#[cfg(test)]and only for loopback, mirroringsts_endpoint_url; the configure API rejectsmetadata_base_url,federation_endpoint_url, andproxymux_endpoint_urlmaterial (CWE-918).crates/openshell-providers/src/profiles.rs: YAML names, mintable-strategy set,is_oci_principal_strategy, output spec (private_keyrequired), and the pinned env keysOCI_KEY_ID/OCI_PRIVATE_KEY.--strategy oci-instance-principal|oci-resource-principal|oci-oke-workload-identity), TUI display names, Go SDK constants and converters, regenerated Go protobuf bindings with the pinnedprotoc-gen-go.providers/oci-instance-principal.yaml,providers/oci-resource-principal.yaml,providers/oci-oke-workload-identity.yaml: endpointless example profiles that pair withcredential_bindingandcredential_signing: oci, with setup notes in the header.docs/how-it-works/providers/profiles.mdx.Testing
openshell_core::oci_signature): signing string with and withouthost, body header set for POST/PUT/PATCH, PEM helpers, session key generation, JWTexpextraction, IMF-fixdate. The supervisoroci_signatureandl7::resttests from feat(sandbox): proxy-side OCI request signing for CONNECT tunnels #3962 pass unchanged over the shared module.provider_refresh, wiremock): instance principal against a mock metadata service and federation endpoint with an rcgen RSA certificate, asserting the<tenancy>/fed-x509/<fingerprint>key id, the host-less header list, the sanitized certificate and intermediate, the optionalpurpose, an ephemeral session key distinct from the instance key, and expiry at the tokenexp; federation401maps toPERMISSION_DENIED. OKE workload identity against a mock proxymux, asserting theBearerservice-account token,opc-request-id, apodKeyequal to the session key's SPKI, the base64 envelope decode, and expiry capped atmax_lifetime_seconds;403names the enhanced-cluster requirement; an unreadable token file isINVALID_ARGUMENT. Resource principal from temp files republishes the token and the key in the single-line form the proxy accepts; passphrase keys and a missing token are rejected. A refresh state without the pinnedprivate_keyoutput fails withFAILED_PRECONDITION. Every minted pair loads inOciSigningKey::from_credentials.oci-instance-principalconfigures with empty material and pinsprivate_keytoOCI_PRIVATE_KEY;metadata_base_url,federation_endpoint_url, andproxymux_endpoint_urlmaterial are rejected for the instance and OKE strategies.--runtime-credentials. Provider listing and example-catalog validation include the new ids. The public/durable schema inventory test is re-pinned for the additive enum values with the review note instorage_proto.rs.openshell-server(1874),openshell-supervisor-network(1432),openshell-core(515),openshell-providers(137), CLI and TUI. Go SDKgo build ./... && go test ./...with bindings regenerated by the pinnedprotoc-gen-go1.36.11.cargo fmt --all --check;cargo clippy --all-targets -D warningson core, supervisor-network, providers, server, CLI, and TUI; license headers; markdownlint;fern check.openshell provider profile linton the three new profiles (and the three from feat(sandbox): proxy-side OCI request signing for CONNECT tunnels #3962) against a gateway and CLI built from this branch: all pass.openshell provider refresh configure --helplists the three strategies.ST$token plus session key transport these strategies produce was verified live in feat(sandbox): proxy-side OCI request signing for CONNECT tunnels #3962 with a security-token principal.Checklist
architecture/was removed upstream in docs: remove the architecture directory #3799; the field-level docs above are updated instead.