Skip to content

CloudTaserConfig CRD

The CloudTaserConfig custom resource provides a reusable, namespace-scoped configuration object for CloudTaser sidecar injection. Instead of specifying vault addresses, secret paths, and environment mappings as individual pod annotations, you define them once in a CR and reference it from your workloads.


API Details

Field Value
API Group api.cloudtaser.io
API Version v1alpha1
Kind CloudTaserConfig
Short Name ctc
Scope Namespaced
# List all CloudTaserConfig resources
kubectl get ctc -A

# Describe a specific config
kubectl describe ctc my-app-config -n production

Spec Fields

vaultAddress

Type string
Required Yes

The URL of the EU-hosted OpenBao or Vault instance, including scheme and port.

spec:
  vaultAddress: "https://vault.eu-west-1.example.com:8200"

vaultRole

Type string
Required Yes

The Vault Kubernetes auth role name. This role must be configured in Vault to accept service account tokens from the target namespace and service accounts.

spec:
  vaultRole: "my-app-role"

vaultAuthPath

Type string
Required No
Default "auth/kubernetes"

The mount path of the Kubernetes auth method in Vault. Override this when using a non-default auth mount.

spec:
  vaultAuthPath: "auth/kubernetes-production"

secretPaths

Type []string
Required Yes

A list of Vault KV secret paths to fetch at pod startup. Each path is read in order, and all key-value pairs from each path are made available to the wrapped application process.

spec:
  secretPaths:
    - "secret/data/myapp/database"
    - "secret/data/myapp/api-keys"
    - "secret/data/shared/tls-certs"

envMap

Type map[string]map[string]string
Required No

Maps Vault secret fields to specific environment variable names. The outer key is the Vault path (must match an entry in secretPaths), and the inner map provides field: ENV_VAR mappings.

spec:
  envMap:
    "secret/data/myapp/database":
      username: DB_USER
      password: DB_PASS
      host: DB_HOST
    "secret/data/myapp/api-keys":
      stripe_key: STRIPE_SECRET_KEY
      sendgrid_key: SENDGRID_API_KEY

Unmapped fields

Fields not listed in envMap are still injected into the process environment using their original Vault field names. The map provides renaming, not filtering.

wrapperImage

Type string
Required No
Default Uses the image configured in the operator

Overrides the wrapper container image. Useful when pinning specific wrapper versions per workload or using a private registry mirror.

spec:
  wrapperImage: "europe-docker.pkg.dev/myproject/cloudtaser/wrapper:v0.2.0"

wrapperResources

Type corev1.ResourceRequirements
Required No
Default requests: {cpu: 10m, memory: 32Mi}, limits: {cpu: 100m, memory: 64Mi}

Resource requests and limits for the injected wrapper init container and sidecar.

spec:
  wrapperResources:
    requests:
      cpu: "20m"
      memory: "48Mi"
    limits:
      cpu: "200m"
      memory: "128Mi"

namespaceSelector

Type metav1.LabelSelector
Required No

When set, restricts which namespaces this config can be referenced from. Pods in namespaces that do not match the selector will not be injected even if they reference this config.

spec:
  namespaceSelector:
    matchLabels:
      environment: production
      team: payments

Status Fields

The status subresource is managed by the operator and is read-only.

ready

Type bool

Indicates whether the config has been validated and is ready for use. The operator validates vault connectivity and auth configuration.

message

Type string

A human-readable message describing the current state, especially useful when ready is false.

injectedPods

Type int

The number of pods currently running with this config applied.

lastValidated

Type metav1.Time

Timestamp of the last successful validation of the vault connection and auth configuration.

conditions

Type []metav1.Condition

Standard Kubernetes conditions providing detailed status information.

Condition Type Description
VaultReachable The operator can reach the configured vault address.
AuthConfigured The Kubernetes auth role is valid and accepts tokens from the target namespace.
SecretsAccessible The configured secret paths are readable with the given role.
Ready All validation checks have passed.

Full Example

cloudtaserconfig-full.yaml
apiVersion: api.cloudtaser.io/v1alpha1
kind: CloudTaserConfig
metadata:
  name: payment-service
  namespace: production
  labels:
    app.kubernetes.io/name: payment-service
    app.kubernetes.io/part-of: payments
spec:
  vaultAddress: "https://vault.eu-west-1.example.com:8200"
  vaultRole: "payment-service"
  vaultAuthPath: "auth/kubernetes"
  secretPaths:
    - "secret/data/payments/database"
    - "secret/data/payments/stripe"
    - "secret/data/payments/internal-api"
  envMap:
    "secret/data/payments/database":
      username: PGUSER
      password: PGPASSWORD
      host: PGHOST
      port: PGPORT
      dbname: PGDATABASE
    "secret/data/payments/stripe":
      secret_key: STRIPE_SECRET_KEY
      webhook_secret: STRIPE_WEBHOOK_SECRET
    "secret/data/payments/internal-api":
      token: INTERNAL_API_TOKEN
  wrapperImage: "europe-docker.pkg.dev/skipops/cloudtaser/wrapper:v0.2.0"
  wrapperResources:
    requests:
      cpu: "10m"
      memory: "32Mi"
    limits:
      cpu: "100m"
      memory: "64Mi"
  namespaceSelector:
    matchLabels:
      environment: production

Usage Pattern

Step 1: Create the CloudTaserConfig in your target namespace.

kubectl apply -f cloudtaserconfig-full.yaml

Step 2: Verify the config is ready.

kubectl get ctc payment-service -n production

Expected output:

NAME              READY   INJECTED-PODS   LAST-VALIDATED         AGE
payment-service   True    0               2026-03-21T10:00:00Z   5s

Step 3: Reference the config from your Deployment annotations.

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-service
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: payment-service
  template:
    metadata:
      labels:
        app: payment-service
      annotations:
        cloudtaser.io/inject: "true"
        cloudtaser.io/config: "payment-service"
        cloudtaser.io/rotation: "sighup"
        cloudtaser.io/ebpf: "true"
    spec:
      serviceAccountName: payment-service
      containers:
        - name: api
          image: eu.gcr.io/myproject/payment-service:v2.1.0
          ports:
            - containerPort: 8080

Step 4: Confirm injection after pod creation.

kubectl get pods -n production -l app=payment-service -o jsonpath='{.items[0].metadata.annotations.cloudtaser\.io/status}'

Expected output: injected


Troubleshooting

Config not found

If the webhook cannot find the referenced CloudTaserConfig in the pod's namespace, the pod will be admitted without injection and cloudtaser.io/status will be set to "error". Check that the CR name matches exactly and exists in the same namespace as the pod.

Config not ready

If the CloudTaserConfig exists but its ready status is false, the webhook will still inject the sidecar, but the wrapper may fail to authenticate at runtime. Always verify kubectl get ctc shows READY: True before deploying workloads.

Check operator logs for detailed validation errors:

kubectl logs -n cloudtaser-system deployment/cloudtaser-operator -f