Skip to content

Operator Installation

The CloudTaser operator is the core component that enables secret injection into Kubernetes workloads. It runs as a Deployment with a mutating admission webhook that intercepts pod creation, injects the wrapper binary via an init container, and rewrites container entrypoints so secrets are fetched from an EU-hosted vault directly into process memory.

Prerequisites

Before installing the operator, ensure the following requirements are met.

Required

All three prerequisites are mandatory. The operator will not function without a compatible Kubernetes cluster, Helm, and a reachable vault instance.

Requirement Minimum Recommended
Kubernetes 1.28+ 1.30+
Helm 3.x Latest 3.x
Vault OpenBao 2.x or HashiCorp Vault 1.15+ OpenBao (no license concerns)

Kubernetes Cluster

The operator is tested on GKE Standard, EKS (managed node groups), and AKS (regular node pools). Serverless environments such as GKE Autopilot and AWS Fargate are not supported because the eBPF agent requires host-level access.

EU-Hosted Vault

CloudTaser requires an OpenBao or HashiCorp Vault instance hosted in the EU. This is the foundation of the data sovereignty guarantee -- secrets transit only between the EU vault and process memory on the Kubernetes node. They never pass through etcd, Kubernetes Secrets, or any US-controlled storage layer.

Recommended EU regions

  • GCP: europe-west1 (Belgium), europe-west3 (Frankfurt), europe-west4 (Netherlands)
  • AWS: eu-central-1 (Frankfurt), eu-west-1 (Ireland), eu-west-3 (Paris)
  • Azure: westeurope (Netherlands), germanywestcentral (Frankfurt)
  • Self-hosted: Any EU data center

The vault instance must have:

  • KV v2 secrets engine enabled
  • Kubernetes auth backend enabled
  • TLS configured (the wrapper validates the server certificate)
  • Network reachability from the Kubernetes cluster

Installation

Install the operator and all CloudTaser components using the unified Helm chart from the OCI registry:

helm install cloudtaser oci://ghcr.io/skipopsltd/cloudtaser-helm/cloudtaser \
  --namespace cloudtaser-system \
  --create-namespace \
  --set operator.vaultAddress=https://vault.eu.example.com

OCI registry authentication

The CloudTaser Helm chart is hosted on GitHub Container Registry. If your cluster requires authentication to pull from ghcr.io, create an image pull secret and reference it in your values:

kubectl create secret docker-registry ghcr-credentials \
  --docker-server=ghcr.io \
  --docker-username=<username> \
  --docker-password=<token> \
  --namespace cloudtaser-system
helm install cloudtaser oci://ghcr.io/skipopsltd/cloudtaser-helm/cloudtaser \
  --namespace cloudtaser-system \
  --create-namespace \
  --set operator.vaultAddress=https://vault.eu.example.com \
  --set imagePullSecrets[0].name=ghcr-credentials

Key Helm Values

The following values control operator behavior. For the full values reference, see Helm Values.

values.yaml
operator:
  # Vault endpoint (required)
  vaultAddress: "https://vault.eu.example.com"

  # Container image
  image:
    repository: ghcr.io/skipopsltd/cloudtaser-operator
    tag: "v0.4.18-amd64"
    pullPolicy: IfNotPresent

  # Replicas (use 3+ for production HA)
  replicaCount: 1
  ha: false
  leaderElect: false

  # Resource requests and limits
  resources:
    requests:
      cpu: 50m
      memory: 64Mi
    limits:
      cpu: 200m
      memory: 128Mi

  # Webhook configuration
  webhook:
    port: 9443
    failurePolicy: Fail      # (1)!
    timeoutSeconds: 10
    # Provide your own TLS cert (optional)
    # certSecret: my-webhook-certs

# Wrapper image injected into workload pods
wrapper:
  image:
    repository: ghcr.io/skipopsltd/cloudtaser-wrapper
    tag: "v0.0.14-amd64"
  1. Fail means pods will not be created if the webhook is unavailable. Use Ignore only in non-production environments where you prefer availability over enforcement.

