Take the 2-minute tour ×

I keep important settings like the hostnames and ports of development and production servers in my version control system. But I know that it's bad practice to keep secrets (like private keys and database passwords) in a VCS repository.

But passwords--like any other setting--seem like they should be versioned. So what is the proper way to keep passwords version controlled?

I imagine it would involve keeping the secrets in their own "secrets settings" file and having that file encrypted and version controlled. But what technologies? And how to do this properly? Is there a better way entirely to go about it?

I ask the question generally, but in my specific instance I would like to store secret keys and passwords for a Django/Python site using git and github.

Also, an ideal solution would do something magical when I push/pull with git--e.g., if the encrypted passwords file changes a script is run which asks for a password and decrypts it into place.

EDIT: For clarity, I am asking about where to store production secrets.

share|improve this question
Actually front up some money to keep the whole repo private. –  John Mee Jul 20 '12 at 8:22
@JohnMee I actually already pay for a private repository, but the point remains--you shouldnt keep sensitive information in your repository. –  Chris W. Jul 20 '12 at 8:25
I think a large part of the reason satisfying answers will be hard to get is that the old-fashioned plaintext password to connect to a database is a relic of a less hostile era. The proper answer is something like "your code shouldn't need a secret", but the systems you are accessing don't give you much choice. –  msw Jul 26 '12 at 11:54
Will you access this confidential data only from Python? Then I would recommend a special file object. –  User Jul 29 '12 at 19:13
@user1320237 a special file object? What is that? Where can I find documentation? –  Chris W. Jul 30 '12 at 16:49

14 Answers 14

You're exactly right to want to encrypt your sensitive settings file while still maintaining the file in version control. As you mention, the best solution would be one in which Git will transparently encrypt certain sensitive files when you push them so that locally (i.e. on any machine which has your certificate) you can use the settings file, but Git or Dropbox or whoever is storing your files under VC does not have the ability to read the information in plaintext.

Tutorial on Transparent Encryption/Decryption during Push/Pull

This gist https://gist.github.com/873637 shows a tutorial on how to use the Git's smudge/clean filter driver with openssl to transparently encrypt pushed files. You just need to do some initial setup.

Summary of How it Works

You'll basically be creating a .gitencrypt folder containing 3 bash scripts,


which are used by Git for decryption, encryption, and supporting Git diff. A master passphrase and salt (fixed!) is defined inside these scripts and you MUST ensure that .gitencrypt is never actually pushed. Example clean_filter_openssl script:


SALT_FIXED=<your-salt> # 24 or less hex characters

openssl enc -base64 -aes-256-ecb -S $SALT_FIXED -k $PASS_FIXED

Similar for smudge_filter_open_ssl and diff_filter_oepnssl. See Gist.

Your repo with sensitive information should have a .gitattribute file (unencrypted and included in repo) which references the .gitencrypt directory (which contains everything Git needs to encrypt/decrypt the project transparently) and which is present on your local machine.

.gitattribute contents:

* filter=openssl diff=openssl
    renormalize = true

Finally, you will also need to add the following content to your .git/config file

[filter "openssl"]
    smudge = ~/.gitencrypt/smudge_filter_openssl
    clean = ~/.gitencrypt/clean_filter_openssl
[diff "openssl"]
    textconv = ~/.gitencrypt/diff_filter_openssl

Now, when you push the repository containing your sensitive information to a remote repository, the files will be transparently encrypted. When you pull from a local machine which has the .gitencrypt directory (containing your passphrase), the files will be transparently decrypted.


I should note that this tutorial does not describe a way to only encrypt your sensitive settings file. This will transparently encrypt the entire repository that is pushed to the remote VC host and decrypt the entire repository so it is entirely decrypted locally. To achieve the behavior you want, you could place sensitive files for one or many projects in one sensitive_settings_repo. You could investigate how this transparent encryption technique works with Git submodules http://git-scm.com/book/en/Git-Tools-Submodules if you really need the sensitive files to be in the same repository.

The use of a fixed passphrase could theoretically lead to brute-force vulnerabilities if attackers had access to many encrypted repos/files. IMO, the probability of this is very low. As a note at the bottom of this tutorial mentions, not using a fixed passphrase will result in local versions of a repo on different machines always showing that changes have occurred with 'git status'.

share|improve this answer
Oh very interesting. This sounds almost exactly like what I want (except its encrypting the entire repository). –  Chris W. Jul 27 '12 at 21:21
You could either keep all the sensitive setting files for multiple applications in one encrypted repository or add the encrypted repository with the sensitive settings to your project as a Git submodule as described here git-scm.com/book/en/Git-Tools-Submodules . –  dghubble Jul 27 '12 at 23:17
Storing production passwords/settings in an (encrypted) submodules is not uncommon. stackoverflow.com/questions/11207284/… . It would even make it easier to manage settings across projects. –  dghubble Jul 27 '12 at 23:22

Heroku pushes the use of environment variables for settings and secret keys:

The traditional approach for handling such config vars is to put them under source - in a properties file of some sort. This is an error-prone process, and is especially complicated for open source apps which often have to maintain separate (and private) branches with app-specific configurations.

