TL;DR

1
2
3
4
5
gpg --list-secret-keys --keyid-format=long   # get the fingerprint
# .sops.yaml → creation_rules: pgp: <FINGERPRINT>
sops -e -i secrets.yaml                        # encrypt in place
sops secrets.yaml                              # edit decrypted, re-encrypt on save
sops -d secrets.yaml                           # decrypt to stdout

SOPS encrypts the values of a structured file (YAML/JSON/env/ini) and leaves the keys readable, so a secrets.enc.yaml is a clean, reviewable git diff. Decryption needs the GPG private key on the machine.

Prerequisites

gpg and sops installed. Check: gpg --version and sops --version.

1. Get a GPG key

Use an existing key or create one:

1
2
gpg --full-generate-key
gpg --list-secret-keys --keyid-format=long

Copy the 40-char fingerprint (the long hex line under sec). That fingerprint is what SOPS references — not the short key id.

2. Tell SOPS which key to use

Put a .sops.yaml at the repo root so you never pass keys by hand:

1
2
3
creation_rules:
  - path_regex: \.enc\.ya?ml$
    pgp: "FBC7B9E2A4F9289AC0C1D4843C1FCF3D"
  • path_regex scopes the rule to files you name *.enc.yaml.
  • pgp takes one or more comma-separated fingerprints (multiple recipients = anyone with one of those private keys can decrypt).

3. Encrypt, edit, decrypt

1
2
3
sops -e -i secrets.enc.yaml     # encrypt in place (-i), values only
sops secrets.enc.yaml           # open $EDITOR decrypted; re-encrypts on save
sops -d secrets.enc.yaml        # decrypt to stdout

Commit the encrypted file. The plaintext never touches git.

What SOPS touches

PartEncrypted?
Values (password: hunter2)yes
Keys / structure (password:)no (readable diffs)
Extra sops: metadata blockadded (recipients, MAC)

Traps

  • Subkeys: to force a specific GnuPG subkey, append ! to the fingerprint in creation_rules (e.g. A3D6...E8F!). Only honored since SOPS 3.9.3.
  • Different gpg binary: set SOPS_GPG_EXEC to point SOPS at a wrapper instead of the default gpg.
  • Back up the private key. Lose it and the encrypted files are gone — SOPS is only as recoverable as the GPG key. Add a second recipient (a backup/escrow key) in creation_rules from day one.
  • Rotating recipients: after editing creation_rules, run sops updatekeys secrets.enc.yaml to re-encrypt the file key for the new set.
  • Only structured files get value-level encryption; for a blob use sops -e --input-type binary.

Git and automation

  • The encrypted file is what lives in git; reviewers see key names, never values.
  • On any host/CI that must decrypt, import the private key into its GPG keyring first (gpg --import), then sops -d.
  • Ansible can consume SOPS directly via the community.sops collection (e.g. the community.sops.sops lookup / load_vars) so playbooks read secrets without a manual decrypt step. Verify the collection is installed on the control node.

See also