CoursesFluxAdvanced

Secrets: SOPS & Sealed Secrets

Encrypted secrets in Git.

Advanced12 min · lesson 10 of 12

Flux faces the same GitOps secrets problem — no plaintext in Git — and integrates the standard solutions natively. SOPS is first-class: the kustomize-controller can decrypt SOPS-encrypted files at reconcile time using a key it holds (age or a cloud KMS), so encrypted secrets live safely in Git and are decrypted only in-cluster during apply. Sealed Secrets and the External Secrets Operator also work, since Flux just applies whatever CRDs you give it.

kustomization (SOPS)
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
spec:
path: ./apps
decryption:
provider: sops
secretRef: { name: sops-age } # the age/KMS key Flux decrypts with
# secrets in Git are SOPS-encrypted; Flux decrypts them at apply time only
# create the key: `flux create secret` / an age key stored as a Secret

Where the trust sits

With SOPS, the decryption key Flux holds is the crown jewel — anyone with it decrypts every secret, so store it as a tightly-controlled Secret (or, better, keep the key in a cloud KMS Flux calls, so the raw key never sits in the cluster). With External Secrets, the trust moves to the operator’s access to Vault/the cloud store. Either way, the pattern is the same: ciphertext or references in Git, the unlocking key protected and scoped, and plaintext existing only transiently in-cluster.

terminal
# encrypt a secret for Git with SOPS (age); Flux decrypts it at reconcile
$ sops --encrypt --age $AGE_PUBKEY db-secret.yaml > db-secret.enc.yaml
$ git add db-secret.enc.yaml # safe: ciphertext only
The SOPS key is the whole secrets boundary
Flux’s SOPS decryption is only as strong as the key it uses: a leaked age key or over-broad KMS access exposes every secret in the repo. Store the key as a locked-down Secret (or keep it in KMS so Flux calls out to decrypt and the key never rests in-cluster), scope who and what can use it, and rotate on exposure. GitOps secrets are safe because of that key’s protection, not because they are in Git.