When developing a Web App, and trying to adhere to what is generally considered best practice, e.g. The 12 factor app methodology etc. One key concept is to keep configuration and sensitive data out of your source code - access keys, connection strings etc. Using something like .env files to set different connection strings for a dev, test and production environment.

However, another key point (not sure is is mentioned in the 12 factor app), seems to be Infrastructure as Code. I completely see the benefit of this, however, I don't see how it can be reconciled with not storing/hard coding sensative data. Surely to entirely automate the provisioning of a new environment, a series of env variables has to be specified - in code...

How can these two seemingly contradictory pieces of standard practices be reconciled?

My current approach is something like this:

  1. Hosted Git Repo with however many dev branches and a master branch

  2. When dev branches are merged with master branch, the CI build is triggered, this builds the project and runs unit and integration tests.

  3. The git repo also has a production branch, when master is merged into production, the same build runs, but if it is successful, a CD release is created. (In my case this is a deployment to an Azure App Service)

So my three environments are the local dev machines (before a PR into the master branch in the hosted repo), the CI build server and the production app service. At the moment, locally we have a .env file which isn't checked into the git repo. On the CI server, the NODE_ENV value is set to test, so the code uses hard-coded unit test values (nothing sensitive). Then in production we manually set the connection strings etc. in the app service settings. This, I feel, is potentially an issue.

So possibly I could add an infrastructure folder to the repo, with Terraform code in it, then as part of the release process, terraform plan could see if there is anything that needs changing between the code's infrastrucutre and the real world infrastructure (and if so, execute it). But where do I store the production env variables?

  • 1
    Usual answer to this is use a king of secret storage, etc, consul, vault. this way your secrets are not stored with the code and are handled on a separate system (which need backups of course)
    – Tensibai
    Sep 1 '17 at 14:13

There are, as always, a few ways to solve this.

You can use a central source to keep secrets that each server reads from ala Hashicorp Vault. While popular this is not my preferred approach as its rather complex. There are quite a few key value stores that can provide similar functionality such as AWS Parameter Store.

You can manually put data in these stores and/or store it encrypted in git. Using tools such as kops (AWS only) or ejson (provider agnostic) you can have the secrets in the same repo as the app. Then have the app either fetch all the secrets at deploy time or just the decryption key so it can load the encrypted file.

  • 1
    Side note - kops is no longer AWS-only, from its link: with GCE and VMware vSphere in alpha and other platforms planned Sep 2 '17 at 2:38
  • OK, so would it be possible to create an Azure key vault in my terraform config, and then configure my app service to be approved for access to the sql credentials? (I currently create the sql server, DBs and app service all in a resource group in my terraform config). That way I can safely just call to the key vault in my code, but it will only work in the production environment? Sep 16 '17 at 12:26
  • To put it another way, if I have a SQL Server specified in terraform, I have to write in its username and password, to create a key vault secret, I also have to specify the secret (SQL password). How do I get around this Sep 16 '17 at 13:20
  • Don't manage it with Terraform. Managing secrets requires a tool that's dedicated to the task usually, Terraform isn't. I dont have any suggestions what to use since I've not used Azure
    – Robo
    Sep 16 '17 at 22:23

This is a common problem in configuration management, and while I can't speak for Chef as I haven't worked with it, I can tell you how this is solved by both Puppet and SaltStack.

Firstly, this distinction becomes a little less important with interpreted languages since there isn't much difference between including this sensitive data in a configuration file and including it in a text file that is interpreted (and I'm not aware of any compiled configuration management systems)

But secondly, both Puppet and SaltStack, so you can simply make the equivalent of a .env file and include it just as you do with your applications.

Typically this is not the recommended approach however. Instead, SaltStack recommends you use Pillars for managing this data, which are stored separately from the code (called "States"). This pillar data is uniquely calculated for each minion and sent directly from the server only to the minion only using standard SSL encryption - so one minion cannot see another's pillar data. In fact, minions can't edit pillar data and they definitely can't rewrite pillar data on the server - this data is unicast only.

Similarly, Puppet utilizes Heira for achieving something very similar. This allows you to store your code and metadata separately. You will then reference the pillar in your salt state or heira value in your manifest using a variable/function call thereby allowing your code to populate these values at runtime.

  • The question is about a webapp and makes no mention of Config Management tools. While you could use config management you havent mentioned the encryption implementations at all such as hiera-gpg
    – Robo
    Sep 2 '17 at 2:41
  • @Robo - Even infrastructure must be configured - and it can be configured with a configuration management tool. For example, Puppet and Salt have plugins for managing your load balancer. Cisco's ACI fabric has a puppet agent and there is a puppet module for VMWare NSX or you can use Cisco NSO to manage a range of devices. Sep 2 '17 at 2:58
  • You can manage Open Stack with these, AWS and more. And anything that has an API can be configured even if there isn't already a module for it by punting and creating a module using ruby or python (respectively). Configuration management tools are built to configure infrastructure, not merely servers. And yes, I did not mention hiera gpg, since the OP asked about separating the data, not encrypting it. But this is nonetheless a great point worth noting. You can also encrypt your metadata, not just store it separately. Sep 2 '17 at 3:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.