1. Create a JSON file containing encrypted secrets (DB pass, etc.)
2. Upload the file to a secure S3 bucket with fine-tuned permissions and server-side encryption
3. For the instance that is launching, include the permission in the IAM role that allows it to "S3:GetObject" on the specific JSON file you uploaded.
4. Deliver decryption keys to the app in some manner (Chef, Ansible, etc.)
5. When the app starts, it downloads the JSON file and loads the environment variables.
I wrote a blog post[1] about this with more detailed info and an NPM module if you use Node.js.
[1] http://blog.matthewdfuller.com/2015/01/using-iam-roles-and-s...
I have a question about redundancy or "What happens if your gatekeper EC2 instance goes down"? If you have multiple gatekeepers could they be set up this way:
- let's say you have five different web apps using a gatekeeper to hold their secrets
- let's say you have n gatekeepers (let's say 3) and each of the apps knows the address of all three gatekeepers.
- If the primary gatekeeper is unreachable, all five apps would try to contact the secondary gatekeeper, but that gatekeeper would only (ever) respond in the event that the secondary gatekeeper also found the primary gatekeeper unreachable.
It's like a sleeper cell - at any given moment you have multiple replacement gatekeepers ready and waiting to serve, but each of them is unable to respond unless the one above it in the list stops responding. In this way you could lose gatekeepers (even permanently) and build a little bit of resilience into the apps depending on it while you're able to sort out what happened and restore normal behaviour.
Is this a good idea?
It's relatively common to provision secrets with configuration management software like Chef/puppet/ansible/etc using, e.g. Chef's encrypted data bags.
Another slightly heavier-weight solution with some nice properties is to use a credential broker such as Vault: https://www.vaultproject.io/
DB_USER=scott DB_PASSWORD=b3withm3pl3aze /usr/bin/python webapp.py
That could be troublesome if an attacker figured out a way to run remote commands on your server even as an unprivileged user.
pikachu@POKEMONGYM ~ $ sleep 99 &
[1] 21340
pikachu@POKEMONGYM ~ $ cat /proc/21340/environ
XDG_SESSION_ID=5COMP_WORDBREAKS=
"'><;|&(:TERM=screenSHELL=/bin/bashXDG_SESSION_COOKIE=8571b679eed8952dd96ad28a54...<etc>(I actually gave the wrong example in my previous comment. While it is true that giving the ENV on cmdline will show up in ps eaux, the more appropriate example is what I just explained in this comment.)
Now, if an attacker manages to get root access then it's game over[1]. That just shouldn't happen. But nobody should be running their webserver as root. So, whatever that user is should be low-powered with only enough privileges to start the webserver & bind port 8080 (and use iptables or whatever to reroute connections to port 80 --> 8080) and the whole setup should be designed that this account won't be able to escalate things further if someone got a bash shell to it.
______
1. You should at least have some way of detecting that it happened and consider all data & files compromised and just wipe the whole machine & start over. Or take that machine offline for investigation into what happened and put a fresh new one in its place.
It would be kind of weird to include that considering how argv works.
What are your other 11 objections?
Usually the base config is in VCS but without user/password/db strings. We then manually configure the file with the encrypted strings on the server (usually with the machine name in the filename so that we can use hostname in code to find it and makes it clear the file is machine specific). Not all tools make this easy though and only works if you can add your own code in between. Also prefer files to environment as the files can be locked down easier in my opinion and more obvious what is going on.
I like some of the other solutions that are using encrypted strings but with a keystore server and may consider for the future if they support both windows and linux.
/srv/www/domain.com/public_html/
|--------->/private/
|--------->/logs/
|--------->/tmp/
Anything stored in /private/ is not publicly accessible by the web server process, but can be read or written by anything running under the user's username.It's specifically for storing things like configuration files.
I think this should be standard practice.
There's a variety of mechanisms for loading this into your environment.
I typically handle this by versioning a `config.example` file, which includes all the necessary config keys an application expects. The example file defaults these attrs to various strings meant to show they are examples only. I include instructions to copy the `config.example` to a `config.yml` (or some other appropriate extension), and replace the values as necessary. The `config.yml` file is specifically excluded in the `.gitignore` file. The application will only load the `config.yml` file when started, so I also ensure to raise a descriptive error informing team members when they are missing a local `config.yml`.
This allows the `config.example` to also serve as a self-documenting config for the application, as comments can be included that identify and explain each of the config keys and their purposes.
Disclaimer: I worked on it.
Another way is a second file that overrides settings as needed. Although I have found that to be less maintainable if the configuration file changes. That file should be somewhere entirely out of the VC tree.
Either way, the file must be placed in a directory that is not served by the web server.
/include
and
/public
are traditional. Only /public is exposed by the web server.
use git crypt[1][2]
use git-dir and work-tree options/env vars
[1] https://www.agwa.name/projects/git-crypt/[2] though you have to remember to git crypt lock