Verify Installation

After the Helm install completes, verify the operator is running:

Check Pods

kubectl get pods -n cloudtaser-system

Expected output:

NAME                                    READY   STATUS    RESTARTS   AGE
cloudtaser-operator-6f8b9c7d4-x2k9m    1/1     Running   0          45s
cloudtaser-ebpf-node1                   1/1     Running   0          45s

Check Webhook Configuration

kubectl get mutatingwebhookconfigurations | grep cloudtaser

Expected output:

cloudtaser-webhook   1          45s

Verify the webhook is configured with the correct CA bundle:

kubectl get mutatingwebhookconfiguration cloudtaser-webhook -o yaml

The caBundle field should be populated and the rules section should target pod creation.

Check Operator Logs

kubectl logs -n cloudtaser-system deployment/cloudtaser-operator --tail=20

Look for a log line confirming the webhook server has started and vault connectivity is established.

Run Validation (Optional)

If you have the CloudTaser CLI installed, run a full validation:

cloudtaser validate \
  --vault-address https://vault.eu.example.com

Create a CloudTaserConfig CR

Instead of specifying vault configuration on every workload via annotations, you can define a shared CloudTaserConfig custom resource. Workloads reference the config by name, reducing annotation duplication and centralizing management.

cloudtaserconfig.yaml
apiVersion: api.cloudtaser.io/v1alpha1
kind: CloudTaserConfig
metadata:
  name: default
  namespace: cloudtaser-system
spec:
  vaultAddress: "https://vault.eu.example.com"
  vaultRole: "cloudtaser"
  secretPaths:
    - "secret/data/shared/config"
  envMap:
    db_password: PGPASSWORD
    api_key: API_KEY
  rotation:
    strategy: restart     # restart | sighup | none
    interval: 1h

Apply the config:

kubectl apply -f cloudtaserconfig.yaml

Workloads can reference this config with a single annotation instead of specifying all vault parameters individually:

annotations:
  cloudtaser.io/inject: "true"
  cloudtaser.io/config: "default"

Annotate Your First Workload

Add CloudTaser annotations to a Deployment to enable secret injection:

myapp-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
      annotations:
        cloudtaser.io/inject: "true"
        cloudtaser.io/config: "default"
    spec:
      containers:
        - name: myapp
          image: myapp:latest
myapp-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
      annotations:
        cloudtaser.io/inject: "true"
        cloudtaser.io/vault-address: "https://vault.eu.example.com"
        cloudtaser.io/vault-role: "cloudtaser"
        cloudtaser.io/secret-paths: "secret/data/myapp/config"
        cloudtaser.io/env-map: "db_password=PGPASSWORD,api_key=API_KEY"
    spec:
      containers:
        - name: myapp
          image: myapp:latest

Apply and verify:

kubectl apply -f myapp-deployment.yaml
kubectl get pods -l app=myapp

When the pod starts, the operator:

  1. Injects an init container that copies the wrapper binary to a memory-backed emptyDir (/cloudtaser/)
  2. Rewrites the container entrypoint to /cloudtaser/wrapper
  3. The wrapper authenticates to vault using Kubernetes auth, fetches secrets, and fork+execs the original application with secrets as environment variables

Secrets in memory only

Secrets exist only in process memory. They never touch etcd, Kubernetes Secrets, or disk. The eBPF agent blocks attempts to read /proc/pid/environ, /proc/pid/mem, and ptrace calls on protected processes.

Troubleshooting

Symptom Cause Fix
Pod stuck in Init Wrapper init container cannot pull image Check imagePullSecrets and registry access
Pod CrashLoopBackOff Wrapper cannot reach vault Verify vault endpoint is reachable from the cluster
Webhook not firing MutatingWebhookConfiguration missing or misconfigured Check kubectl get mutatingwebhookconfigurations
403 permission denied from vault Kubernetes auth role misconfigured Run cloudtaser connect or verify the vault role manually

For more details, see Troubleshooting.

Next Steps