Skip to content

Secret Management (SOPS + Age)

Key Concepts

  • Age generates a keypair. Public key goes in .sops.yaml. Private key stays local (~/.config/sops/age/keys.txt).
  • SOPS encrypts/decrypts files using the Age public key. Encrypted files are safe to commit.
  • .secrets/ is gitignored — decrypted values live here only during active sessions.

Key Lifecycle

Generate operator key

bash mkdir -p ~/.config/sops/age age-keygen -o ~/.config/sops/age/keys.txt cat ~/.config/sops/age/keys.txt # note the public key line

Add key to .sops.yaml

Edit .sops.yaml and replace age1REPLACE_WITH_... with your public key.

Encrypt a new secret file

bash cat > /tmp/mysecret.yaml <<EOF my_key: my_value EOF sops --encrypt --age age1YOURPUBLICKEY /tmp/mysecret.yaml > secrets/local/mysecret.sops.yaml

Decrypt for use

```bash bash scripts/decrypt-secrets.sh local

Output: .secrets/local/mysecret.yaml

```

Edit in-place

bash sops secrets/local/cluster.sops.yaml

Rotate key

```bash sops updatekeys secrets/local/cluster.sops.yaml

Add new recipient to .sops.yaml first

```

CI Key

Store the CI Age private key as SOPS_AGE_KEY GitHub Actions secret. Add the corresponding public key to all path_regex entries in .sops.yaml.

Rules

  1. Never commit .secrets/ — it is gitignored
  2. Never hardcode secrets in HCL, YAML, or shell scripts
  3. All secret files must end in .sops.yaml
  4. detect-secrets pre-commit hook will block plaintext leaks