Best Practices Around Committing .env Files To Version Control

July 21, 2022

Pre-Requisite

Basic understanding of .env files.

Insight

I am in favour of the idea that the contents of the .env file should be committed to version control. The trouble is that blindly committing it creates a huge security risk. Here I discuss a few pointers on how to do so in a safe manner.

Committing .env File To Version Control

Pros

  • All the variables are tracked - creating, updating, and deleting variables are easy.
  • Easy deployment - corollary to above, deployment is easy because every variable you need is in the repository.
  • All the benefits that come with version control such as history, revert, comparison, etc.

Cons

  • Security Risk - your secrets are exposed to anyone who has access to your repository (both public and private).
  • All the drawbacks that come with version control, mainly history - your secrets will live forever in your repo unless you edit past commits or nuke all your history.

Despite the security concerns, the benefits are too great to not commit. Below are some of the best practices to follow to keep your secrets safe while committing .env variables.

Best Practices

Suggestion 1: Create + Only Commit The Template .env File

The best way to protect your secrets is to never commit them in the first place. But I still want to be able to track which variables are needed so that all developers are on the same page. For this reason, I recommend creating a template .env file.

Consider a sample .env file's content below:


    VERY_IMPORTANT_SECRET = KNDSAIJOFNEWHKFNERKJGNBFDSHFNDSFNDSKJ
    NOT_VERY_IMPORTANT_SECRET = NFDSIJNFJDN
    RANDOM_VARIABLE_1 = FNDSJANFS
    RANDOM_VARIABLE_2 = MFDKSJANFEJWF
        
Now create a near identical file called .env.template with the following content:

    VERY_IMPORTANT_SECRET =
    NOT_VERY_IMPORTANT_SECRET = NFDSIJNFJDN
    RANDOM_VARIABLE_1 = FNDSJANFS
    RANDOM_VARIABLE_2 = MFDKSJANFEJWF
        

The trick is to NEVER commit your actual .env file but commit your .env.template file that only contains non-sensitive information. .env.template file serves to tell all the developers that such variables exist and need to be filled in, that's it. In this case, VERY_IMPORTANT_SECRET value was left blank.

The blank values should be filled in during the developer's setup (typically this is done by duplicating .env.template, renaming it as .env, and then getting the values from other developers or a setup guide). If any changes are needed to be made in the .env file (for ex. naming), they should be mirrored in the .env.template so that all devs are notified of the changes.

Suggestion 2: Utilize Cloud Service

This is meant to complement Suggestion 1 above. The shortcomings of Suggestion 1 is that we are unable to commit important prod and staging env variables. This can be worked around by preparing special .env files only meant for staging and production and uploading that to the cloud services.

If you are currently using cloud service providers (gcloud, AWS, Azure, etc), most of them offer tools to manage your variables. For example in Azure DevOps, you can upload .env files in Pipelines/Library to be used during your CI like the picture below:

Azure DevOps .env file.

You can take a step further and store .env.staging and .env.prod to target different environments. Your file will only be as secure as the security rules you define for it, so please make sure you configure them as needed.

Suggestion 3: Encryption

You can also choose to encrypt values that can only be decrypted by the production servers. This means you may get away with committing all production-level encrypted variables to version control.

However, some caution needs to be advised on how to handle the private key and where you are decrypting them (server vs client). They should only be decrypted on the server side. If done right, we can harness the full potential of version control by committing all information to version control.