SecretMapping CRD¶
The SecretMapping custom resource defines how existing Kubernetes Secrets map to OpenBao paths. It is typically auto-generated by the cloudtaser-cli target discover command during migration, but can also be created manually. When applied, the operator automatically injects matching workloads with the cloudtaser wrapper, replacing their dependency on Kubernetes Secrets with direct OpenBao access.
SecretMapping enables incremental migration from Kubernetes Secrets to OpenBao-based secret delivery. The CLI discovers existing secret references automatically, generates mapping definitions, and the operator handles the cutover. Teams can migrate one workload at a time without application code changes, maintaining continuity while progressively strengthening data sovereignty.
API Details¶
| Field | Value |
|---|---|
| API Group | api.cloudtaser.io |
| API Version | v1alpha1 |
| Kind | SecretMapping |
| Short Name | sm |
| Scope | Namespaced |
# List all SecretMappings
kubectl get sm -A
# Describe a specific mapping
kubectl describe sm payment-service-secrets -n production
Purpose¶
SecretMapping bridges the gap between existing Kubernetes Secrets and OpenBao-based secret delivery. During a migration:
- Discovery -- The CLI scans workloads and identifies which Kubernetes Secrets they reference (via
envFrom,env.valueFrom, and volume mounts). - Mapping -- The CLI generates SecretMapping CRs that map each K8s Secret to a corresponding OpenBao path.
- Migration -- The operator reads the SecretMapping, injects the wrapper into matching pods, and (optionally) removes the original Secret references.
This allows teams to migrate incrementally, one workload at a time, without changing application code.
Spec Fields¶
selector¶
| Type | metav1.LabelSelector |
| Required | Yes |
Label selector that identifies which workloads this mapping applies to. All pods matching the selector in the same namespace will receive cloudtaser injection based on this mapping.
vaultAddress¶
| Type | string |
| Required | Yes |
The URL of the EU-hosted OpenBao or OpenBao instance.
vaultRole¶
| Type | string |
| Required | Yes |
The OpenBao Kubernetes auth role for authenticating the matched workloads.
vaultAuthPath¶
| Type | string |
| Required | No |
| Default | "auth/kubernetes" |
The mount path of the Kubernetes auth method in OpenBao.
sources¶
| Type | []Source |
| Required | Yes |
An array of secret sources describing the mapping from original Kubernetes Secrets to OpenBao paths. Each entry represents one Kubernetes Secret that has been migrated.
Source Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
originalType |
string |
Yes | The type of original K8s secret reference: "Secret", "ConfigMap", or "ExternalSecret" |
originalRef |
string |
Yes | The name of the original Kubernetes Secret or ConfigMap |
vaultPath |
string |
Yes | OpenBao KV path where the secret data has been migrated |
envMapping |
map[string]string |
No | Maps original secret keys to environment variable names |
spec:
sources:
- originalType: "Secret"
originalRef: "payment-db-credentials"
vaultPath: "secret/data/payments/database"
envMapping:
username: PGUSER
password: PGPASSWORD
- originalType: "Secret"
originalRef: "stripe-api-key"
vaultPath: "secret/data/payments/stripe"
envMapping:
api_key: STRIPE_SECRET_KEY
stripOriginals¶
| Type | bool |
| Required | No |
| Default | false |
When true, the operator removes the original Kubernetes Secret references (envFrom, env.valueFrom, volume mounts) from the pod spec during injection. This ensures the pod no longer depends on Kubernetes Secrets at all.
Use with caution
Setting stripOriginals: true modifies the pod spec to remove Secret references. Verify that all referenced secrets have been migrated to OpenBao before enabling this. If a secret is missing from OpenBao, the application will fail to start.
Incremental migration
During migration, keep stripOriginals: false (the default). Both the original K8s Secret and OpenBao secret will be available. Once you have verified the application works with OpenBao secrets, set stripOriginals: true to complete the cutover.
Status Fields¶
The status subresource is managed by the operator and is read-only.
ready¶
| Type | bool |
Indicates whether the mapping has been validated and is active.
message¶
| Type | string |
A human-readable status message.
matchedWorkloads¶
| Type | int |
The number of workloads (Deployments, StatefulSets, DaemonSets, Jobs) whose pods match the selector.
migratedSecrets¶
| Type | int |
The number of source entries that have been validated as accessible in OpenBao.
Full Example¶
apiVersion: api.cloudtaser.io/v1alpha1
kind: SecretMapping
metadata:
name: payment-service-secrets
namespace: production
labels:
app.kubernetes.io/name: payment-service
app.kubernetes.io/managed-by: cloudtaser-cli
annotations:
cloudtaser.io/discovered-at: "2026-03-21T09:00:00Z"
cloudtaser.io/source-cluster: "gke-prod-eu-west1"
spec:
selector:
matchLabels:
app: payment-service
vaultAddress: "https://vault.eu-west-1.example.com:8200"
vaultRole: "payment-service"
vaultAuthPath: "auth/kubernetes"
sources:
- originalType: "Secret"
originalRef: "payment-db-credentials"
vaultPath: "secret/data/payments/database"
envMapping:
username: PGUSER
password: PGPASSWORD
host: PGHOST
port: PGPORT
dbname: PGDATABASE
- originalType: "Secret"
originalRef: "stripe-api-key"
vaultPath: "secret/data/payments/stripe"
envMapping:
secret_key: STRIPE_SECRET_KEY
webhook_secret: STRIPE_WEBHOOK_SECRET
- originalType: "Secret"
originalRef: "internal-api-token"
vaultPath: "secret/data/payments/internal-api"
envMapping:
token: INTERNAL_API_TOKEN
stripOriginals: false
Usage with the CLI¶
The typical workflow uses the CLI to generate SecretMappings automatically.
Discover existing secrets¶
This scans all workloads in the production namespace, identifies Kubernetes Secret references, and generates a SecretMapping YAML file for each workload.
Review and customize¶
Review the generated files and adjust envMapping or vaultPath values as needed. The CLI generates sensible defaults based on the original Secret keys.
Migrate secrets to the secret store¶
cloudtaser-cli target protect --mapping secretmappings/payment-service-secrets.yaml \
--secretstore-address https://vault.eu-west-1.example.com:8200
This copies the actual secret values from Kubernetes Secrets into the specified paths in the secret store.
Apply the mapping¶
Verify¶
Expected output:
Complete the cutover¶
Once verified, enable stripOriginals to remove the original K8s Secret dependencies:
kubectl patch sm payment-service-secrets -n production \
--type merge -p '{"spec":{"stripOriginals":true}}'
Restart the workload to apply the change:
Relationship to CloudTaserConfig¶
SecretMapping and CloudTaserConfig serve complementary purposes:
| CloudTaserConfig | SecretMapping | |
|---|---|---|
| Created by | Platform team, manually | CLI discover command |
| Use case | New workloads built for OpenBao | Migrating existing workloads from K8s Secrets |
| Selection | Referenced by annotation | Label selector (automatic matching) |
| Strips originals | Not applicable | Optional (stripOriginals) |
| Recommended for | Greenfield deployments | Brownfield migrations |
Both can coexist in the same namespace. If a pod matches both a SecretMapping selector and has a cloudtaser.io/config annotation, the explicit annotation takes precedence.