Managing Secrets with helm-secrets and SOPS
Keep encrypted values files in git and let the helm-secrets plugin decrypt them at deploy time with SOPS, so passwords never sit in plaintext.
Plaintext passwords in a values file is the mistake everyone makes once. The values you pass to Helm end up base64-encoded in a Secret — which is not encryption — and worse, that file tends to get committed. You need real encryption at rest that still works with a normal Helm workflow.
SOPS + helm-secrets
SOPS (Secrets OPerationS, from Mozilla) encrypts only the values in a YAML file, leaving the keys readable, so a diff still shows which secret changed without revealing what it changed to. It encrypts against a KMS key — AWS KMS, GCP KMS, Azure Key Vault, or age/PGP for local setups.
The helm-secrets plugin wires SOPS into Helm. You reference an encrypted file with the secrets:// prefix (or helm secrets upgrade), and the plugin transparently decrypts it to a temp file, feeds it to Helm, then shreds it. Your git history holds only ciphertext; decryption needs the KMS key that CI and operators hold.
Why this beats the alternatives for a lot of teams
- Secrets live with the chart in git — reviewable, versioned, no separate secret store to keep in sync.
- Access is controlled by who can use the KMS key, not by filesystem permissions.
- It composes with normal
-flayering: plainvalues.yamlplus an encryptedsecrets.yaml.
For clusters that already run the External Secrets Operator or Vault, prefer having the chart reference an existing Secret. helm-secrets shines when you want GitOps-friendly secrets without standing up extra infrastructure.
Example
# One-time: install the plugin and encrypt a values file with SOPS + age
helm plugin install https://github.com/jkroepke/helm-secrets
export SOPS_AGE_RECIPIENTS=age1ql3z7... # your team's public key
sops --encrypt --encrypted-regex '^(password|token|apiKey)$' \
secrets.yaml > secrets.enc.yaml # commit ONLY the .enc file
# Deploy: plaintext base values + transparently-decrypted secrets
helm secrets upgrade --install my-web ./mychart \
-f values-prod.yaml \
-f secrets://secrets.enc.yaml \
-n web --atomic
# Inspect what is inside without leaving plaintext on disk
helm secrets decrypt secrets.enc.yamlWhen to use it
- A developer checks encrypted values files into Git using helm-secrets with SOPS so secrets are version-controlled and auditable without ever storing plaintext credentials in the repository.
- A platform team configures SOPS to use an AWS KMS key so only CI runners with the correct IAM role can decrypt the values files, eliminating shared passwords.
- An operator runs helm secrets upgrade to transparently decrypt a SOPS-encrypted values file and pass it to helm upgrade without ever writing the plaintext to disk.
More examples
Encrypt a secrets file with SOPS
Installs the helm-secrets plugin and encrypts a values file with an age public key, producing a ciphertext file safe to commit.
# Install helm-secrets plugin
helm plugin install https://github.com/jkroepke/helm-secrets
# Encrypt with age key
sops --encrypt --age $(cat ~/.config/sops/age/keys.txt | grep 'public key' | cut -d: -f2) \
values-secrets.yaml > values-secrets.enc.yamlDeploy with encrypted values
Uses the helm-secrets wrapper to decrypt the encrypted file on the fly and pass plaintext values to helm, without writing secrets to disk.
helm secrets upgrade --install my-app ./myapp \
-f values-prod.yaml \
-f values-secrets.enc.yaml \
-n productionSOPS config for KMS
Configures SOPS to encrypt any secrets values file using an AWS KMS key, restricting decryption to IAM roles with key access.
# .sops.yaml — root of the repo
creation_rules:
- path_regex: values-secrets.*\.yaml$
kms: arn:aws:kms:us-east-1:123456789:key/mrk-abc123
aws_profile: ci-deployer
Discussion