Architecture¶
Related Notes
secrets/sops/index | secrets/sops/architecture | secrets/sops/operations | secrets/sops/security
Overview¶
SOPS (Secrets OPerationS) is a file-level encryption tool that encrypts the values of structured data files while leaving the keys in plaintext. It supports YAML, JSON, ENV, INI, and BINARY formats and encrypts with multiple backends: AWS KMS, GCP KMS, Azure Key Vault, age, and PGP. SOPS is designed for managing encrypted secrets in version-controlled repositories.
Encryption Model¶
SOPS uses a two-tier encryption architecture: a randomly generated data key encrypts the file content, and one or more master keys encrypt the data key. This separation allows multiple master keys from different backends to protect the same file without duplicating the data encryption work.
graph TD
subgraph "Master Keys (Envelope Encryption)"
KMS["AWS KMS Key"]
GKMS["GCP KMS Key"]
AKV["Azure Key Vault Key"]
AGE["age Public Key"]
PGP["PGP Public Key"]
HV["HashiCorp Vault Key"]
end
DK["Data Key (256-bit random)"]
FILE["Encrypted File (YAML/JSON/ENV/INI/BINARY)"]
META["sops.metadata block"]
KMS -->|encrypts data key| DK
GKMS -->|encrypts data key| DK
AKV -->|encrypts data key| DK
AGE -->|encrypts data key| DK
PGP -->|encrypts data key| DK
HV -->|encrypts data key| DK
DK -->|encrypts values| FILE
DK -->|stored encrypted in| META
META -->|sops.kms[]| KMS
META -->|sops.pgp[]| PGP
META -->|sops.age[]| AGE
META -->|sops.azure_kv[]| AKV
META -->|sops.gcp_kms[]| GKMS
META -->|sops.hc_vault[]| HV
Key Hierarchy¶
graph BT
subgraph "Decryption Path"
MK1["Master Key 1<br/>(AWS KMS)"]
MK2["Master Key 2<br/>(age)"]
MK3["Master Key 3<br/>(PGP)"]
EDK["Encrypted Data Keys<br/>(stored in sops metadata)"]
DK["Data Key (256-bit AES)"]
PLAIN["Plaintext Values"]
end
MK1 -->|decrypts| EDK
MK2 -->|decrypts| EDK
MK3 -->|decrypts| EDK
EDK -->|yields| DK
DK -->|AES-256-GCM decrypts| PLAIN
style DK fill:#f9f,stroke:#333,stroke-width:2px
style PLAIN fill:#bfb,stroke:#333
Encryption Flow¶
When SOPS creates a new encrypted file:
- Generate data key -- SOPS generates a random 256-bit data key using a cryptographically secure random number generator.
- Encrypt data key with each master key -- SOPS invokes each configured master key backend (KMS, age, PGP, etc.) to encrypt the data key. Each backend produces an encrypted copy of the data key.
- Encrypt individual values -- SOPS encrypts each leaf value in the document individually using AES-256-GCM with the data key. Each value gets a unique IV (initialization vector).
- Compute MAC -- SOPS computes a Message Authentication Code (HMAC-SHA256) over the encrypted values to detect tampering.
- Store metadata -- All encrypted data keys, IVs, MACs, and backend references are stored in the
sopsmetadata block embedded in the file.
sequenceDiagram
participant User
participant SOPS as SOPS CLI
participant DK as Data Key Generator
participant KMS as AWS KMS
participant AGE as age
participant FS as File System
User->>SOPS: sops encrypt --kms arn --age key file.yaml
SOPS->>DK: Generate 256-bit random data key
DK-->>SOPS: data_key (plaintext)
SOPS->>KMS: Encrypt data_key with KMS key
KMS-->>SOPS: encrypted_data_key_kms
SOPS->>AGE: Encrypt data_key with age public key
AGE-->>SOPS: encrypted_data_key_age
SOPS->>SOPS: Encrypt each value with AES-256-GCM
SOPS->>SOPS: Compute HMAC-SHA256 MAC
SOPS->>FS: Write file with sops metadata block
Decryption Flow¶
- Read sops metadata -- SOPS parses the
sopsblock from the encrypted file to discover available master keys. - Attempt master key decryption -- SOPS iterates through the available backends, attempting to decrypt the data key. It tries each encrypted data key until one succeeds (using available credentials).
- Verify MAC -- Once the data key is recovered, SOPS recomputes the MAC and verifies it against the stored MAC to detect tampering.
- Decrypt values -- Each leaf value is decrypted using AES-256-GCM with the data key and its stored IV.
- Reconstruct document -- SOPS reassembles the plaintext document structure, replacing encrypted values with their decrypted content.
Supported Backends¶
| Backend | Key Type | Use Case |
|---|---|---|
| AWS KMS | Symmetric encryption key | Teams using AWS; supports IAM roles, profiles, and encryption context |
| GCP KMS | Symmetric encryption key | Teams using GCP; supports service account authentication |
| Azure Key Vault | RSA or AES key | Teams using Azure; supports service principal authentication |
| age | Public/private key pair (X25519) | Local and CI/CD use; no cloud dependency, simple key management |
| PGP | Public/private key pair | Legacy deployments; complex keyring management |
| HashiCorp Vault | Transit engine key | Organizations already running Vault; centralized key management |
Recommended Backend
age is the recommended backend for most use cases due to its simplicity, modern cryptography, and lack of keyring complexity. PGP is considered legacy. Cloud KMS backends are ideal when the organization already uses the respective cloud provider.
Key Groups¶
Key groups provide a quorum-based decryption policy. Instead of requiring any single master key, SOPS can be configured to require at least one master key from each group for decryption.
# .sops.yaml
creation_rules:
- path_regex: .*keygroups.*
key_groups:
# Group 1: Cloud KMS keys
- kms:
- arn: arn:aws:kms:us-east-1:111122223333:key/dev-key
pgp:
- fingerprint1
# Group 2: Offline recovery keys
- pgp:
- fingerprint3
- fingerprint4
# Group 3: age backup keys
- age:
- age1s3cqcks5genc6ru8chl0hkkd04zmxvczsvdxq99ekffe4gmvjpzsedk23c
With this configuration, decryption requires at least one valid key from each of the three groups. This enforces geographic or organizational separation of trust.
.sops.yaml Configuration¶
The .sops.yaml file is a declarative configuration file placed at the root of a repository. It maps file path patterns to encryption keys, automating key selection when creating new encrypted files.
creation_rules:
# Development files: use dev KMS key + age
- path_regex: \.dev\.yaml$
kms: arn:aws:kms:us-west-2:927034868273:key/fe86dd69-4132-404c-ab86-4269956b4500
age: age129h70qwx39k7h5x6l9hg566nwm53527zvamre8vep9e3plsm44uqgy8gla
# Production files: use prod KMS key + PGP + age
- path_regex: \.prod\.yaml$
kms: arn:aws:kms:us-west-2:361527076523:key/5052f06a-5d3f-489e-b86c-57201e06f31e
pgp: FBC7B9E2A4F9289AC0C1D4843D16CEE4A27381B4
age: age1qe5lxzzeppw5k79vxn3872272sgy224g2nzqlzy3uljs84say3yqgvd0sw
# Catchall: use global KMS key + PGP
- kms: arn:aws:kms:us-east-1:777788889999:key/global-key
pgp: 3333CCCC
Rules are evaluated sequentially and the first match wins. SOPS supports matching by path_regex or exact name.
File Format Support¶
| Format | Extension | Behavior |
|---|---|---|
| YAML | .yaml, .yml |
Encrypts leaf values; keys and structure remain plaintext |
| JSON | .json |
Encrypts leaf values; keys and structure remain plaintext |
| ENV | .env |
Encrypts values; variable names remain plaintext |
| INI | .ini |
Encrypts values; section headers and keys remain plaintext |
| BINARY | Any | Encrypts the entire file content as a blob |
Value-Level Encryption¶
Unlike full-file encryption tools, SOPS encrypts individual values within structured files. This provides several advantages:
- Diff-friendly -- Since keys are plaintext,
git diffshows which keys changed, making secret rotation reviewable. - Partial decryption -- SOPS can extract or set individual values without decrypting the entire file.
- Structured MAC -- Each value has its own authentication tag, enabling precise tampering detection.
Key Rotation¶
SOPS supports two key rotation mechanisms:
sops updatekeys-- Syncs the encrypted file with the current.sops.yamlcreation rules. Adds new master keys and removes old ones while preserving the data key.sops rotate-- Generates a new data key and re-encrypts all values. Old master keys are preserved for decryption continuity.
Rotation vs Updatekeys
updatekeys does not re-encrypt the data; it only updates which master keys can decrypt the existing data key. rotate re-encrypts everything with a new data key. Use rotate for true cryptographic rotation after a suspected key compromise.
MAC (Message Authentication Code)¶
SOPS computes an HMAC-SHA256 MAC over the encrypted document to detect tampering. The MAC covers: - All encrypted values. - The document tree structure. - The nonce/IV for each encrypted value.
If the MAC verification fails during decryption, SOPS refuses to proceed. This prevents an attacker from modifying encrypted content or swapping values between keys.
How It Works¶
Envelope encryption, value-only encryption model, and KMS integration.
Encryption Model¶
SOPS uses envelope encryption: a data encryption key (DEK) encrypts the file values, and the DEK itself is encrypted by the master key (age, KMS, etc.).
flowchart TB
subgraph File["Encrypted File"]
Meta["sops metadata\n(encrypted DEK, key fingerprints)"]
Keys["YAML/JSON keys\n(plaintext)"]
Values["Values\n(AES-256-GCM encrypted)"]
end
subgraph Master["Master Key Layer"]
Age["age key"]
KMS["AWS/GCP KMS"]
VaultT["Vault Transit"]
end
Master -->|"encrypt DEK"| Meta
Meta -->|"DEK decrypts"| Values
style Values fill:#c62828,color:#fff
style Keys fill:#2e7d32,color:#fff
What Gets Encrypted¶
# Before encryption
apiVersion: v1
kind: Secret
metadata:
name: myapp # ← NOT encrypted (structure visible)
data:
username: admin # ← value ENCRYPTED
password: s3cr3t # ← value ENCRYPTED
# After: sops --encrypt
apiVersion: v1
kind: Secret
metadata:
name: myapp # ← still plaintext (keys visible)
data:
username: ENC[AES256_GCM,data:abc123...] # ← encrypted
password: ENC[AES256_GCM,data:xyz789...] # ← encrypted
sops:
age:
- recipient: age1abc...
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
...encrypted DEK...
Sources¶
Value-Level Encryption Detail¶
Each leaf value in the document is encrypted independently with AES-256-GCM:
- Per-value IV: A unique initialization vector (12 bytes) is generated for each value using a cryptographically secure RNG
- AES-GCM encrypt: The value is encrypted with the data key and its unique IV. GCM produces both ciphertext and a 16-byte authentication tag.
- Stored format:
ENC[AES256_GCM,data:<base64-ciphertext>,iv:<base64-iv>,tag:<base64-authtag>] - MAC covers structure: The HMAC-SHA256 MAC is computed over the entire document tree (keys, encrypted values, IVs, tags), not individual values
This per-value approach enables diff-friendly encryption: git diff shows which keys changed because the keys remain in plaintext.
Decryption Path¶
When decrypting, SOPS follows this sequence:
- Parse metadata: Read the
sopsblock to discover available encrypted data keys - Attempt decryption: Try each encrypted data key in order (KMS → age → PGP → Vault) until one succeeds using available credentials
- Verify MAC: Recompute HMAC-SHA256 over the encrypted document and compare against the stored MAC. Abort if mismatch.
- Decrypt values: For each
ENC[...]value, decrypt using AES-256-GCM with the data key and the stored IV - Reconstruct: Replace encrypted values with plaintext, remove the
sopsmetadata block
Partial Encryption¶
SOPS supports encrypting only specific fields using regex or suffix matching:
# .sops.yaml - only encrypt fields matching the regex
creation_rules:
- path_regex: .*\.yaml$
encrypted_regex: "^(password|secret|api_key|token|private_key)$"
With partial encryption, unencrypted fields remain readable and diffable, while sensitive values are protected. The MAC only covers encrypted values, so modifications to plaintext fields are not detected by SOPS (use Git integrity for those fields instead).
Benchmarks¶
Scope
Performance characteristics, scaling limits, and resource consumption for SOPS.
Encryption Performance¶
| File Size | Encrypt Time | Decrypt Time | Notes |
|---|---|---|---|
| 1KB (few secrets) | < 100ms | < 100ms | Typical config file |
| 10KB | 100-200ms | 100-200ms | Large config |
| 100KB | 200-500ms | 200-500ms | Unusual for secrets |
Key Provider Performance¶
| Provider | Encrypt | Decrypt | Notes |
|---|---|---|---|
| age | < 50ms | < 50ms | Fastest, local-only |
| PGP | 50-100ms | 50-100ms | Local key |
| AWS KMS | 100-300ms | 100-300ms | Network roundtrip |
| GCP KMS | 100-300ms | 100-300ms | Network roundtrip |
| Azure Key Vault | 100-500ms | 100-500ms | Regional latency |
GitOps Integration¶
| Tool | Decrypt Method | Overhead |
|---|---|---|
| Flux | sops-controller | < 1s per secret |
| ArgoCD | argocd-vault-plugin | 1-3s per secret |
| Helm Secrets | helm-secrets plugin | < 1s per secret |
Sourcing Status¶
Unsourced Performance Data
The performance numbers in this document are estimated from vendor documentation, community benchmarks, and engineering judgment. They do not represent controlled benchmarks with documented test conditions. Specific hardware configurations, software versions, and test methodologies were not recorded.
Use these figures as rough guidance only. For production capacity planning, run your own benchmarks against your specific workload and infrastructure.