Secretless AWS Access
This guide shows how to access AWS services (such as Amazon Bedrock) from your workloads without storing or distributing any AWS credentials. Riptides federates workload identity to AWS via OIDC, and the kernel module automatically signs outbound requests with AWS SigV4 — your application makes plain HTTP calls.
Overview
Section titled “Overview”Traditional approaches to AWS access require distributing long-lived IAM access keys or mounting service account tokens. Both create secrets that must be rotated, stored securely, and audited.
With Riptides, the flow is:
- The Riptides control plane acts as an OIDC identity provider
- AWS IAM is configured to trust this OIDC provider
- A
CredentialSourcereferences the IAM role to assume - A
CredentialBindingbinds the credential to your workload’s identity - The kernel module intercepts outbound HTTP requests to AWS and attaches SigV4 signatures automatically
Your application never sees or handles AWS credentials.
Prerequisites
Section titled “Prerequisites”- A Riptides control plane with an OIDC endpoint (e.g.,
https://cp.example.com/oidc) - An AWS account with permissions to create IAM roles and OIDC identity providers
- A workload deployed on a Kubernetes cluster with the Riptides daemon installed
kubectlconfigured with access to theriptides-systemnamespace- The
oidc-loginkubectl plugin (kubelogin) for control plane authentication. See Install theoidc-loginPlugin.
Step 1: Configure AWS IAM
Section titled “Step 1: Configure AWS IAM”Create an OIDC Identity Provider
Section titled “Create an OIDC Identity Provider”In the AWS Console or via CLI, register the Riptides control plane as an OIDC identity provider.
AWS Console:
- Navigate to IAM > Identity providers > Add provider
- Select OpenID Connect
- Set the Provider URL to your Riptides control plane OIDC URL (e.g.,
https://<your-env-id>.console.riptides.io/oidc) - Set the Audience to
sts.amazonaws.com - Click Add provider
AWS CLI:
Note: Riptides uses a Let’s Encrypt certificate, so AWS will validate the OIDC provider against its trusted CA bundle and
--thumbprint-listis not required.
aws iam create-open-id-connect-provider \ --url https://<your-env-id>.console.riptides.io/oidc \ --client-id-list sts.amazonaws.comCreate an IAM Role with a Trust Policy
Section titled “Create an IAM Role with a Trust Policy”Create an IAM role that AWS workloads will assume. The trust policy restricts assumption to a specific SPIFFE ID, ensuring only the intended workload can obtain credentials.
AWS Console:
- Navigate to IAM > Roles > Create role
- Select Custom trust policy
- Apply the below mentioned json
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/<your-env-id>.console.riptides.io/oidc" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "<your-env-id>.console.riptides.io/oidc:aud": "sts.amazonaws.com" } } } ]}AWS CLI:
Save the above JSON to trust-policy.json, replacing the account ID and <your-env-id> placeholders:
aws iam create-role \ --role-name my-app-bedrock-role \ --assume-role-policy-document file://trust-policy.jsonAttach the appropriate permissions policy for your use case. For example, to access Amazon Bedrock:
AWS Console:
- Select the created Role
- Add permissions > Create inline policy
- Policy editor > JSON
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream", "bedrock:InvokeAgent" ], "Resource": "*" } ]}AWS CLI:
Save the above JSON to bedrock-policy.json, replacing my-app-bedrock-role with your role name:
aws iam put-role-policy \ --role-name my-app-bedrock-role \ --policy-name bedrock-access \ --policy-document file://bedrock-policy.jsonStep 2: Create a WorkloadIdentity
Section titled “Step 2: Create a WorkloadIdentity”The WorkloadIdentity must exist before other resources that reference its workloadID. It assigns a SPIFFE identity to the workload and enables TLS intercept for outbound connections so the kernel can inject credentials.
First, find the daemon running on the host:
riptides-cli ctl get daemonsRetrieve its ID:
riptides-cli ctl get daemon <daemon-name> -o jsonpath='{.spec.workloadID}'Use that value in the scope.daemon.id field below:
riptides-cli ctl apply -f - <<EOFapiVersion: core.riptides.io/v1alpha1kind: WorkloadIdentitymetadata: name: my-app namespace: riptides-systemspec: connection: tls: mode: PERMISSIVE intercept: true scope: daemon: id: "<daemon-id>" selectors: - k8s:label:app: my-app k8s:pod:namespace: my-app process:name: python3 workloadID: my-app/workloadEOFKey field:
connection.tls.intercept: true: The kernel intercepts outbound TLS connections and handles credential injection. Required for theinjectionpropagation mode to work.
Step 3: Create the CredentialSource
Section titled “Step 3: Create the CredentialSource”The CredentialSource tells Riptides how to obtain AWS credentials. For AWS, it references the IAM role ARN. Riptides uses the workload’s SPIFFE-based JWT-SVID to call sts:AssumeRoleWithWebIdentity and obtain temporary credentials, which are automatically rotated before expiration.
riptides-cli ctl apply -f - <<EOFapiVersion: core.riptides.io/v1alpha1kind: CredentialSourcemetadata: name: my-app-aws-creds namespace: riptides-systemspec: aws: roleArn: arn:aws:iam::123456789012:role/<replace with the created identity provider name>EOFVerify:
riptides-cli ctl describe credentialsource my-app-aws-creds# STATE should show AVAILABLEStep 4: Create the AWS Service
Section titled “Step 4: Create the AWS Service”Define a Riptides Service resource for the AWS API endpoint your workload needs to reach.
riptides-cli ctl apply -f - <<EOFapiVersion: core.riptides.io/v1alpha1kind: Servicemetadata: name: bedrock-runtime-svc namespace: riptides-systemspec: addresses: - address: bedrock-agent-runtime.us-east-1.amazonaws.com port: 443 external: true labels: app: my-app service: bedrock-runtimeEOFKey fields:
external: true: Indicates this is an external service outside the user’s environment.labels: Used by CredentialBinding injection selectors to match this Service.
Step 5: Create the CredentialBinding
Section titled “Step 5: Create the CredentialBinding”The CredentialBinding connects the CredentialSource to your workload and configures how the credential is delivered.
riptides-cli ctl apply -f - <<EOFapiVersion: core.riptides.io/v1alpha1kind: CredentialBindingmetadata: name: my-app-aws-binding namespace: riptides-systemspec: workloadID: my-app/workload credentialSource: my-app-aws-creds propagation: injection: selectors: - app: my-app service: bedrock-runtimeEOFVerify:
riptides-cli ctl describe credentialbinding my-app-aws-binding# STATE should show OKWhen the workload makes an outbound HTTPS request to the AWS endpoint, the kernel intercepts the connection and injects the AWS credentials. The workload does not handle any credentials.
Step 6: Configure the Riptides CA Bundle
Section titled “Step 6: Configure the Riptides CA Bundle”Because tls.intercept: true causes the kernel to terminate and re-originate TLS, processes need to trust the Riptides CA. The daemon automatically merges the intercept CA into the OS trust store, so on most hosts no extra configuration is needed.
In containers or environments where the OS trust store is not updated by the daemon, set the appropriate CA bundle environment variable for your runtime:
# For the AWS SDKexport AWS_CA_BUNDLE=/sys/module/riptides/certs/ca-certificates.crt
# For Python requestsexport REQUESTS_CA_BUNDLE=/sys/module/riptides/certs/ca-certificates.crt
# For Node.jsexport NODE_EXTRA_CA_CERTS=/sys/module/riptides/certs/ca-certificates.crtSee Trusting the Riptides CA for the full list of runtime-specific environment variables.
Step 7: Make Plain HTTP Calls from Your Application
Section titled “Step 7: Make Plain HTTP Calls from Your Application”Your application makes standard HTTP requests to the AWS API. The kernel handles TLS and SigV4 signing transparently.
import requests
# No AWS SDK needed -- no credentials in the applicationresponse = requests.post( "https://bedrock-agent-runtime.us-east-1.amazonaws.com/agents/AGENT123/agentAliases/ALIAS456/sessions/session-001/text", json={ "inputText": "What is the status of my order?" }, headers={ "Content-Type": "application/json" })
print(response.json())Under the hood:
Credential provisioning (happens when you apply the CredentialBinding):
- The control plane authenticates to AWS STS using the workload’s SPIFFE JWT-SVID via
AssumeRoleWithWebIdentity. - AWS STS returns temporary credentials (access key, secret key, session token).
- The control plane pushes the credentials to the daemon, which loads them into the kernel module.
- Riptides automatically refreshes credentials before they expire.
At connection time:
- The application opens a connection to
bedrock-agent-runtime.us-east-1.amazonaws.com:443. - The daemon evaluates the connection context and sets a reference to the appropriate credential in the evaluation context.
- The kernel module intercepts the connection, checks the evaluation context for a credential reference, and signs the HTTP request with AWS SigV4.
- The signed request is forwarded to the AWS API over TLS.
How It Works: The OIDC Federation Flow (Reference)
Section titled “How It Works: The OIDC Federation Flow (Reference)”Phase 1 — Credential provisioning (triggered by CredentialBinding creation):
Riptides Control Plane | |-- (1) Workload has SPIFFE ID: spiffe://example.com/my-app/workload |-- (2) Control plane presents workload's JWT-SVID to AWS STS AssumeRoleWithWebIdentity |-- (3) AWS validates the JWT against the Riptides OIDC endpoint |-- (4) AWS returns temporary credentials (access key, secret key, session token) |-- (5) Control plane pushes credentials to daemon → daemon loads them into kernel module |-- (6) Credentials are automatically refreshed before expirationPhase 2 — Connection-time injection:
Workload (plain HTTP) | vRiptides Kernel Module (intercepts outbound connection) | |-- (1) Daemon evaluates connection context |-- (2) Daemon determines credential to inject; sets reference in eval context |-- (3) Kernel checks eval context for credential reference |-- (4) Kernel signs the HTTP request with SigV4 using the referenced credentials | vAWS API (e.g., Bedrock)The temporary credentials are automatically rotated before they expire. Your application is never aware that AWS credentials exist.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Likely Cause | Fix |
|---|---|---|
CredentialSource stuck in PENDING | OIDC provider not reachable from AWS | Verify the Riptides control plane URL is publicly accessible and the OIDC discovery endpoint returns valid metadata |
CredentialBinding state is not OK | Mismatched workloadID between CredentialBinding and WorkloadIdentity | Ensure both resources use the same workloadID value |
| Requests to AWS time out | Missing or incorrect Service address | Confirm the Service address matches the actual AWS endpoint hostname for your region |