On-the-wire credential injection: Secretless OCI access example
In our view, every workload must have a verifiable identity, and only workloads with a trusted, cryptographically provable identityshould be allowed to access protected resources, without relying on secrets.
This approach is essential to defend against modern threats, where increasingly sophisticated attacks routinely target static credentials, configuration files, and long-lived keys. Secrets eventually leak; identities can be continuously verified.
Riptides is built around this principle: SPIFFE-based workload identities, enforced at runtime, with access decisions tied to who the workload is, not what secrets it happens to possess.
For a deeper exploration of the problem space and why the industry must move beyond credentials, see the following posts:
- Workload Identity Without Secrets: A Blueprint for the Post‑Credential Era
- The Hidden Risk in Service Mesh mTLS: When Your Sidecar Becomes a Trojan Horse
- Growing Threat of npm Supply Chain Attacks and the Runtime Fix That Stops It
- Shai‑Hulud 2.0: A Technical Breakdown and Why Secrets Need to Die
- When Remote Code Execution Isn’t the End — Designing for Containment
You can also learn how Riptides assigns trusted identities to processes at the kernel level here:
Workload Attestation and Metadata Gathering: Building Trust from the Ground Up
Overview
In this post, we show how to securely access OCI resources without creating or managing secrets, using the OCI CLI as client/example.
This pattern applies to any client application accessing OCI.
Riptides integrates transparently with the OCI SDK, enabling this capability without requiring any application code changes.
If you’re interested in how Riptides supports other cloud providers, see:
- On-the-Wire Credential Injection: Secretless AWS Bedrock Access Example
- On‑Demand Credentials: Secretless AI Assistant Example on GCP
In this walkthrough, we configure secretless access for the OCI CLI using Riptides. Under the hood, this leverages:
- Riptides’ open‑source oci-req-signer-c library
- OCI Workload Identity Federation
For background, see:
- Workload Identity Federation
- OCI simplifies multi‑cloud workloads with OCI IAM Workload Identity Federation
The standard way: Authenticating and authorizing the client
To access OCI resources, the OCI CLI traditionally authenticates as an IAM user with appropriate permissions. This is the conventional model used by most cloud SDKs and CLIs today.
For this demo:
- Create an IAM group called
IAMUserViewers - Add a test IAM user to the group
- Attach the following policy:
Allow group IAMUserViewers to inspect users in tenancyThe OCI CLI requires a configuration file that specifies which user it authenticates as. This file typically contains sensitive material such as:
key_file(private signing key)pass_phraseprotecting the private keysecurity_token_filefor session-based auth
In this model, the client application is directly responsible for handling credentials. Even when carefully secured, these files become high-value targets: they must be stored somewhere, protected at rest, rotated regularly, and kept out of logs, backups, and build artifacts. This credential-centric approach is functional, but it tightly couples application execution with secret management, increasing both operational overhead and security risk.
Even if all best practices are followed, this model does not protect against supply‑chain attacks, as discussed in the posts linked earlier.
Listing users using this approach:
oci iam user list | jq '.data[].name'
"testuser1"
"testuser2"On‑the‑wire Credential injection with Riptides
Now let’s look at the same operation in a Riptides managed environment.
Riptides eliminates stored secrets by injecting credentials dynamically at runtime. The client never stores, reads, or manages OCI credentials directly.
Prerequisites
Register Riptides Control Plane as an external IDP
To enable secretless access, OCI must be able to trust identities issued by Riptides and map them to an OCI IAM principal. This is done in two steps:
- Create an OCI service user that will be impersonated
- Configure OCI to trust Riptides as an OIDC identity provider and map workload identities to that user
Step 1: Create an OCI service user for impersonation
OCI requires a concrete IAM principal to authorize API calls. Instead of authenticating as a human user, we create a service user that will be impersonated using short-lived credentials.
The following service user definition creates a service user in OCI Identity Domains:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"urn:ietf:params:scim:schemas:oracle:idcs:extension:user:User": {
"serviceUser": true
},
"userName": "testserviceuser1"
}What this does:
- Declares a standard user object
- Marks the user as a service user, not a human
- Creates an identity that can be safely impersonated by workloads
Add this service user to the IAMUserViewers group so it inherits the required permissions.
At this point, we have an OCI principal that is allowed to access the Identity API, but no credentials have been issued or stored yet.
Step 2: Trust Riptides as an OIDC Identity Provider
Next, register the Riptides Control Plane as an OIDC identity provider in OCI. This enables OCI to trust tokens issued by Riptides and exchange them for User Principal Session Tokens (UPSTs).
{
"active": true,
"allowImpersonation": true,
"issuer": "https://<riptides-control-plane>/oidc",
"name": "Token Trust JWT to UPST",
"oauthClients": ["1d92..."],
"publicKeyEndpoint": "https://<riptides-control-plane>/oidc/keys",
"impersonationServiceUsers": [
{
"rule": "sub eq spiffe://acme.org/oci-cli",
"value": "2a86..."
}
],
"subjectType": "User",
"type": "JWT",
"schemas": [
"urn:ietf:params:scim:schemas:oracle:idcs:IdentityPropagationTrust"
]
}What this configuration enables:
issuer: Identifies the Riptides Control Plane as the trusted OIDC issueroauthClients: Restricts trust to a specific OAuth 2.0 client registered for the Riptides Control PlanepublicKeyEndpoint: Allows OCI to fetch the public keys used to verify ID tokens signed by Riptides Control PlaneimpersonationServiceUsers: Defines how a workload identity maps to an OCI IAM service user
In this example:
- If the ID token contains a
subclaim equal tospiffe://acme.org/oci-cli - OCI will issue temporary credentials for the service user with ID
2a86... type: JWTindicates that the trust relationship is based on JWT-formatted ID tokens
How this fits into the secretless flow:
- Riptides issues an ID token (JWT SVID) to a workload, containing a SPIFFE-based subject
- OCI verifies the token using the configured trust
- OCI exchanges the token for a short-lived UPST
- The workload impersonates the service user without ever handling secrets
At no point does the application receive, store, or manage credentials. Secrets exist, but they are managed by the platform, not the application.
Setting up the client application with Riptides
From Riptides’ perspective, the OCI IAM service API is an external dependency. It is not discovered automatically. To enable credential injection, Riptides must first be told which external service the workload will communicate with.
This is done by registering the OCI Identity API as an external service in the Riptides Control Plane using a Kubernetes custom resource:
apiVersion: core.riptides.io/v1alpha1
kind: Service
metadata:
name: oci-identity-api
namespace: riptides-system
spec:
addresses:
- address: identity.eu-frankfurt-1.oci.oraclecloud.com
# OCI Identity REST API service endpoint
port: 443 # Port the client connects to
labels:
app: oci-identity-api # Label for matching this service
external: true # Indicates this is an external service, not managed by RiptidesWhat this configuration does:
- Declares the OCI Identity REST API endpoint as a known external service
- Allows Riptides to match outbound connections from workloads to this destination
Defining how workloads obtain OCI credentials
At this point, Riptides knows where the workload will connect (OCI Identity API). Next, we define how Riptides should obtain credentialsfor that workload.
This is done in two steps:
- Define how to obtain temporary OCI credentials
- Bind those credentials to a specific workload identity
Step 1: Define a credential source
A CredentialSource describes how Riptides exchanges identity for temporary OCI credentials. In this case, the source is OCI itself, using OCI IAM Workload Identity Federation.
apiVersion: core.riptides.io/v1alpha1
kind: CredentialSource
metadata:
name: oci-cred-1
namespace: riptides-system
spec:
oci: # Temporary credentials sourced from OCI
region: eu-frankfurt-1
clientId: 1d92... # the OAUth 2.0 client id defined in OCI for the Riptides Control Plane
clientSecret: idcscs-.... # the client secret defined in OCI for the Riptides Control Plane
identityDomainUrl: https://idcs-......identity.oraclecloud.com # the URL of the identity domain where the impersonated OCI service user is defined
tenancyOcid: ocid1.tenancy.oc1........ What this configuration defines:
region: The OCI region where credentials will be issued.clientId / clientSecret: OAuth 2.0 credentials used by the Riptides Control Plane, not the application, to interact with OCI IAM.identityDomainUrl: The OCI Identity Domain where the impersonated service user is defined.tenancyOcid: Identifies the OCI tenancy where authentication and authorization occur.
This resource does not issue credentials on its own. It simply defines how credentials can be obtained when needed.
Step 2: Bind credentials to a workload identity
Next, we associate the credential source with a specific workload identity using a WorkloadCredential:
apiVersion: core.riptides.io/v1alpha1
kind: WorkloadCredential
metadata:
name: oci-cli-cred-1
namespace: riptides-system
spec:
credentialSource: oci-cred-1 # Source of temporary credentials
workloadID: oci-cli # Workload ID to get OCI temporary credentials forWhat this does:
- Links the
oci-cliworkload identity to the OCI credential source - Ensures that only workloads with this identity can obtain these credentials
At this point, no credentials are issued yet; the configuration merely defines the relationship.
How it works at runtime
When a workload with the oci-cli identity needs to call OCI:
- The Riptides Control Plane issues an ID token for the workload.
- The token’s
subclaim follows the SPIFFE format:spiffe://<TRUST_DOMAIN>/<WORKLOAD_ID>
In this demo:spiffe://acme.org/oci-cli - OCI validates this token using the previously configured trust relationship.
- OCI exchanges the token for short-lived credentials impersonating the service user.
- Riptides injects these credentials transparently into outgoing requests.
- Credentials are automatically refreshed before expiration.
At no point does the application:
- See credentials
- Store credentials
- Handle rotation or expiration logic
Secrets exist, but they are **entirely managed by the platform, not the workload.
Assigning Workload IDs to processes
We define which processes can be assigned the oci-cli workload ID, and under what conditions:
apiVersion: core.riptides.io/v1alpha1
kind: WorkloadIdentity
metadata:
name: oci-cli-wid
namespace: riptides-system
spec:
scope:
agent:
id: <AGENT_WORKLOAD_ID> # Scope: node(s) where this workload identity can be assigned
workloadID: oci-cli # The workload ID assigned to matching processes
selectors:
- process:name: [oci] # Runtime process attribute that must match to get this identity
egress: # Egress rules for credential injection
- selectors:
- app: oci-identity-api # Service endpoint(s) targeted by this rule
credentialName: oci-cli-cred-1 # Credentials to inject, referenced from WorkloadCredential
connection:
tls:
intercept: true # Intercept traffic and inject credentials into HTTP requestsHow it works
- Riptides Agent runs on nodes and acts as the bridge between the Control Plane and the Linux kernel module.
- Workload IDs and credentials issued by the Control Plane are restricted to processes on the node where the agent runs — this is controlled by the scope field in the WorkloadIdentity CR. Multiple agents can also be targeted if needed.
- The Linux kernel module monitors running processes and checks their runtime attributes against the spec.selectors values. Only matching processes are assigned the workload ID.
- When a process with an assigned workload ID sends a request to a service referenced in the egress rules, the temporary credentials from the specified WorkloadCredential are injected directly into the request.
In this example, any process named oci will receive OCI temporary credentials automatically when sending requests to the OCI Identity service endpoint.
The original HTTP request sent by OCI CLI to OCI Identity service endpoint is modified by Riptides' Linux kernel module as it injects the temporary credentials on the fly. The modified HTTP request requires resigning with the correct OCI signature. Our Linux kernel module accomplishes this using our oci-req-signer-c library, implemented in portable C with Linux kernel compatibility. This enables credentials to be injected and signed at the kernel level just before the request is sent, ensuring full OCI authentication without exposing keys to the client application.
Why is this matters: Unlike sidecars, environment variables, or SDK hooks:
- Identity is bound to process execution, not deployment metadata
- Credentials are scoped to specific destinations
- Enforcement happens at the kernel boundary
- Compromising the application does not automatically expose credentials
From the application’s point of view, authentication “just works.” From a security perspective, access is tightly constrained, observable, and auditable.
Running the Client Application
The OCI SDK still expects a configuration file, so we provide dummy credentials that satisfy the SDK’s syntax requirements but are never used for authentication. Riptides intercepts the request, injects valid temporary credentials, and re-signs the request transparently at runtime.
[DEFAULT]
user=ocid1.user.oc1..dummy
fingerprint=00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
key_file=/var/tmp/dummy_priv_key.pem
tenancy=ocid1.tenancy.oc1......
region=eu-frankfurt-1The private key referenced here must be syntactically valid, but it has no permissions and no security value. At runtime, Riptides replaces it with workload-bound private key derived from the workload identity.
oci --cert-bundle /sys/module/riptides/certs/ca-certificates.crt iam user list | jq '.data.[].name'
"testuser1"
"testuser2"
"testserviceuser1What actually happened:
- The OCI CLI believed it was using local credentials
- The real credentials were never present in files, environment variables, or process memory
- Authentication and request signing occurred inside the kernel, just before the request was sent
- Credentials were scoped, temporary, and automatically refreshed
Key points
- No credentials are ever stored on the client machine or in configuration files.
- Credentials are provided just-in-time for each request, minimizing the risk of leaks or misuse.
- The application workflow remains unchanged, from the client’s perspective, authentication happens automatically and transparently.
When the On-the-wire credential injection is not an option
There may be situations where you cannot or do not want to use on-the-wire credential injection. In these cases, Riptides still provides credentials to the OCI SDK without exposing them on the filesystem:
- The configuration file, private key file, and session token file are made available via
sysfs. - Only processes with the appropriate workload identity can access these files. To disable on-the-wire injection, set
connection.tls.intercept: falsein theWorkloadIdentitycustom resource.
Running OCI CLI with sysfs-based credentials
You can point the OCI CLI to the Riptides managed configuration files as follows:
oci oci --auth security_token --cert-bundle /sys/module/riptides/certs/ca-certificates.crt --config-file /sys/module/riptides/credentials/4e1ef9dd-fa21-513d-8505-7e9ef13b9be0/oci-cli-cred-1/oci_config iam user list | jq '.data.[].name'
"testuser1"
"testuser2"
"testserviceuser1The exact path of oci_config can be retrieved from the WorkloadCredential custom resource status fields.
Why is this approach safe
- Credentials never appear on disk or in environment variables
- Only processes with the matching workload identity can read the configuration
- The OCI CLI behaves normally, but secrets are still tightly scoped and ephemeral
This provides a fallback option when on-the-wire injection is not feasible, without compromising the security guarantees of the platform.
Final Thoughts
At Riptides, we are strong advocates of SPIFFE-based workload identities as the foundation for secure, scalable non‑human authentication.
The benefits are concrete and measurable:
- Elimination of static keys — no long-lived secrets to steal or rotate
- Short-lived, impersonated credentials — automatically issued and refreshed
- Full auditability — every action is traceable to a workload
This is more than an implementation detail; it’s a security philosophy: no static secrets, no blind trust, only verifiable workload identities at runtime.
If you enjoyed this post, follow us on LinkedIn and X for more updates. If you’d like to see Riptides in action, get in touch with us for a demo.
Ready to replace secrets
with trusted identities?
Build with trust at the core.