Skip to content

ArgoCD + CloudTaser Quickstart

Deploy CloudTaser into a Kubernetes cluster managed by ArgoCD in under 10 minutes. This guide covers deploying the operator via an ArgoCD Application, annotating workloads for secret injection, and handling common ArgoCD-specific considerations.

For the full integration reference including migration paths and comparison tables, see ArgoCD and GitOps Integration.


Prerequisites

  • An ArgoCD instance managing your target cluster
  • An EU-hosted Vault/OpenBao instance with Kubernetes auth configured
  • kubectl and argocd CLI tools

Step 1: Deploy CloudTaser via ArgoCD Application

Create an ArgoCD Application that deploys CloudTaser from its Helm chart.

cloudtaser-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cloudtaser
  namespace: argocd
spec:
  project: default
  source:
    chart: cloudtaser
    repoURL: https://charts.cloudtaser.io
    targetRevision: "0.5.14"
    helm:
      values: |
        namespace: cloudtaser-system
        operator:
          ha: true
          replicaCount: 2
          leaderElect: true
          vaultAddress: "https://vault.eu.example.com"
          image:
            repository: europe-west4-docker.pkg.dev/skipopsmain/cloudtaser/cloudtaser-operator
            tag: "v0.5.14-amd64"
        ebpf:
          enabled: true
          enforceMode: true
  destination:
    server: https://kubernetes.default.svc
    namespace: cloudtaser-system
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

Apply it:

kubectl apply -f cloudtaser-app.yaml

Or via the ArgoCD CLI:

argocd app create cloudtaser \
  --repo https://charts.cloudtaser.io \
  --helm-chart cloudtaser \
  --revision 0.5.14 \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace cloudtaser-system \
  --sync-policy automated \
  --auto-prune \
  --self-heal \
  --sync-option CreateNamespace=true

Pin the chart version

Always use a specific targetRevision in production instead of "*" to prevent unexpected upgrades during automatic syncs.


Step 2: Verify the Operator Is Running

Wait for ArgoCD to sync the application:

argocd app get cloudtaser

Expected status: Synced and Healthy.

Verify the operator pods:

kubectl get pods -n cloudtaser-system -l app.kubernetes.io/name=cloudtaser-operator

Expected: pods in Running state.

Verify the webhook is registered:

kubectl get mutatingwebhookconfiguration cloudtaser-operator-webhook

Step 3: Annotate a Workload

Add CloudTaser annotations to your application's pod template. This is the only change needed in your Git repository -- no secret values, no encrypted files.

deploy/myapp/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      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: myorg/myapp:v1.2.3

Commit and push. ArgoCD syncs the manifest, Kubernetes creates the pod, and the CloudTaser webhook intercepts it to inject the wrapper.

Nothing secret in Git

The annotations contain only references to vault paths and environment variable names. No secret values are stored in Git, etcd, or Kubernetes Secrets.


Step 4: Verify Injection

After ArgoCD syncs the workload:

# Check that the wrapper is running as PID 1
kubectl exec myapp-<pod-id> -- cat /proc/1/cmdline | tr '\0' ' '

Expected output starts with /cloudtaser/wrapper.

# Check wrapper logs for successful secret fetch
kubectl logs myapp-<pod-id> -c myapp 2>&1 | grep "secrets loaded"

Expected: "msg":"secrets loaded, starting child process","secret_count":2.


Using CloudTaserConfig for Shared Configuration

Instead of repeating vault address and role in every Deployment, create a CloudTaserConfig CR:

deploy/cloudtaser/config.yaml
apiVersion: cloudtaser.io/v1alpha1
kind: CloudTaserConfig
metadata:
  name: production
  namespace: default
spec:
  vaultAddress: "https://vault.eu.example.com"
  vaultRole: "cloudtaser"
  rotation: restart

Then reference it from workloads:

annotations:
  cloudtaser.io/inject: "true"
  cloudtaser.io/config: "production"
  cloudtaser.io/secret-paths: "secret/data/myapp/config"
  cloudtaser.io/env-map: "db_password=PGPASSWORD"

Sync waves

Deploy CloudTaserConfig resources before the workloads that reference them. Use ArgoCD sync waves:

metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "-1"

Helm Values for ArgoCD

Key Helm values relevant to ArgoCD deployments.

The unified cloudtaser chart exposes these value groups:

Prefix Description
operator.* Operator deployment (replicas, image, webhook config)
wrapper.* Default wrapper sidecar settings
ebpf.* eBPF daemonset (enable/disable, enforce mode)
s3proxy.* S3 encryption proxy defaults
networkPolicy.* Auto-generated NetworkPolicy for vault egress
pdb.* PodDisruptionBudget settings

See the full Helm Values Reference for all available values.

Example: Production HA configuration

operator:
  ha: true
  replicaCount: 3
  leaderElect: true
  vaultAddress: "https://vault.eu.example.com"
  webhook:
    failurePolicy: Fail
    timeoutSeconds: 10
  resources:
    requests:
      cpu: 100m
      memory: 128Mi
    limits:
      cpu: 500m
      memory: 256Mi

ebpf:
  enabled: true
  enforceMode: true
  reactiveKill: true

networkPolicy:
  enabled: true
  vaultCIDR: "10.0.0.0/8"
  vaultPort: 8200

pdb:
  enabled: true
  operator:
    minAvailable: 1

ArgoCD-Specific Considerations

Resource diff noise from injected containers

When CloudTaser injects the wrapper, ArgoCD sees a diff between the desired state (no wrapper) and the live state (wrapper injected by webhook). To prevent ArgoCD from showing these diffs as out-of-sync:

argocd-cm ConfigMap
data:
  resource.customizations.ignoreDifferences.all: |
    jsonPointers:
      - /spec/template/spec/initContainers
      - /spec/template/spec/containers/0/command
      - /spec/template/spec/containers/0/args
      - /spec/template/spec/volumes

Webhook timeout during sync

If the operator is being deployed in the same sync as workloads, the webhook may not be ready when ArgoCD creates workload pods. Use sync waves to ensure the operator is deployed first:

# CloudTaser operator Application
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "-1"
# Workload Applications
metadata:
  annotations:
    argocd.argoproj.io/sync-wave: "0"

App of Apps pattern

For multi-cluster deployments, use the ArgoCD App of Apps pattern with cluster-specific values:

apps/cloudtaser.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cloudtaser
  namespace: argocd
spec:
  project: default
  source:
    chart: cloudtaser
    repoURL: https://charts.cloudtaser.io
    targetRevision: "0.5.14"
    helm:
      valueFiles:
        - values-base.yaml
        - values-{{ .Values.cluster }}.yaml
  destination:
    server: '{{ .Values.clusterServer }}'
    namespace: cloudtaser-system

Troubleshooting

Symptom Cause Fix
ArgoCD shows Degraded for operator Webhook cert not yet generated Wait 30 seconds for cert generation, then check operator logs
Pods fail to create after sync Webhook not ready (failurePolicy: Fail) Use sync waves to deploy operator before workloads
ArgoCD shows out-of-sync on Deployments Injected containers differ from desired state Add ignoreDifferences to ArgoCD ConfigMap (see above)
Sync succeeds but secrets missing Vault auth not configured for this cluster Run cloudtaser validate --vault-address <url>

For the full troubleshooting guide, see Troubleshooting Decision Trees.