Saturday, September 10, 2011

Capistrano, Database.yml and how to deploy without exposing your database passwords

The other day we wanted to secure our database, changing the user (instead of root) and password that Rails uses. Having them harcoded in database.yml makes it unsafe.

Fortunately we deploy through Capistrano, and there is a recipe for deploying using database credentials previously stored in the target machine. This way, database.yml is not available from source code and credentials remain private.

Everything is available as a gist here ( http://www.simonecarletti.com/blog/2009/06/capistrano-and-database-yml/ ) but I want to complete the information to save you some time.

The recipe is split into 2 tasks:
- generating the database.yml in the target machine (that will end with a cap deploy:setup )
- deploying , but using the database.yml in the target machine (that will end with the usual cap deploy)

Steps:
  1. Download the gist AND save it in /config/capistrano_database_yml.rb
  2. Follow Requirements point in the gist doc (or in the link above)
  3. Follow Usage point in the gist doc (or in the link above)
    1. Note that you must add a require line in your capistrano deploy.rb . This line should be: require "config/capistrano_database_yml" . Since it is searched in your $LOAD path
  4. Create a custom template as in the Custom template section of the gist doc.
    1. In our case we ask for user and password
    2. Save the template in config/deploy/database.yml.erb
    3. There is an error in the doc, at least for Rails 3. To make deploy prompt for user or password, use the usual arb syntax: <%= %> 
    4. We end with something like for the .erb:
      base: &base
        adapter: mysql2
        encoding: utf8
        pool: 5
        host: localhost
        timeout: 5000
        username: <%=Capistrano::CLI.ui.ask("Enter MySQL database username: ")%>
        password: <%=Capistrano::CLI.ui.ask("Enter MySQL database password: ")%>
      development:
        database: my_app_development
        <<: *base
      test:
        database: my_app_test
        <<: *base
      staging:
        database: my_app_staging
        <<: *base
      preproduction:
        database: my_app_preproduction
        <<: *base
      production:
        database: my_app_production
        <<: *base
  5. When the erb is saved. you can run the cap deploy:setup (or cap deploy:setup if you are in a multistage)
    1. this will create a database.yml in your_target_machine /shared/config/database.yml
    2. during this task you were asked for the username and password, and they will be written in the database.yml
    3. revise that the generated database.yml have the right privileges: will be accessible only to  the user you deploy and run teh application with
  6. Once done. You can deploy the application in the usual way. It will use the new database.yml
    1. cap deploy(or cap deploy)
For Jenkins, you must create (or copy) the database.yml to each of the jenkins 'projects'. As it runs test, you only need a database.yml with 'test' section. Revise the access rights of this file also (ex: chmod for Jenkins user only).
The location of databse.yml per project will be(in our case is):
/var/lib/jenkins/jobs//workspace/config/database.yml
 
Profit! 


P.S. As a bonus, take a look to this compilation of capistrano recipes:

https://github.com/webficient/capistrano-recipes


No comments:

Post a Comment