A better solution is to use environment variables, and keep the keys out of the code. On a traditional host or working locally you can set environment vars in your bashrc. On Heroku, you use config vars.

With Foreman and .env files Heroku provide an enviable toolchain to export, import and synchronise environment variables.

Personally, I believe it's wrong to save secret keys alongside code. It's fundamentally inconsistent with source control, because the keys are for services extrinsic to the the code. The one boon would be that a developer can clone HEAD and run the application without any setup. However, suppose a developer checks out a historic revision of the code. Their copy will include last year's database password, so the application will fail against today's database.

With the Heroku method above, a developer can checkout last year's app, configure it with today's keys, and run it successfully against today's database.

share|improve this answer
This answer hasn't enough attention, but it most coincides with the linux way. –  Nikolay Fominyh Aug 1 '12 at 8:53
So if environment vars are set in your bashrc, and you're deploying a new server, then what creates the bashrc? Doesn't that just move the passwords out of your source code repo, and into your deployment config? (which is presumably also in the source code repo, or in a repo of its own?) –  Jonathan Hartley Feb 1 '13 at 16:14

The cleanest way in my opinion is to use environment variables. You won't have to deal with .dist files for example, and the project state on the production environment would be the same as your local machine's.

I recommend reading The Twelve-Factor App's config chapter, the others too if you're interested.

share|improve this answer
It seems like environment variables are a good way to run the application with the secret settings... but it still doesnt answer the question of where to keep those settings. –  Chris W. Jul 27 '12 at 21:22
You should usually have a README file for each of your apps. In there, specify which environment variables should be set, and every time you deploy a project, just follow the steps and set each of them. You can also create a shell script with many export MY_ENV_VAR=, and when you deploy, just fill it with the right values and source it. If by keep you mean version the settings, you shouldn't be doing this in the first place. –  Samy Dindane Jul 27 '12 at 22:46
Also, upvote for The Twelve-Factor App--really great stuff. –  Chris W. Aug 1 '12 at 7:05
@Samy: And if you've automated deployment? –  Jonathan Hartley Feb 1 '13 at 16:15
@JonathanHartley: Updating your production environment shouldn't change environment variables. If you want to update them, you should do it manually, whether you deploy a new version of your application or not. –  Samy Dindane Feb 1 '13 at 18:19

An option would be to put project-bound credentials into an encrypted container (TrueCrypt or Keepass) and push it.

Update as answer from my comment below:

Interesting question btw. I just found this: github.com/shadowhand/git-encrypt which looks very promising for automatic encryption

share|improve this answer
It would be nice to have something which I could automate. Such that if my encrypted password file changes it automatically decrypts the new file. –  Chris W. Jul 20 '12 at 8:21
Interesting question btw. I just found this: github.com/shadowhand/git-encrypt which looks very promising for automatic encryption. –  schneck Jul 20 '12 at 8:24
Wow, great. The description of git-encrypt sounds like exactly what I'm looking for " When working with a remote git repository which is hosted on a third-party storage server, data confidentiality sometimes becomes a concern. This article walks you through the procedures of setting up git repositories for which your local working directories are as normal (un-encrypted) but the committed content is encrypted." (Of course, I only want a subset of my content encrypted...) –  Chris W. Jul 20 '12 at 8:27
@schneck post your comment as an answer so that Chris could accept it - sounds like it's what he's looking for. –  Tony Abou-Assaleh Jul 27 '12 at 18:31
@TonyAbou-Assaleh I did, thanks for the hint :) –  schneck Jul 30 '12 at 13:06

I suggest using configuration files for that and to not version them.

You can however version examples of the files.

I don't see any problem of sharing development settings. By definition it should contain no valuable data.

share|improve this answer
But then where to store the canonical password records? It would make me nervous to have that data sitting only in a configuration file on a machine which might blow up some day. –  Chris W. Jul 20 '12 at 8:23
@ChrisW. If the machine blows up, you don't necessarily need the password anymore... However, if you only have one copy of the data on your production machine, that should raise up a red flag. But that doesn't mean it should be in VCS. There should be RAID, full backups supplemented by incremental backups on magnetic and optical media. A lot of corporations have a change control procedure which may dictate how and where to store passwords and other sensitive materials on paper as well. –  Steve Buzonas Jul 29 '12 at 16:58
@ChrisW I dont' want to be rough but it seems you don't tell us the truth and the passwords you want to store are not used in Development but in production. Isn't this true? Otherwise, why do you care for a development or test machine and development passwords? Nobody would do that. –  tiktak Jul 30 '12 at 17:59
BTW, at our company, all the development passwords are available on paper and on the intranet. Because they have no value. They're there because the software we develop needs authentication. –  tiktak Jul 30 '12 at 18:01
@tiktak, you are correct--my question is about what do with regard to production passwords. I dont particularly care about storing development passwords in A VCS in the clear. Sorry if I haven't made that clear enough. –  Chris W. Jul 30 '12 at 21:21

EDIT: I assume you want to keep track of your previous passwords versions - say, for a script that would prevent password reusing etc.

