Vault / OpenBao Integration
This guide walks through integrating HashiCorp Vault (or OpenBao) with Riptides so that workloads can retrieve secrets — API keys, database passwords, cloud credentials — without ever storing Vault tokens inside the cluster.
How It Works
Section titled “How It Works”Every workload managed by Riptides receives a SPIFFE SVID (X.509 certificate). When a workload needs a secret from Vault, Riptides presents that SVID as a JWT to Vault’s JWT auth method. Vault validates the JWT against the Riptides control plane’s OIDC discovery endpoint, confirms the workload’s SPIFFE ID matches the configured role, and issues the requested secret. No long-lived Vault tokens are stored or distributed.
The flow:
- The control plane reads the CredentialBinding and presents the workload’s JWT-SVID to Vault’s JWT auth method.
- Vault validates the JWT using the issuer URL.
- Vault returns the requested credential.
- The control plane pushes the credential to the daemon, which loads it into the kernel.
- The kernel injects the credential into outbound requests at connection time.
Prerequisites
Section titled “Prerequisites”- A running Riptides control plane
- A Vault (or OpenBao) instance reachable from the cluster
kubectlaccess to theriptides-systemnamespace
Step 1: Configure Vault JWT Auth Method
Section titled “Step 1: Configure Vault JWT Auth Method”Enable the JWT auth method in Vault and point it at the Riptides control plane’s OIDC discovery URL.
# Enable the JWT auth method at a custom pathvault auth enable -path=jwt jwt
# Configure it to use the Riptides control plane for token validationvault write auth/jwt/config \ oidc_discovery_url="https://<your-controlplane-url>" \ default_role="<default-role-name>"Replace <your-controlplane-url> with the address of your Riptides control plane (for example, controlplane.example.com).
Step 2: Create a Vault Policy
Section titled “Step 2: Create a Vault Policy”Define a policy that grants read access to the secret path your workload needs.
vault policy write my-api-keys - <<EOFpath "secret/data/creds/my-role" { capabilities = ["read"]}EOFStep 3: Create a Vault Role
Section titled “Step 3: Create a Vault Role”Bind the policy to a role that accepts JWTs from the Riptides control plane. The bound_audiences field must match the audience you configure in the CredentialSource, and bound_subject should match the workload’s SPIFFE ID.
vault write auth/jwt/role/my-api-keys \ role_type="jwt" \ bound_audiences="<your-vault-audience>" \ bound_subject="spiffe://<trust-domain>/<workload-path>" \ user_claim="sub" \ token_policies="my-api-keys" \ token_ttl="1h"Step 4: Create a CredentialSource (Vault Token Type)
Section titled “Step 4: Create a CredentialSource (Vault Token Type)”The CredentialSource tells Riptides where Vault lives and which secret to fetch. The token type is used when Vault returns a value you want to inject as a bearer token or API key.
apiVersion: core.riptides.io/v1alpha1kind: CredentialSourcemetadata: name: vault-api-keys namespace: riptides-systemspec: vault: address: "https://vault.example.com" audience: - "your-vault-audience" jwtAuthMethodPath: jwt path: "secret/creds/my-role" role: "my-api-keys" type: token: source: api_keyField reference:
| Field | Description |
|---|---|
address | Full URL of the Vault server. |
audience | List of audiences included in the JWT presented to Vault. Must match the role’s bound_audiences. |
jwtAuthMethodPath | Mount path of the JWT auth method in Vault. |
path | Vault secret path to read from. |
role | Vault role name to authenticate as. |
type.token.source | Field name inside the Vault response to extract (e.g., api_key, token, secret). |
Apply it:
riptides-cli ctl apply -f credentialsource-vault.yamlVerify the source is available:
riptides-cli ctl get credentialsource vault-api-keys# STATE should show AVAILABLEStep 5: Create a Service for the Target API
Section titled “Step 5: Create a Service for the Target API”Define an external Service so Riptides knows where the API lives. The labels on this Service will be referenced by the egress selectors and injection selectors.
apiVersion: core.riptides.io/v1alpha1kind: Servicemetadata: name: my-api-svc namespace: riptides-systemspec: addresses: - address: api.example.com port: 443 external: true labels: api: my-apiriptides-cli ctl apply -f service-api.yamlStep 6: Create a CredentialBinding
Section titled “Step 6: Create a CredentialBinding”The CredentialBinding connects a CredentialSource to a workload and configures how the credential is delivered. You can use injection (the kernel adds the credential to outbound requests matching selector labels) and/or sysfs (credential is written to a file on the host, readable by the workload process).
apiVersion: core.riptides.io/v1alpha1kind: CredentialBindingmetadata: name: vault-api-keys-binding namespace: riptides-systemspec: credentialSource: vault-api-keys propagation: injection: selectors: - api: my-api sysfs: {} workloadID: "my-namespace/app/my-workload"Propagation modes:
injection: The daemon evaluates the connection context and determines which services receive the credential based on the selector labels. The kernel then injects the credential (e.g., as anAuthorization: Bearerheader) into matching outbound requests. No code changes needed.sysfs: The credential is written to a file at a deterministic path under/sys/module/riptides/credentials/. Your workload can read it directly.
When both are specified, the credential is available through either mechanism.
riptides-cli ctl apply -f credentialbinding-vault.yamlAfter applying, check the binding status:
riptides-cli ctl get credentialbinding vault-api-keys-binding -o yamlA healthy binding shows state: OK and, when sysfs is enabled, a sysfs.files section with the path to the credential file:
status: state: OK sysfs: files: - path: /sys/module/riptides/credentials/<hash>/vault-api-keys-binding/token.jwt type: TOKENStep 7: Create a WorkloadIdentity with Egress
Section titled “Step 7: Create a WorkloadIdentity with Egress”The WorkloadIdentity assigns a SPIFFE ID to your workload and enables TLS intercept for outbound connections. The CredentialBinding created in the previous step controls which services receive the credential via its propagation.injection.selectors.
apiVersion: core.riptides.io/v1alpha1kind: WorkloadIdentitymetadata: name: my-workload namespace: riptides-systemspec: connection: tls: mode: PERMISSIVE intercept: true scope: daemonGroup: id: "<cluster>/<daemongroup-path>" selectors: - k8s:label:app: my-workload k8s:pod:namespace: my-namespace process:name: node workloadID: "my-namespace/app/my-workload"Key fields:
connection.tls.intercept: true: Tells the kernel to intercept outbound connections and handle TLS + credential injection.
riptides-cli ctl apply -f workloadidentity.yamlStep 8: Configure the Riptides CA Bundle
Section titled “Step 8: Configure the Riptides CA Bundle”Because the egress rule uses tls.intercept: true, the kernel module terminates and re-originates the TLS connection. Applications that perform their own TLS certificate verification need to trust the Riptides CA.
Set the appropriate CA bundle environment variable for your application:
# 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.crt
# For cURLexport CURL_CA_BUNDLE=/sys/module/riptides/certs/ca-certificates.crtIf your application uses the injection propagation mode exclusively (the kernel injects credentials into plain HTTP requests), the kernel handles TLS entirely and no CA configuration is needed. The CA bundle is only required when the application itself initiates a TLS connection to a destination where tls.intercept: true is configured.
See Trusting the Riptides CA for the full list of supported environment variables.
Cloud Credential Types
Section titled “Cloud Credential Types”In addition to the token type, Vault CredentialSources support cloud-native credential generation. These use Vault’s secrets engines to produce short-lived cloud credentials:
spec: vault: address: "https://vault.example.com" audience: - "your-vault-audience" jwtAuthMethodPath: jwt path: "aws/creds/my-role" role: "my-aws-role" type: aws: {}Vault’s AWS secrets engine generates temporary IAM credentials. The workload receives AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN.
spec: vault: address: "https://vault.example.com" audience: - "your-vault-audience" jwtAuthMethodPath: jwt path: "gcp/token/my-role" role: "my-gcp-role" type: gcp: {}spec: vault: address: "https://vault.example.com" audience: - "your-vault-audience" jwtAuthMethodPath: jwt path: "azure/creds/my-role" role: "my-azure-role" type: azure: {}These cloud types remove the need for static cloud credentials entirely. Vault generates short-lived credentials on demand, and Riptides delivers them transparently to the workload.
Verification
Section titled “Verification”After deploying all resources, confirm the end-to-end flow:
-
CredentialSource is
AVAILABLE:Terminal window riptides-cli ctl get credentialsource vault-api-keys -
CredentialBinding is
OK:Terminal window riptides-cli ctl get credentialbinding vault-api-keys-binding -
WorkloadIdentity is assigned:
Terminal window riptides-cli ctl get workloadidentity my-workload -
Your workload can reach the API without any credential configuration in its code or environment variables. The Riptides kernel handles authentication transparently.