Reference¶
Scope
Look-up facts for SOPS 3.13.x: releases, file formats, key backends, CLI subcommands, environment variables, the .sops.yaml schema, the on-disk format, GitOps integration keys and a hardening checklist. For the reasoning behind these, see Explanation. For step-by-step tasks, see How-to Guides.
Release History¶
SOPS publishes signed binaries, .deb/.rpm packages, SBOMs and container images for each release. The project has no published LTS or support-window policy. Fixes land in the next patch or minor release of the current line (TBD: no official support policy found as of 2026-09).
| Version | Release date | Highlights |
|---|---|---|
| 3.13.3 | 2026-07-23 | Fixes a 3.13.2 regression that computed a wrong MAC for YAML lists containing comments. Fixes completion output |
| 3.13.2 | 2026-06-30 | exec-env/exec-file --user resets supplementary groups and sets HOME/USER/LOGNAME. JSON store keeps large int64 values. INI metadata newline fix |
| 3.13.1 | 2026-05-16 | Documentation moves from the README to getsops.io. Fixes the gpg-agent cache key for password-protected age keys |
| 3.13.0 | 2026-05-08 | SOPS_HC_VAULT_ALLOWLIST (Vault/OpenBao URL allowlist). SOPS_GCP_KMS_ENDPOINT and SOPS_GCP_KMS_UNIVERSE_DOMAIN. YAML inline comments preserved. SOPS_AGE_KEY accepts space-separated keys. Drops Go 1.24. cosign v3 signing |
| 3.12.2 | 2026-03-18 | Reverts the GCP quota-project change from 3.12.0 (it needed extra permissions). Cleans up temp files on Ctrl+C/SIGTERM during edit |
| 3.12.1 | 2026-02-22 | Re-release of 3.12.0 with no code changes (the 3.12.0 release failed) |
| 3.12.0 | 2026-02-19 (tag) | HuaweiCloud KMS backend. age hybrid post-quantum identities. SOPS_AGE_SSH_PRIVATE_KEY_CMD. SOPS_GCP_KMS_CLIENT_TYPE (gRPC or REST) |
| 3.11.0 | 2025-09-28 | Security: temp edit file is owner-only, and binary-store encryption-selection options are ignored. sops set --value-file and --value-stdin. Shell completion. Keys as YAML lists in .sops.yaml. Azure key version optional |
| 3.10.2 | 2025-04-14 | YAML store bug fix |
| 3.10.1 | 2025-03-31 | Re-release of 3.10.0 (the Go module cache held a different commit) |
| 3.10.0 | 2025-03-30 | Security: Shamir timing fix (GHSA-vq4h-9ghm-qmrr). age plugins, SSH keys as age recipients, passphrase-protected age identities, SOPS_AGE_KEY_CMD, SOPS_EDITOR, SOPS_CONFIG, set --idempotent, stdin for encrypt/decrypt |
| 3.9.0 | 2024-06-28 | Separate subcommands (encrypt, decrypt, edit, rotate, set, unset, filestatus). --mac-only-encrypted. --decryption-order. Comment-based encryption selection. Key-group merge |
| 3.8.0 | 2023-09-15 | First release under the getsops org: AWS SDK v2, refreshed PGP/Azure/GCP/Vault backends |
Dates are the GitHub release/tag dates. See the changelog and releases.
Distribution Artifacts¶
| Artifact | Name pattern (3.13.3 example) |
|---|---|
| Linux binary | sops-v3.13.3.linux.amd64, sops-v3.13.3.linux.arm64 |
| macOS binary | sops-v3.13.3.darwin.amd64, sops-v3.13.3.darwin.arm64, universal sops-v3.13.3.darwin |
| Windows binary | sops-v3.13.3.amd64.exe, sops-v3.13.3.arm64.exe |
| Packages | .deb and .rpm |
| Container images | ghcr.io/getsops/sops:v3.13.3 and quay.io/getsops/sops:v3.13.3 (Debian-based), plus -alpine tags |
| Supply chain | sops-v3.13.3.checksums.txt, cosign signatures, SPDX SBOMs |
| Go library | github.com/getsops/sops/v3 (the decrypt package). Building from source needs Go >= 1.25 |
File Formats¶
The store is chosen from the file extension, or from --input-type / --output-type (yaml, json, dotenv, ini, binary).
| Format | Extensions | What is encrypted | Limits |
|---|---|---|---|
| YAML | .yaml, .yml |
Leaf values and comments. Keys stay plaintext | No anchors/aliases. No top-level arrays. Multi-document streams share one sops block |
| JSON | .json |
Leaf values. Keys stay plaintext | No top-level arrays. Default indent is one tab |
| ENV (dotenv) | .env |
Values. Variable names stay plaintext | Flat key/value only |
| INI | .ini |
Values. Sections and keys stay plaintext | Metadata is flattened into a [sops] section |
| BINARY | anything else | The whole file as one blob, stored base64-encoded under data in a JSON document |
Encryption-selection options are ignored (since 3.11.0) |
Key Backends¶
| Backend | CLI flag | Env var (encrypt) | .sops.yaml creation-rule key |
Key-group key | Authentication |
|---|---|---|---|---|---|
| age (X25519, SSH, plugins, post-quantum) | --age |
SOPS_AGE_RECIPIENTS |
age |
age |
Local identity file, SOPS_AGE_KEY, SOPS_AGE_KEY_CMD, SSH key |
| PGP / GnuPG | --pgp |
SOPS_PGP_FP |
pgp |
pgp |
gpg-agent keyring (SOPS_GPG_EXEC overrides the binary) |
| AWS KMS | --kms (ARN+ROLE_ARN) |
SOPS_KMS_ARN |
kms (+ aws_profile) |
kms (arn, role, context, aws_profile) |
AWS SDK v2 default chain, profiles, assumed roles |
| GCP Cloud KMS | --gcp-kms |
SOPS_GCP_KMS_IDS |
gcp_kms |
gcp_kms (resource_id) |
Application Default Credentials, GOOGLE_OAUTH_ACCESS_TOKEN |
| Azure Key Vault | --azure-kv |
SOPS_AZURE_KEYVAULT_URLS |
azure_keyvault |
azure_keyvault (vaultUrl, key, version) |
DefaultAzureCredential (env, workload identity, managed identity, Azure CLI) |
| HashiCorp Vault / OpenBao Transit | --hc-vault-transit |
SOPS_VAULT_URIS |
hc_vault_transit_uri |
hc_vault |
VAULT_TOKEN or ~/.vault-token. SOPS_HC_VAULT_ALLOWLIST limits which servers are contacted |
| HuaweiCloud KMS (since 3.12.0) | --hckms (region:key-uuid) |
SOPS_HUAWEICLOUD_KMS_IDS |
hckms |
hckms (key_id) |
HUAWEICLOUD_SDK_AK/_SK/_PROJECT_ID, ~/.huaweicloud/credentials, instance metadata |
PGP status
PGP is not deprecated in SOPS 3.13.3. The docs say "it's recommended to use age over PGP, if possible", and Flux says the same. Nothing in the changelog announces PGP removal.
age Recipient and Identity Types¶
| Type | Recipient prefix | Identity prefix | Since |
|---|---|---|---|
| Native X25519 | age1... |
AGE-SECRET-KEY-1... |
3.7.0 |
SSH (ssh-ed25519, ssh-rsa only) |
ssh-ed25519 AAAA..., ssh-rsa AAAA... |
~/.ssh/id_ed25519, ~/.ssh/id_rsa, or SOPS_AGE_SSH_PRIVATE_KEY_FILE/_CMD |
3.10.0 |
Plugin (for example age-plugin-yubikey) |
age1<plugin>1... |
AGE-PLUGIN-... |
3.10.0 |
| Hybrid post-quantum (ML-KEM-768 + X25519) | age1pq1... (~2,000 characters) |
AGE-SECRET-KEY-PQ-1... |
3.12.0 (needs age >= v1.3.0 keys) |
age Identity Lookup¶
| Platform | Default keys.txt location |
|---|---|
| Linux | $XDG_CONFIG_HOME/sops/age/keys.txt, falling back to $HOME/.config/sops/age/keys.txt |
| macOS | $XDG_CONFIG_HOME/sops/age/keys.txt, falling back to $HOME/Library/Application Support/sops/age/keys.txt |
| Windows | %AppData%\sops\age\keys.txt |
Since 3.11.0, identities from all sources are loaded: the default file, SOPS_AGE_KEY_FILE, SOPS_AGE_KEY, SOPS_AGE_KEY_CMD (it receives SOPS_AGE_RECIPIENT since 3.12.0) and SSH keys.
CLI Subcommands¶
| Subcommand | Purpose |
|---|---|
sops encrypt / decrypt |
Encrypt or decrypt to stdout. -i/--in-place writes back. Reads stdin when no file is given (use --filename-override to pick a creation rule) |
sops edit |
Decrypt into $SOPS_EDITOR/$EDITOR (falls back to vim, nano, vi), then re-encrypt. Creates new files from .sops.yaml rules |
sops rotate |
New data key, re-encrypts all values. --add-* / --rm-* flags change master keys at the same time |
sops updatekeys |
Re-sync master keys with .sops.yaml without changing the data key. -y skips the prompt. Accepts several files |
sops set / unset |
Set or remove one tree path ('["a"]["b"]'). Value as JSON, --value-file or --value-stdin (3.11.0). --idempotent (3.10.0) |
sops decrypt --extract |
Print one tree path, for example '["data"]["password"]' |
sops filestatus |
Report whether a file is SOPS-encrypted (JSON output) |
sops exec-env / exec-file |
Run a command with secrets in its environment or in a FIFO/temp file. --user drops privileges. --background is deprecated |
sops groups add / delete |
Manage key groups on a file |
sops keyservice |
Run a gRPC key service (unauthenticated: tunnel it, for example over SSH) |
sops publish |
Re-encrypt and upload files to S3, GCS or Vault KV via destination_rules |
sops completion bash/zsh |
Shell completion scripts (3.11.0) |
The legacy top-level flags sops -e, sops -d and sops -r still work in 3.13.3. Combining several of them is deprecated. sops --version checks for updates unless you pass --disable-version-check or set SOPS_DISABLE_VERSION_CHECK=true (3.10.0 deprecated the implicit check).
Environment Variables¶
| Variable | Effect |
|---|---|
SOPS_CONFIG |
Path to the config file (instead of searching for .sops.yaml) |
SOPS_EDITOR |
Editor for sops edit (falls back to EDITOR) |
SOPS_DECRYPTION_ORDER |
Comma-separated backend order. Default age,pgp. Offline methods go first, then the rest |
SOPS_AGE_RECIPIENTS |
age recipients for encryption |
SOPS_AGE_KEY, SOPS_AGE_KEY_FILE, SOPS_AGE_KEY_CMD |
age identities: inline, file, or command output |
SOPS_AGE_SSH_PRIVATE_KEY_FILE, SOPS_AGE_SSH_PRIVATE_KEY_CMD |
SSH private key used as an age identity |
SOPS_PGP_FP, SOPS_GPG_EXEC |
PGP fingerprints, and an alternative gpg binary |
SOPS_KMS_ARN |
AWS KMS ARNs (optionally +ROLE_ARN) |
SOPS_GCP_KMS_IDS, SOPS_GCP_KMS_CLIENT_TYPE, SOPS_GCP_KMS_ENDPOINT, SOPS_GCP_KMS_UNIVERSE_DOMAIN |
GCP KMS keys, grpc (default) or rest client, sovereign-cloud endpoint overrides |
SOPS_AZURE_KEYVAULT_URLS |
Azure Key Vault key URLs |
SOPS_VAULT_URIS, SOPS_HC_VAULT_ALLOWLIST |
Vault/OpenBao transit URIs, and a URL-prefix allowlist (all by default, none blocks all) |
SOPS_HUAWEICLOUD_KMS_IDS |
HuaweiCloud KMS key IDs |
SOPS_KEYSERVICE, SOPS_ENABLE_LOCAL_KEYSERVICE |
Remote key service address, and whether to use the in-process one |
SOPS_DISABLE_VERSION_CHECK |
Skip the network version check on --version |
.sops.yaml Schema¶
SOPS looks for .sops.yaml in the current working directory and its parents, not next to the target file. It must be named .sops.yaml. Since 3.10.0 SOPS warns when it finds a .sops.yml. Top-level keys: creation_rules, destination_rules, stores.
| Creation-rule key | Type | Meaning |
|---|---|---|
path_regex |
string | Regex matched against the file path relative to the config file. Omitted = match everything. The first matching rule wins |
age, pgp, kms, gcp_kms, azure_keyvault, hc_vault_transit_uri |
string (comma-separated) or list | Recipients for a single key group. Lists since 3.11.0 |
hckms |
list | HuaweiCloud KMS key IDs |
aws_profile |
string | AWS profile for the rule's kms keys |
key_groups |
list of key groups | Several groups for Shamir splitting. Overrides the single-group keys |
shamir_threshold |
int | 0 (default = all groups required) or >= 2 |
mac_only_encrypted |
bool | true = MAC covers only encrypted values (default false) |
unencrypted_suffix / encrypted_suffix |
string | Select values by key suffix. Default: _unencrypted suffix leaves a value plaintext |
unencrypted_regex / encrypted_regex |
string | Select values by key regex |
unencrypted_comment_regex / encrypted_comment_regex |
string | Select values by a preceding or trailing comment (YAML) |
Only one of the six selection options may be set per rule. Key groups also accept merge (a list of key groups whose keys are concatenated, useful with YAML anchors). destination_rules (for sops publish) accept path_regex, s3_bucket, s3_prefix, gcs_bucket, gcs_prefix, vault_path, vault_address, vault_kv_mount_name, vault_kv_version, recreation_rule and omit_extensions. stores accepts yaml.indent (default 4, range 2-9), json.indent and json_binary.indent (default -1 = tab, 0 = none).
On-Disk Format¶
| Element | Format |
|---|---|
| Encrypted value | ENC[AES256_GCM,data:<b64>,iv:<b64>,tag:<b64>,type:<str\|int\|float\|bool\|bytes\|time\|comment>] |
| Cipher | AES-256-GCM with a 256-bit data key and a 256-bit (32-byte) random IV per value |
| AAD | Concatenated key path of the value, which binds each ciphertext to its location in the tree |
| MAC | SHA-512 over the plaintext values (all values, or only encrypted ones with mac_only_encrypted), stored AES-GCM-encrypted in sops.mac |
| Metadata block | sops: with per-backend lists (kms, gcp_kms, azure_kv, hc_vault, age, pgp, hckms) or key_groups + shamir_threshold, then lastmodified, mac, version, and any selection option (encrypted_regex, mac_only_encrypted, and so on) |
| Per-key entry | Backend identifier (arn [+ role, context, aws_profile], resource_id, vault_url + name + version, vault_address + engine_path + key_name, key_id, recipient, fp) plus enc (encrypted data key or Shamir share). All except age also store created_at |
Empty backend lists are omitted from metadata since 3.10.0. SOPS guarantees backward compatibility of the file format within the major version.
GitOps Integration Reference¶
| Tool | Mechanism | Key/credential delivery |
|---|---|---|
| Flux kustomize-controller | Native: Kustomization.spec.decryption.provider: sops |
Secret in .spec.decryption.secretRef with entries *.agekey, *.asc (PGP), sops.aws-kms, sops.azure-kv, sops.gcp-kms, sops.vault-token. Or workload identity via .spec.decryption.serviceAccountName (feature gate ObjectLevelWorkloadIdentity, kustomize-controller >= v1.6.0). OpenBao/Vault Kubernetes auth via --sops-vault-configmap (kustomize-controller v1.9.0, 2026-06-17) |
| Argo CD + KSOPS | Kustomize KRM exec plugin (apiVersion: viaduct.ai/v1, kind: ksops) run by the repo-server |
Keys mounted into argocd-repo-server. Needs kustomize build --enable-alpha-plugins --enable-exec |
| Argo CD + helm-secrets | Helm plugin that decrypts SOPS-encrypted values files (secrets:// value-file URLs) |
Keys in the repo-server. See the helm-secrets ArgoCD wiki |
| Argo CD + argocd-vault-plugin | AVP_TYPE: sops backend fills <placeholders> from a SOPS file |
Keys in the plugin sidecar |
| Terraform / OpenTofu | carlpett/sops provider: data "sops_file", plus an ephemeral resource (provider >= v1.3.0, Terraform >= 1.11) that keeps plaintext out of state |
Local keys or cloud credentials of the runner |
Flux requires apiVersion, kind and metadata to stay plaintext. Use encrypted_regex: ^(data|stringData)$ for Kubernetes Secrets.
Backend Audit Trails¶
| Backend | Audit mechanism |
|---|---|
| AWS KMS | CloudTrail logs Decrypt/Encrypt calls with key ARN, principal and timestamp. Encryption context appears in the log |
| GCP KMS | Cloud Audit Logs (Data Access logs must be enabled) for Decrypt/Encrypt |
| Azure Key Vault | Key Vault diagnostic logs (AuditEvent) via Azure Monitor |
| Vault / OpenBao | Audit devices log every transit encrypt/decrypt request |
| age / PGP | No server-side trail. Audit at the file level (Git history, filesystem ACLs) |
| SOPS itself | Optional: logs each decryption to PostgreSQL, configured in /etc/sops/audit.yaml (schema audit/schema.sql) |
Performance Characteristics¶
SOPS has no published benchmark suite. Treat the following as qualitative guidance. Measure on your own workload before capacity planning.
| Factor | Effect |
|---|---|
| Local backends (age, PGP) | No network call. Data-key decryption is dominated by process start-up and, for PGP, by gpg-agent |
| Cloud KMS and Vault/OpenBao | One network round trip per master key tried. --decryption-order puts the cheapest or most available backend first |
| Key groups (Shamir) | One successful master-key decryption per group up to the threshold |
| File size | Every leaf is encrypted separately (AES-GCM plus a base64-encoded 32-byte IV and 16-byte tag), so ciphertext files are much larger than plaintext ones. Binary files grow by the base64 overhead |
| Measured latencies | TBD: no controlled benchmark with documented conditions found |
Hardening Checklist¶
- Use age (or cloud KMS) for new files. Keep PGP only where existing workflows depend on it.
- Configure at least two independent master keys (for example KMS in two regions plus an offline age key) or key groups for separation of duty.
- Anchor
path_regexpatterns (^secrets/prod/.*\.yaml$) and put the catch-all rule last. - For Kubernetes manifests, set
encrypted_regex: ^(data|stringData)$and keepmac_only_encryptedoff unless you need to edit plaintext fields outside SOPS. - Store age private keys with
0600permissions. In CI, injectSOPS_AGE_KEYfrom the secret store instead of writing a file. - Use AWS KMS encryption context and key policies to bind keys to environments.
- Set
SOPS_HC_VAULT_ALLOWLISTwhen files come from untrusted sources (3.13.0+). - After removing a key, run
sops updatekeysthensops rotate -i, and then rotate the underlying credentials. - Never expose
sops keyservicewithout an authenticated, encrypted tunnel. - Pin the SOPS version in CI and verify release checksums/cosign signatures.
Sources¶
- SOPS documentation (source: getsops/docs)
- SOPS CHANGELOG and releases
- SOPS config schema (
config/config.go) - age README: post-quantum keys
- Flux Kustomization API: Decryption and kustomize-controller CHANGELOG
- KSOPS, helm-secrets ArgoCD integration, argocd-vault-plugin backends
- terraform-provider-sops