5/25/2016 - 9:30 AM

12 factor app configuration vs leaking environment variables

12 factor app configuration vs leaking environment variables

App configuration in environment variables: for and against

For (some of these as per the 12 factor principles) 

1) they are are easy to change between deploys without changing any code

2) unlike config files, there is little chance of them being checked
into the code repo accidentally

3) unlike custom config files, or other config mechanisms such as Java
System Properties, they are a language- and OS-agnostic standard."


4) because the key and value both have to be plain text, it discourages
adding more complicated things as config settings when they really ought
not to need to be.  Look at any mongoid.yml for example.  Multi-level
config hashes are a code smell (my opinion)


1) Environment variables are 'exported by default', making it easy to 
do silly things like sending database passwords to Airbrake.  Sure we could
introduce code to filter them out, but it's another thing we need to
remember to update every time we add one - not robust in the face of
code changes.  Better not to put them there in the first place

2) It provides the "illusion of security": env vars are really no more
secure than files, in that if you can read someone's files you can also
(quite easily in Linux) read the environment variables of their running
processes.  This is not to say that files are better, just that they
don't pretend to be.

3) in some respect it's just deferring the problem: in order to start
your production instance those config variables still need to be read
from some source so they can be added to the environment, and 98% of the
time that source will be a local file.

4) if you restart an app by sending it a signal (e.g. SIGHUP) from an 
unrelated shell that causes it to re-exec itself, it will still have the
environment of the original process.  So for example, you can't update
config in environment variables and do a Unicorn "zero downtime" restart.
This can cause confusion

5) There is no single place in which to look to find out what settings are
accepted/required: even successfully starting the app doesn't mean that some code
path somewhere won't dereference an unset env var sometime later.  We don't pass 
parameters into modules using arbitrarily-named and undeclared globals,  so
why is it OK to pass params into the main program that way

My argument:

is that what we're really asking for is a configuration source that

a) lives outside the project.  This requirement could be met by
environment variables or a file in /etc or even a request to a web
server - see e.g. as the AWS instance metadata


but in any case it should be difficult to accidentally merge production
config values into the project version control.

b) can be easily and reliably read using any of a variety of languages
(including shell scripts and the like) without complicated parsing code
or library dependencies

c) has limits on its expressitivity, so that people aren't trying to add
code that wants hashes and dates and lists and stuff like that as config

d) ideally, makes it hard to accidentally send the configuration values
to our collaborators and external services

Is that a fair representation of the arguments for/against, or am I
missing something?