How to protect DB credentials for Rails app
This gem helps us to keep DB credentials for rails app in private place.
Installation
Add this line to to your Gemfile:
gem "shadow_db_credentials"
And then execute it:
$ bundle
Usage
Create “shadowed” credentials file (your_prod_credentials) inside some directory (e.g. ~/.credentials):
username: your_username
password: your_password
The location of your credentials directory is controlled by CREDENTIALS_DIR environment variable. Register it in config/initializers/env_variables.rb file:
ENV['CREDENTIALS_DIR'] ||= "#{ENV['HOME']}/.credentials"
If you want to have different credentials directory per environment, define it in corresponding env file:
# config/environments/development.rb
...
ENV['CREDENTIALS_DIR'] ||= "#{ENV['HOME']}/.credentials"
Remove all the credentials (username/password) that you don’t want to keep inside config/database.yml and replace them with single credentials attribute. It points to the name of your_prod_credentials file:
development:
adapter: postgresql
database: your_dev_db
credentials: your_dev_credentials
production:
adapter: postgresql
database: your_prod_db
credentials: your_prod_credentials
Note: If you want, you can move other sensitive information as well, such as database name, url etc.
adapter : postgresql
database: your_prod_db
username: your_username
password: your_password
Next, you have to create code hook inside rails config/application.rb in order to call gem’s API:
require 'shadow_db_credentials'
...
module YourRailsApp
class Application < Rails::Application
...
def config.database_configuration
orig_db_configurations = super
processor = ShadowDbCredentials.new(ENV['CREDENTIALS_DIR'])
processor.process_configurations(orig_db_configurations)
end
end
end
The hook will access original DB configuration and try to expand all credentials attributes with corresponding values dynamically, at run time.
If you think that processing all environments is not necessary, you cant process only current environment:
module YourRailsApp
class Application < Rails::Application
...
def config.database_configuration
orig_db_configurations = super
processor = ShadowDbCredentials.new(ENV['CREDENTIALS_DIR'])
processor.process_configuration(orig_db_configurations, Rails.env)
end
end
end
You can check result of your work:
$ rails console production
> ActiveRecord::Base.configurations["production"]
=> {"adapter"=>"postgresql", "username"=>"your_username", "password"=>"your_password"}
> Rails.application.config.database_configuration['production']
=> {"adapter"=>"postgresql", "username"=>"your_username", "password"=>"your_password"}
Or you can get connection information with API call:
require 'shadow_db_credentials'
credentials_dir = ENV['CREDENTIALS_DIR']
processor = ShadowDbCredentials.new(credentials_dir)
# 1. get production hash, read configuration from default location
prod_conf = processor.retrieve_configuration "production"
prod_conf.inspect
# 2. get development hash, read configuration from dynamic source
source = StringIO.new <<-TEXT
development:
adapter: postgresql
credentials: your_dev_db
TEXT
dev_conf = processor.retrieve_configuration 'development', source
dev_conf.inspect