Secrets
Norn v2 uses SOPS + age for secret management. Secrets are encrypted at rest and decrypted at deploy time, then injected as environment variables into Nomad tasks.
How It Works
- Secrets are stored in a
secrets.enc.yamlfile alongside the app'sinfraspec.yaml - During the submit step of the deploy pipeline, Norn decrypts the file using SOPS
- Decrypted key-value pairs are merged into the environment variables passed to
nomad.Translate() - Nomad injects them as environment variables in the running containers
v1 vs v2
In v1, secrets were synced to Kubernetes Secrets and mounted into pods. In v2, there is no Kubernetes — secrets go directly from SOPS to Nomad environment variables during the pipeline.
Setup
1. Generate an age key
age-keygen -o ~/.config/sops/age/keys.txtmacOS
SOPS on macOS looks for age keys at ~/Library/Application Support/sops/age/keys.txt. Symlink to avoid duplicating:
ln -sf ~/.config/sops/age/keys.txt \
~/Library/Application\ Support/sops/age/keys.txt2. Create a .sops.yaml in the app directory
creation_rules:
- age: >-
age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx3. Create and encrypt secrets
# Create a plaintext file
cat > secrets.yaml <<EOF
DATABASE_URL: postgres://user:pass@host:5432/db
API_KEY: sk-1234567890
EOF
# Encrypt it
sops -e secrets.yaml > secrets.enc.yaml
rm secrets.yaml4. Declare expected keys in infraspec
secrets:
- DATABASE_URL
- API_KEYThe secrets list is informational — it tells the UI and CLI which keys to expect. The actual values come from secrets.enc.yaml.
CLI Management
# List secret keys for an app
norn secrets myapp
# Compare declared, encrypted, and plaintext secret state
norn secrets status
norn secrets status myapp
# Plan value-safe plaintext env migrations
norn secrets migrate-plan
norn secrets migrate-plan myapp
# Set or update a secret
norn secrets set myapp DATABASE_URL=postgres://...
# Delete a secret
norn secrets delete myapp OLD_KEYThe status command compares the secrets list in infraspec.yaml with encrypted keys in secrets.enc.yaml and reports plaintext secret-like values still present in env blocks. Secret values are never printed.
The migrate-plan command turns those plaintext findings into a value-safe checklist. It shows the app, field, key, whether the key is declared in secrets, whether it already exists in secrets.enc.yaml, and the recommended action. It does not print or move secret values; operators still make the actual secrets.enc.yaml change with SOPS or norn secrets set.
Use the strict gate when you want plaintext secret-like env values to block validation:
norn validate --strict-secrets
NORN_STRICT_SECRETS=true norn preflight myapp HEADThe gate is opt-in so older apps can be migrated deliberately. Once an app is clean, keep NORN_STRICT_SECRETS=true in the platform runtime env to prevent drift.
The set command decrypts the file, updates the key, and re-encrypts.