Skip to content

Security

Threat Model

SOPS operates at the file level within version-controlled repositories. Its security model depends on the strength of the master key backends, the integrity of the .sops.yaml configuration, and the safety of the encrypted data in transit and at rest.

Threat Vector Impact Mitigation
Compromised master key Decryption of all files encrypted with that key Key groups for quorum, key rotation
Tampered encrypted file Potential data corruption or injection HMAC-SHA256 MAC verification
Leaked .sops.yaml with key ARNs Reveals encryption key locations ARNs are not secrets; access is gated by IAM/auth
Stale keys in metadata Former team members retain decryption ability Regular updatekeys and key rotation
CI/CD credential leak Decryptor access in build pipelines Short-lived tokens, scoped IAM roles
Binary file substitution Swapping encrypted blobs MAC covers entire document tree

Key Management Best Practices

age vs PGP

Criterion age PGP
Key format Single X25519 key pair Complex keyring with subkeys
Key management One file per key Keyserver sync, trust db, keyring
Cryptographic agility Modern (X25519, ChaCha20-Poly1305) RSA or Curve25519; legacy defaults
Attack surface Minimal binary, no keyring Large attack surface (gpg agent, keyserver)
Key rotation Replace key file, run updatekeys Subkey rotation, keyring management
Recommendation Preferred for new deployments Legacy only; migrate when possible

Recommendation

Use age for all new SOPS deployments. It provides simpler key management, a smaller attack surface, and modern cryptography. PGP should only be retained for backward compatibility with existing encrypted files.

Key Rotation Strategy

  1. Master key rotation -- Generate new age keys or KMS keys. Run sops updatekeys <file> to add the new keys to existing encrypted files while preserving the current data key.
  2. Data key rotation -- Run sops rotate <file> to generate a new data key and re-encrypt all values. This is necessary after a suspected key compromise.
  3. Rotation cadence -- Rotate master keys annually or when team members leave. Rotate data keys on a shorter cadence for highly sensitive secrets.
# Add new age key to existing file (no re-encryption)
sops updatekeys secret.enc.yaml

# Full data key rotation (re-encrypts all values)
sops rotate --input-type yaml --output-type yaml secret.enc.yaml

Multi-Backend Redundancy

Always configure at least two master key backends for each file. The recommended pattern:

creation_rules:
  - path_regex: \.prod\.yaml$
    kms: arn:aws:kms:us-east-1:111122223333:key/prod-key
    age: >-
      age1s3cqcks5genc6ru8chl0hkkd04zmxvczsvdxq99ekffe4gmvjpzsedk23c
    pgp: FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4

This ensures: - AWS KMS -- Primary decryption path for CI/CD and automated systems. - age -- Offline decryption capability for disaster recovery. - PGP -- Additional offline recovery path.

If the AWS KMS key becomes unavailable (account suspension, region outage), decryption is still possible using the age or PGP keys.

.sops.yaml Configuration Security

The .sops.yaml file controls which keys encrypt which files. While the file itself does not contain secret material, its configuration has security implications.

Path Regex Accuracy

Ensure path_regex patterns are precise to prevent mis-encryption:

# Good: precise pattern
creation_rules:
  - path_regex: ^secrets/prod/.*\.yaml$
    kms: arn:aws:kms:us-east-1:111122223333:key/prod-key

# Bad: overly broad pattern
creation_rules:
  - path_regex: .*\.yaml$
    kms: arn:aws:kms:us-east-1:111122223333:key/prod-key

An overly broad pattern could cause development files to be encrypted with production keys, or vice versa.

Key Groups for Separation of Duty

Key groups enforce that decryption requires at least one key from each group:

creation_rules:
  - path_regex: ^secrets/prod/.*\.yaml$
    key_groups:
      # Team A must participate
      - age:
          - age1_team_a_key
      # Team B must participate
      - age:
          - age1_team_b_key
      # Offline recovery key must exist
      - pgp:
          - FINGERPRINT_RECOVERY_KEY

With this configuration, no single team can decrypt production secrets alone.

File Permissions

# .sops.yaml should be readable by all team members but not writable casually
chmod 644 .sops.yaml

# Private age keys must be strictly protected
chmod 600 ~/.config/sops/age/keys.txt

CI/CD Integration Security

AWS KMS in CI/CD

Use IAM roles with minimal permissions for CI/CD pipelines:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt",
        "kms:DescribeKey",
        "kms:Encrypt"
      ],
      "Resource": ["arn:aws:kms:us-east-1:111122223333:key/prod-key"]
    }
  ]
}

KMS Encryption Context

SOPS supports AWS KMS encryption context, which binds the decryption to specific context values. Use this to prevent cross-environment decryption. SOPS automatically includes the file path as encryption context when configured.

age in CI/CD

Store the age private key as a CI/CD secret variable:

# GitHub Actions example
env:
  SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}

The SOPS_AGE_KEY environment variable allows SOPS to decrypt without writing the key to disk. This is safer than checking in the key file.

GPG Agent in CI/CD

PGP in CI/CD requires importing the private key into the GPG agent, which increases complexity and attack surface:

# Import private key (avoid this pattern when possible; prefer age)
echo "$SOPS_PGP_KEY" | gpg --import

Prefer age for CI/CD to avoid the complexity and security risks of GPG key management in ephemeral build environments.

MAC Verification

SOPS computes an HMAC-SHA256 Message Authentication Code over the encrypted document structure. This provides:

  • Integrity verification -- Any modification to the encrypted values, key names, or document structure is detected.
  • Tampering detection -- Swapping values between keys or inserting new encrypted values invalidates the MAC.
  • Rejection on failure -- SOPS refuses to decrypt if MAC verification fails.

The MAC key is derived from the data key and is stored alongside the encrypted data keys in the sops metadata block.

Partial Encryption Security

SOPS supports encrypting only specific parts of a file using encrypted_regex or encrypted_suffix:

# .sops.yaml
creation_rules:
  - path_regex: .*\.yaml$
    encrypted_regex: "^(password|secret|api_key|token)$"

Partial Encryption Risks

When using partial encryption, ensure that the unencrypted fields do not contain sensitive information. The MAC only covers encrypted values, so modifications to plaintext fields are not detected. Review which fields are excluded from encryption carefully.

Auditing

SOPS does not include a built-in audit log, but auditing is achievable through the master key backends and file metadata:

Key Usage Auditing

Each encrypted file contains a sops metadata block listing every master key and its encrypted data key fragment. Inspect it to identify which backends and key IDs protect a file:

# View the sops metadata block (shows all master key references)
sops --decrypt --extract '["sops"]' secret.enc.yaml

Backend-Level Audit Trails

Backend Audit Mechanism
AWS KMS CloudTrail logs all Decrypt and GenerateDataKey API calls with key ARN, user identity, and timestamp
GCP KMS Cloud Audit Logs for cryptoKeys.decrypt and cryptoKeys.encrypt
Azure Key Vault Azure Monitor activity log for key operations
age / PGP No server-side audit trail -- audit at the file-access level (git log, filesystem ACLs)

Key Hygiene Auditing

# List all keys referenced across encrypted files
grep -r '"sops":' --include="*.enc.*" -A 20 | grep -E '(arn|age|fp):'

# Identify files with stale or deprecated keys
sops updatekeys --show-diff secret.enc.yaml

Regularly review CloudTrail and Cloud Audit Logs for unauthorized decryption attempts, and run sops updatekeys on a schedule to remove stale master keys from encrypted file metadata.