Search code examples
12factor

Is using ENV variables a good idea?


Background

Our app uses a MySQL DB and a couple more services.

To connect our app to these servers, we have the usernames and passwords saved in a prod.config file. If we are in dev, we use a dev.config file and so on...

Recently, I have been studying good practices in the industry ( such as the https://12factor.net/ ) and the majority of them ( if not all ) specify that information like usernames and pwd's to connect to DB and other services should not be in conifg files but rather in ENV variables.

If you have no idea what the 12 factor spec is you can check this free tutorial:

Problem

Now, at first this looks fine. Many CI tools like Travis or CircleCI already force you to do this anyway. The problem here is when your smallest app uses multiple services.

In our case, for our smallest app, we would need 13 ENV variables. Variables that wouldn't be in any specific file, they would all have to be in the ENV of the machine they run on.

I fail to see how this can be seen as a good practice. I understand the main idea of not pushing your confg files with all this sensitive data, but this approach poses several issues:

  1. When the machine reboots, you loose all you ENV variables.
  2. If you want to avoid the previous problem, you need to run a script on machine start, that sets these said variables, which means you would have them stored in a file, defeating the whole purpose.
  3. Where do you save these variables? They need to be somewhere else other than you flimsy head!

Questions

  • How would I solve the previous issues?
  • Why is saving private info in ENV variables seen as a good idea?

Solution

  • I'm going to step back a bit here and pose a question to you: why are you trying to connect to a production database from a testing environment?

    The beauty of CI tools is that they allow you to spin up Docker containers to act as testing services. In your production code, it is considered best practice to keep your passwords saved in environmental variables for two main reasons: 1.) If someone ever got a hold of your code, they would have access to your database. It requires an extra level of security that is just not realistic. 2.) If someone did get a hold of your passwords, you want to be able to change them quickly. This is easier to do if your code references environmental variables instead of hard-coded strings.

    When you move to a CI system, point #2 becomes moot, but point #1 becomes exceedingly important. With Travis and CircleCI, your config file is public. If you put your production password into your config file, I (or someone much more malicious) could just go scan your file and jump into your database. I've heard stories of hackers scraping public repositories for hardcoded passwords in config files. It's even easier with a tool like CircleCI.

    The environmental variables you set in Travis and CircleCI should be stored at a repository level- you shouldn't need to move variables around or save them.

    Environmental variables in a production system should be set-up as part of a startup script. This is highly dependent on what kind of service you're using, so I won't go into much detail here.