Search code examples
ruby-on-railssecuritycapistrano

How to use secrets.yml for API_KEYS in Rails 4.1?


In one of my recent projects I started out by .gitignoring the files containing secrets and environment variables. So the entire project is committed to the repo except the files that contain third party secrets such as that of Stripe, Twitter API or Facebook Graph or internal api_keys, ala the ./config/initializers/secret_token.rb file.

Now I am at a point where the project is about to go live (excited!) and I need to port all the environment variables on to the production server using Capistrano i.e. cap production deploy.

[Edit 4: Yr, 2018] In case of initializers/secret_token.rb it is clear that Rails 4.1 has a new way of handling secrets.yml file that pulls in the :secret_key_base value to the production server. Here, I recommend using the capistrano-secrets-yml gem which works right out of the box and is dead simple to use.

What is left is the way to carry other secrets like API_KEYS, APP_IDs etc. to the production server without checking any of those into the repo. How to do this, what is the most recommended/securest way or the best practices?

NOTE: I'll be editing the question as it progresses/I get more clarity.

EDIT1: Server is a Ubuntu/Linux VPS on DigitalOcean [Answer to Denise, below].

EDIT2: Can the env_variables/secrets be carried over to the server via secrets.yml? Secret_token for sessions is not the only secret after all! [Answered on Edit3]

EDIT3: Yes! It's possible to send in the API_keys via secrets.yml according to this blog. Will share my findings in sometime. :-)


Solution

  • First rule: DO NOT CHECK-IN secrets.yml into the repo.

    All right, here's how a secret.yml would look:

    development:
      secret_key_base: 6a1ada9d8e377c8fad5e530d6e0a1daa3d17e43ee... 
      # Paste output of $ rake secret here for your dev machine.
    
    test:
      secret_key_base: _your_secret_ as above
    
    production:
      secret_key_base: <%= secure_token %>
    
    
      STRIPE_PUBLISHABLE_KEY: 'Put your stripe keys for production'
      STRIPE_SECRET_KEY: 'Put actual keys for production here'
      FB_APP_SECRET: 'same as above'
      FB_CALLBACK_URL: 'FB url here'
      FB_CALLBACK_UPDATE_URL: 'FB url here'
      GOOGLE_KEY: 'Put your keys for production'
      GOOGLE_SECRET: 'same as above'
      TWITTER_KEY: 'same as above'
      TWITTER_SECRET: 'same as above'
      TWITTER_USERNAME: 'same as above'
      LINKEDIN_KEY: 'same as above'
      LINKEDIN_SECRET: 'same as above'
    

    Note the secure_token up there in the production: block. On production server I'm using an initializer to dynamically generate secret_tokens on-the-fly.

    sidenote: be careful about spaces and tabs inside the .yml file. It must be properly formatted and spaced (such as having a space after the ':' symbol).

    To set it up on production you could then scp the file directly from your local or use the capistrano-secrets-yml gem.

    This will not work. See an updated method as per @OddityOverseer's answer below.

    To access the environment variables in your app environments/production.rb use:

    FB_APP_SECRET            = ENV['FB_APP_SECRET']
    FB_CALLBACK_URL          = ENV['FB_CALLBACK_URL']
    FB_CALLBACK_UPDATE_URL   = ENV['FB_CALLBACK_UPDATE_URL']
    GOOGLE_KEY               = ENV['GOOGLE_KEY']
    GOOGLE_SECRET            = ENV['GOOGLE_SECRET']
    TWITTER_KEY              = ENV['TWITTER_KEY']
    TWITTER_SECRET           = ENV['TWITTER_SECRET']
    TWITTER_USERNAME         = ENV['TWITTER_USERNAME']
    LINKEDIN_KEY             = ENV['LINKEDIN_KEY']
    LINKEDIN_SECRET          = ENV['LINKEDIN_SECRET']
    

    UPDATED August-2016:

    To access the environment variables in your app environments/production.rb use:

    FB_APP_SECRET            = Rails.application.secrets.FB_APP_SECRET
    FB_CALLBACK_URL          = Rails.application.secrets.FB_CALLBACK_URL
    FB_CALLBACK_UPDATE_URL   = Rails.application.secrets.FB_CALLBACK_UPDATE_URL
    GOOGLE_KEY               = Rails.application.secrets.GOOGLE_KEY
    GOOGLE_SECRET            = Rails.application.secrets.GOOGLE_SECRET
    TWITTER_KEY              = Rails.application.secrets.TWITTER_KEY
    TWITTER_SECRET           = Rails.application.secrets.TWITTER_SECRET
    TWITTER_USERNAME         = Rails.application.secrets.TWITTER_USERNAME
    LINKEDIN_KEY             = Rails.application.secrets.LINKEDIN_KEY
    LINKEDIN_SECRET          = Rails.application.secrets.LINKEDIN_SECRET
    

    That's about it.