Guide 7 of 12
Configuration and credentials
Two sources, in order: an encrypted credentials file if one exists, then environment variables, which always win. No globals, no init(): config.Load() returns a struct once, at startup, and every field is validated then, so a missing setting is a refusal to boot rather than a nil a request trips over an hour later.
The environment variables
Named after the app: a service called blog reads BLOG_*.
| Variable | What it selects |
|---|---|
<NAME>_ENV | A closed set: development, test or production. Selects behaviour. |
<NAME>_CREDENTIALS | Any name; selects which credentials file to read. Defaults to <NAME>_ENV. |
<NAME>_MASTER_KEY | The decryption key, handed in by a deployment so no key file has to exist in the image. |
<NAME>_ADDR | The listen address, default :8080. |
<NAME>_DATABASE_URL | The database. Development and test default to the compose stack on :5440; production has no default and must be given. |
<NAME>_LOG_LEVEL | debug, info, warn or error. |
<NAME>_MIGRATE_AT_BOOT | true by default; set to false only for a deployment that migrates from one place on purpose. |
(There is also <NAME>_SHUTDOWN_GRACE, how long the server waits for in-flight requests on SIGTERM, and <NAME>_CONFIG_DIR for running the binary from somewhere other than the app root. Both have sensible defaults.)
<NAME>_ENV and <NAME>_CREDENTIALS are deliberately separate. <NAME>_ENV is a closed set with no "staging" member on purpose, because every behavioural switch in the app reads it, and a typo there should fail loudly rather than fall through to production behaviour silently. A staging deployment is:
BLOG_ENV=production BLOG_CREDENTIALS=staging
production strictness, staging secrets, which is what "staging" means here: not a third environment, but production behaviour reading a different credentials file.
The credentials files
The Rails pattern: committed ciphertext, a key that is never committed.
config/credentials.yml.enc + config/master.key development
config/credentials/staging.yml.enc + config/credentials/staging.key
config/credentials/production.yml.enc + config/credentials/production.key
Each file is flat, one section named after the app, whose keys give the environment-variable names: blog.addr is overridden by BLOG_ADDR, so a value can move between the file and the environment without renaming anything.
bogie credentials:edit
bogie credentials:edit -e production
make credentials ENV=staging
bogie credentials:edit opens development's file with its key; -e production (or make credentials ENV=production) opens that environment's own file, making it and its key the first time. A key opens only the file it was made for: development's key can never read production's file.
Test never reads a credentials file. It runs from defaults and the environment only, so tests need nobody's secrets and can never accidentally open the development database.
In a container
The encrypted files travel in the image; the keys never do. At runtime the key for whichever credentials file is selected arrives as <NAME>_MASTER_KEY, read directly with no file to write and no permissions to get wrong. See Deploying for where that value comes from.