I think GnuPG is the best way to go - it's already used in one git-related project (git-annex) to encrypt repository contents stored on cloud services. GnuPG (gnu pgp) provides a very strong key-based encryption.

  1. You keep a key on your local machine.
  2. You add 'mypassword' to ignored files.
  3. On pre-commit hook you encrypt the mypassword file into the mypassword.gpg file tracked by git and add it to the commit.
  4. On post-merge hook you just decrypt mypassword.gpg into mypassword.

Now if your 'mypassword' file did not change then encrypting it will result with same ciphertext and it won't be added to the index (no redundancy). Slightest modification of mypassword results in radically different ciphertext and mypassword.gpg in staging area differs a lot from the one in repository, thus will be added to the commit. Even if the attacker gets a hold of your gpg key he still needs to bruteforce the password. If the attacker gets an access to remote repository with ciphertext he can compare a bunch of ciphertexts, but their number won't be sufficient to give him any non-negligible advantage.

Later on you can use .gitattributes to provide an on-the-fly decryption for quit git diff of your password.

Also you can have separate keys for different types of passwords etc.

share|improve this answer


No, just don't, even if it's your private repo and you never intend to share it, don't.

You should create a local_settings.py put it on VCS ignore and in your settings.py do something like

from local_settings import DATABASES, SECRET_KEY


If your secrets settings are that versatile, I am eager to say you're doing something wrong

share|improve this answer
But i'll still need to keep track of those secrets somewhere. E.g., keypass or something along those lines, right? –  Chris W. Jul 20 '12 at 21:44

Provide a way to override the config

This is the best way to manage a set of sane defaults for the config you checkin without requiring the config be complete, or contain things like hostnames and credentials. There are a few ways to override default configs.

Environment variables (as others have already mentioned) are one way of doing it.

The best way is to look for an external config file that overrides the default config values. This allows you to manage the external configs via a configuration management system like Chef, Puppet or Cfengine. Configuration management is the standard answer for the management of configs separate from the codebase so you don't have to do a release to update the config on a single host or a group of hosts.

FYI: Encrypting creds is not always a best practice, especially in a place with limited resources. It may be the case that encrypting creds will gain you no additional risk mitigation and simply add an unnecessary layer of complexity. Make sure you do the proper analysis before making a decision.

share|improve this answer

Usually, i seperate password as a config file. and make them dist.


And when i run main.py, put the real password in default.cfg that copied.

ps. when you work with git or hg. you can ignore *.cfg files to make .gitignore or .hgignore

share|improve this answer
I'm not familiar with .dist files--how do they work? –  Chris W. Jul 30 '12 at 16:53
.dist files are what I was talking about: examples of real configuration files. A good practice is that it should be possible to run the software only by renaming by removing the ".dist" extension (or better: copying), that is, you should be able to try software in seconds, without having to configure it during the whole day. –  tiktak Jul 30 '12 at 18:04

Encrypt the passwords file, using for example GPG. Add the keys on your local machine and on your server. Decrypt the file and put it outside your repo folders.

I use a passwords.conf, located in my homefolder. On every deploy this file gets updated.

share|improve this answer
Then the software needs to decrypt the password file. –  tiktak Jul 30 '12 at 18:05
Well, only when deploying the site the password get decrypted and written to a plain text password file –  Willian Jul 31 '12 at 7:21

No, private keys and passwords do not fall under revision control. There is no reason to burden everyone with read access to your repository with knowing sensitive service credentials used in production, when most likely not all of them should have access to those services.

Starting with Django 1.4, your Django projects now ship with a project.wsgi module that defines the application object and it's a perfect place to start enforcing the use of a project.local settings module that contains site-specific configurations.

This settings module is ignored from revision control, but it's presence is required when running your project instance as a WSGI application, typical for production environments. This is how it should look like:

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.local")

# This application object is used by the development server
# as well as any WSGI server configured to use this file.
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

Now you can have a local.py module who's owner and group can be configured so that only authorized personnel and the Django processes can read the file's contents.

share|improve this answer

If you need VCS for your secrets you should at least keep them in a second repository seperated from you actual code. So you can give your team members access to the source code repository and they won't see your credentials. Furthermore host this repository somewhere else (eg. on your own server with an encrypted filesystem, not on github) and for checking it out to the production system you could use something like git-submodule.

share|improve this answer
up vote 1 down vote accepted

BlackBox was recently released by StackExchange and while I have yet to use it, it seems to exactly address the problems and support the features requested in this question.

From the description on https://github.com/StackExchange/blackbox:

Safely store secrets in a VCS repo (i.e. Git or Mercurial). These commands make it easy for you to GPG encrypt specific files in a repo so they are "encrypted at rest" in your repository. However, the scripts make it easy to decrypt them when you need to view or edit them, and decrypt them for for use in production.

share|improve this answer

You could use EncFS if your system provides that. Thus you could keep your encrypted data as a subfolder of your repository, while providing your application a decrypted view to the data mounted aside. As the encryption is transparent, no special operations are needed on pull or push.

It would however need to mount the EncFS folders, which could be done by your application based on an password stored elsewhere outside the versioned folders (eg. environment variables).

share|improve this answer

Your Answer


