DevOps Peach

GitOps with Argo CD · Argo CD Security and Operations · Lesson 2 of 4

Secrets and repository credentials

Never commit plain Kubernetes Secrets; use Sealed Secrets, External Secrets or SOPS. Give Argo CD read-only repo access with deploy keys stored as labelled Secrets.

Practice interactively →

GitOps says "everything in Git" — but a Kubernetes Secret is only base64, not encrypted. Committing one leaks it to everyone who can read the repo, forever. Choose one of these patterns instead:

Pattern What is in Git Who decrypts
Sealed Secrets A SealedSecret, encrypted with the controller's public key The sealed-secrets controller in the cluster
External Secrets Operator An ExternalSecret that points to a key in a vault ESO fetches from AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, HashiCorp Vault
SOPS (+ KSOPS / helm-secrets) A YAML file encrypted with age/KMS A plugin in the repo server at render time
# Sealed Secrets: encrypt locally, commit only the sealed file
kubectl create secret generic shop-db --from-literal=password='changeme-example' \
  --dry-run=client -o yaml | kubeseal --format yaml > sealed-shop-db.yaml
# External Secrets: Git holds a reference, the value stays in the vault
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: shop-db, namespace: shop-prod }
spec:
  refreshInterval: 1h
  secretStoreRef: { name: aws-secrets, kind: ClusterSecretStore }
  target: { name: shop-db }
  data:
    - secretKey: password
      remoteRef: { key: prod/shop/db, property: password }

External Secrets is the most common choice when the company already has a vault: rotation happens in the vault, Git never sees a value. Give the ExternalSecret an earlier sync wave than the Deployment that uses it.

Repository credentials

Argo CD needs to read private repos. Use a read-only deploy key (SSH) or a token with read scope only — never a person's account.

ssh-keygen -t ed25519 -f argocd-shop-config -N '' -C argocd@example.com   # add the .pub as a read-only deploy key
argocd repo add git@github.com:example-org/shop-config.git --ssh-private-key-path argocd-shop-config
argocd repo list

Declaratively, a repository is a Secret with a special label:

apiVersion: v1
kind: Secret
metadata:
  name: repo-shop-config
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository     # or repo-creds for a URL-prefix template
stringData:
  url: git@github.com:example-org/shop-config.git
  sshPrivateKey: |
    (from your secret store - do not commit this file)

Rule: Argo CD should be able to read Git, and Git should never be able to read a secret.

Practice interactively →