I'm looking to hear some best practices...
Assuming a web application that interacts with a few different production servers (databases, etc.)... should the configuration files that include database passwords be stored in source control (e.g., git, svn)?
If not, what's the best way to keep track of server database (or other related) passwords that your application needs access to?
Edit: added a bounty to encourage more discussion and to hear what more people consider best practice.
I prefer to have a local_settings file beside the main settings file. This local_settings shouldn't be added to the repository, but I will add a sample.local_setting to the repository to show the structure of this file.
In run time if a local_settings exists, its values will override the values of main settings file.
For example in python:
settings.py:
local_settings.py:
There's no single "silver bullet" answer here and it would all greatly depend on details.
First of all, I consider best practice to separate all source code from configuration in separate repository. So, source code remains source code, but it's installation or deployment (with configuration, passwords, etc) is the whole other thing. This way you'll firmly separate developers' tasks from sysadmins' tasks and can ultimately build 2 distinct teams doing what's they're good at.
When you have separate source code repository + deployment repository, your best next bet is considering deployment options. Best way I see here is using deployment procedures typical for a chosen OS (i.e. building autonomous packages for a chosen OS the way that OS's maintainers do).
For example, Red Hat or Debian packaging procedures usually mean grabbing a tarball of software from external site (that would be exporting sources from your source code VCS), unpacking it, compiling and preparing packages ready for deployment. Deployment itself should ideally mean just doing a quick & simple command that would install the packages, such as
rpm -U package.rpm
,dpkg --install package.deb
orapt-get dist-upgrade
(given that your built packages go to a repository where apt-get would be able to find them).Obviously, to get it working this way, you'll have to supply all configuration files for all components of a system in a fully working state, including all addresses and credentials.
To get more concise, let's consider a typical "small service" situation: one PHP application deployed across n application servers running apache / mod_php, accessing m MySQL servers. All these servers (or virtual containers, that doesn't really matter) reside in a protected private network. To make this example easier, let's assume that all real internet connectivity is fronted by a cluster of k http accelerators / reverse proxies (such as nginx / lighttpd / apache) which have very easy configuration (just internal IPs to forward to).
What do we have for them to be connected and fully working?
Note that there are 2 different "types" of information here: IPs/hostnames is something fixed, you'd likely want to assign them once and for all. Logins & passwords (and even database names), on the other hand, are purely for connectivity purposes here - to make sure for MySQL that it's really our PHP application connecting to it. So, my recommendations here would be splitting these 2 "types":
The last and the toughest question remains here: how to create deployment packages? There are multiple techniques available, 2 main ways are:
For an example above, I'd create packages like:
my-application-php
- which would depend on mod_php, apache and would include generated file like/etc/my-php-application/config.inc.php
that will include MySQL database IPs/hostnames and login / password generated asmd5(current source code revision + salt)
. This package would be installed on every of n application servers. Ideally, it should be able install on a cleanly installed OS and make a fully working application cluster node without any manual activity.my-application-mysql
- which would depend on MySQL-server and would include post-install script that:/etc/my-php-application/config.inc.php
, using md5 algorithm)Ultimately, it should bring the benefit of upgrading your deployment using single command like
generate-packages && ssh-all apt-get dist-upgrade
. Also, you do not store inter-applications passwords anywhere and they get regenerated on every update.This fairly simple example illustrates a lot of methods you can employ here - but, ultimately, it's up to you to decide which solution is better here and which one is overkill. If you'll put more details here or as a separate question, I'll gladly try to get into details.
In general, I agree with paxdiablo: put everything you possibly can under source control. That includes production configuration files with database credentials.
Think about the situation where your server crashes, the backups turn out to be bad and you need to get that server back up. I think you and your customer (or boss) would definitely agree that having everything needed to deploy the site in source control is a big plus.
If you want to build easily deployable packages from your sources using continuous integration (another best practice) you'll have to put the configuration files under source control.
Also consider that in most cases the devs that have source control access cannot access the production database server directly. The production passwords are useless to them.
If the wrong people gained access to your sources, they still need to gain access to the production server in order to do harm with the passwords. So, if your production environment is properly protected, the security risks of passwords in source control are very limited.
Sample configurations file, sure, I would put them under version control. But usually not with realworld access data such as server addresses or passwords. More somethinglike
Problems with passwords in source code:
What I have found works the best is having a config checked in that uses mixture sane defaults and placeholders for deployment specific data. Our apps always look for a system config which allows the override of any variable. This allows the production machine to have a config appropriate for it's deployment.
Note: When I function as an admin I always manage configs separately from code (for good reason).
I found that using a build script (Phing in my case) was the best way to input passwords.