Last active
May 8, 2024 11:36
-
-
Save telent/9742059 to your computer and use it in GitHub Desktop.
12 factor app configuration vs leaking environment variables
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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." | |
http://12factor.net/config | |
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) | |
Against: | |
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 | |
http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AESDG-chapter-instancedata.html | |
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 | |
values | |
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? | |
I agree with Jesse here, and I would (attempt to) disambiguate it by using the word "installation" (or perhaps "instance") in preference to "environment".
I haven't done more than skin the Aero documentation so far, but it's from Juxt so I assume it's good :-) There's another older and probably better-known precedent for a reasonably systematic way to configure from cascading files/environment variables, which is Ruby's bundle tool.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
re: What iolloyd said (in 2016)
values that change depending on the environment should only be available in that environment.
Perhaps it is grammatically persnickety of me, but I'd like to point out that in this context, environment refers to things like:
not to environment variables specifically.
Each of those run-environments may have a custom copy of the configuration file, and that meets the needs of separating configuration state from application code. As well as environment variables and command line parameters, one could have cascading config files. E.g.:
myApp --config=default.cfg --config=devel.cfg --config=test-bug-fix.cfg
myApp --config=default.cfg --config=production.cfg --config=NorthAmerica.cfg --config=UnitedStates.cfg --config=Colorado.cfg
Each file read in order, overriding whatever configuration had been built so far.