TLDR version of this article >>here<<
Often when working on a Rails app, you will have to handle vulnerable data.
Most often these are API keys to services that you integrate.
Most common examples:
- Github, Google, Twitter, Facebook oAuth
- AWS S3
- Stripe, Braintree etc
- Sendgrid, Mailchimp etc
Here you can see a client_id
and client_secret
provided by Github, so that you can add "Log in with Github" functionality:
To use these keys, you could directly place them in your devise.rb
file like
config.omniauth :github, "23r32t34t4rg", "regregbesgbvtegc4g43g343"
However this approach creates a security threat.
For example, if your repository is ever open sourced or shared with third parties, anybody can misuse your API keys.
That can lead to your account:
- being banned (overuse quota with too many requests)
- charged (with your API keys anybody can upload too much data to your S3 account)
- you can experience a data leak (all your application attachements from S3 can be leaked)
That's why should use credentials to encrypt sensitive data.
An encrypted line in devise.rb
would look like:
config.omniauth :github, (Rails.application.credentials[Rails.env.to_sym][:github][:client]).to_s, (Rails.application.credentials[Rails.env.to_sym][:github][:secret]).to_s
So how do you make it work?
Let's start:
When you create a Rails 6 app, under app/config you have a file named credentials.yml.enc
:
If you open the credentials.yml.enc
file, it will usually look like this:
It is encrypted and safe to share in a public repository.
To decrypt the credentials.yml
file, the master.key
file is used:
NEVER SHARE THE MASTER KEY WITH THE PUBLIC.
IF YOU LOSE THE MASTER KEY, YOU WILL NOT BE ABLE TO DECRYPT YOUR CREDENTIALS
By default, master.key
is not included into your git commits.
To decrypt and view or edit your credentials.yml
,
you can run rails credentials:edit
or EDITOR=vim rails credentials:edit
.
When decripted, the credentials.yml
file would typically looks somewhat like this:
To retrieve any data from credentials.yml
in your rails app or in the console, you can run something like
rails c
Rails.application.credentials.dig(:aws, :access_key_id)
#=> sdgb89dngfm6cg8jmbdb8f9bfg6n8fnd7bd9f
Rails.application.credentials[:github][Rails.env.to_sym][:secret]
#=> 6hl65knh4l5vgm8
Editing the file in VIM inside a terminal can a feel tricky and unnatural.
To edit the file, press i
. You will see INSERT
appear on the bottom of the file, prompting that you are currently able to edit the file:
When you're done, press ESC
. next press :wq
+ ENTER
to exit with saving.
or press ESC
+ :q!
+ ENTER
to exit without saving.
Real-world example of config/credentials.yml:
awss3:
access_key_id: YOUR_CODE_FOR_S3_STORAGE
secret_access_key: YOUR_CODE_FOR_S3_STORAGE
google_analytics: YOUR_CODE_FOR_GOOGLE_ANALYTICS
recaptcha:
site_key: YOUR_CODE_FOR_RECAPTCHA
secret_key: YOUR_CODE_FOR_RECAPTCHA
google_oauth2:
client_id: YOUR_CODE_FOR_OAUTH
client_secret: YOUR_CODE_FOR_OAUTH
development:
github:
client: YOUR_CODE_FOR_OAUTH
secret: YOUR_CODE_FOR_OAUTH
stripe:
publishable: YOUR_STRIPE_PUBLISHABLE
secret: YOUR_STRIPE_SECRET
production:
github:
client: YOUR_CODE_FOR_OAUTH
secret: YOUR_CODE_FOR_OAUTH
stripe:
publishable: YOUR_STRIPE_PUBLISHABLE
secret: YOUR_STRIPE_SECRET
facebook:
client: YOUR_CODE_FOR_OAUTH
secret: YOUR_CODE_FOR_OAUTH
To set your master key in production (heroku example):
heroku config:set RAILS_MASTER_KEY=YOURMASTERKEY
or
heroku config:set RAILS_MASTER_KEY=`cat config/master.key`
That's it 🤠
Liked this article? Please follow me! It will really motivate me to post more fun stuff!
Top comments (4)
Pro tip:
I like to keep my credentials scoped to their respective environment. So I will always have a credentials/ directory and then the env files. ( i.e staging, production, development, test )
This way they all stay independent.
you can start this off by doing
rails credentials:edit -e development
& here's how it can look:
Yep! Looks great. I always always always have unique keys and credentials. It's more of a pain for rotation, but a better security practice.
Good advice!