Skip to main content

SOPS

SOPS (Secrets OPerationS) is an editor and encryption tool for structured files. It encrypts the values in a YAML file while leaving the keys readable, using a KMS key you name, so a secrets file can be reviewed, diffed and committed like any other code. The Secrets Blueprint is built around it.

What it does

sops file.yaml decrypts the file, opens your editor, and re-encrypts on save. Each value is encrypted separately; the file carries a metadata block naming the key that protects it. Anyone with kms:Decrypt on that key can read the file; anyone without cannot, whatever their Git access. A .sops.yaml at the repository root maps file paths to keys.

How BuiltForProd uses it

The acme-aws-blueprint-secrets repository has one folder per stage (sandbox, dev, staging, prod) and one YAML file per application per stage; sample.yaml and sample2.yaml show the layout. Its .sops.yaml routes each folder to a key in the security account: alias/acme-sops-dev for dev/, and so on.

Those keys are created by the AWS Baseline's sops-kms unit, one per stage with annual rotation. The key policies are the access control:

Whosandbox and dev keysstaging and prod keys
Platform Leads and DevOps Leads permission setsencrypt and decryptencrypt and decrypt
Every other engineer permission setencrypt and decryptno access
acme-secrets-syncer (CI)decrypt onlydecrypt only

The GitHub side mirrors this with CODEOWNERS: the developers team owns sandbox/ and dev/; the platform leads and infra admins own staging/, prod/, .github/, the scripts and .sops.yaml.

Two workflows move secrets to AWS. On a pull request, plan.yml assumes the syncer role through OIDC, runs scripts/validate.sh and scripts/push-to-ssm.sh --dry-run, and posts the list of parameters that would change. Validation fails on a file it cannot decrypt as well as on any decrypted value that is still a placeholder, and the push script fails before it writes anything if a required environment variable is missing, naming all of them at once.

On a push to main, sync.yml runs one job per stage (sandbox, dev, staging and prod); each job runs in the GitHub Environment named after its stage, assumes that stage account's deployer role, decrypts that stage's files and writes every key as a SecureString parameter at /acme/usw2/dev/<app>/<KEY>. A manual run narrows the matrix to the single stage the operator chooses, so no other account is touched; merging to main remains the normal path. From there the External Secrets Operator can deliver the values to Kubernetes.

Infrastructure-generated secrets, such as the DocumentDB master password, do not go through SOPS. The module that creates the resource writes them to Parameter Store directly.

Terms you will see

TermMeaning
Creation ruleA .sops.yaml entry mapping a path pattern to a KMS key.
Data keyThe per-file key SOPS wraps with KMS; only the wrapped form is stored.
SecureStringA Parameter Store value encrypted at rest with KMS.
SyncerThe acme-secrets-syncer role the workflows assume.
Placeholder valueA literal that validate.sh refuses to sync.
Stage matrixThe per-stage sync jobs; a manual run narrows it to one stage.

Where to read more