Git Some Common Sense – Use Environment Variables

It may seem like common sense to some but using environment variables to mask sensitive access/account information is something more and more junior developers are NOT learning in code schools.  Join me as I take a look at some easy ways to prevent that important information from being pushed to your public code base.

This post assumes you’re using Git as your version tracking system.  I’ll be updating this with Mercurial commands in the next week or so.  Thank you for your patience!

In this age of identity theft and corporate data breaches we are constantly bombarded by reminders to set strong passwords, use two factor authentication, and keep our personal information out of the hands of strangers as much as possible.  Keep your Social Security card locked in a safe deposit box or safe, cut up old credit cards, and things of that nature are almost held as universal constants these days.  Danger is lurking everywhere…

Yet when it comes to public code repositories some developers unknowingly present sensitive information openly to the world.

While there are numerous ways sensitive information can be exposed via public repositories, I’m going to focus on using environment variables to “hide” things like credentials, keys, and access tokens from the outside world so you can safely push your code to GitHub.

I will cover several different ways to implement environment variables in a Ruby on Rails application so that you at least know some of the options available to you.

Note:  Methods 1 through 3 will require some manual work to upload the untracked environment variable file to your production system.  This is less than ideal but is currently necessary for safety and security of the information.

1.  A Custom Local Environment File

The method I have most commonly used when creating side projects with sensitive access credentials is to create a local environment file.  Rails 4.1 provides its own secrets.yml file that I’ll cover later, but I do it this way just to get in the practice of knowing HOW things work instead of just relying on “magic” and sugar.

The Process: (after you’ve cloned or initialized the git repo)

  • Create a local_env.yml file in your /config/ directory of your app.

  • Inside that file you’d layout your environment variables for your particular use case like the following example:

TWILIO_API_KEY: 'your_twilio_api_key'
TWILO_SID_: 'your_twilio_sid'
  • Add the file to .gitignore by opening the .gitignore file in the root of your app directory and placing a relative path to your local_env.yml file like this:  /config/local_env.yml 

  • Open your config/application.rb file and add the following lines inside the class Application < Rails::Application section:

config.before_configuration do
  env_file = File.join(Rails.root, 'config', 'local_env.yml')
  YAML.load(File.open(env_file)).each do |key, value|
    ENV[key.to_s] = value
  end
end

This will open the config/local_env.yml file and then set the environment variables based on the key/value pairs in the file.  Keep in mind that this code requires that the file exists.

Usage:

In order to use the environment variables in your code you simply need to use this format:  ENV['KEY_NAME']

So in the case of our earlier example, you would use:  ENV['TWILIO_API_KEY']

*Code sample modified from the snippet provided on the RailsApps Project’s Rails Environment Variables article by Taylor Mock and Daniel Kehoe

2.  Rails secrets.yml file

Starting in Rails 4.1 the secrets.yml file has been made available to hold environment variables.  You still need to manually add this file to the .gitignore file, Rails does not currently do this for you.  Otherwise this functions much the same as method 1 except for three differences.

The first difference is that Rails will create and populate this file by default with the secret_key_base for your application.  It will also load this file by default without you needing to update the config/application.rb file.

Next, you don’t need to use the same KEY_NAME = VALUE_NAME format as with the custom .yml file.  You can enter in your key/value pairs in lowercase as they’ll be accessed in a different manner than method 1

The final difference is that you can use Rails.application.secrets.<key_name> to access the environment variables in your application.  Keeping with our example from method 1, this would be used as follows:

Rails.application.secrets.twilio_api_key

3.  dotenv (a Ruby gem)

The dotenv gem simplifies some of the setup of things by allowing you to create a .env file at the root of your application directory to hold the sensitive information.  Like methods 1 and 2, you still need to add the .env to your .gitignore file.

The Process:

  • Include the gem in your Gemfile 
group :development, :test do
  gem 'dotenv-rails', '~> version_number'
end
  • In the terminal run:
bundle install # or however you choose to handle your gem installations
  • Create the .env file and then add your key/value information in with the following format:
KEY_ONE_NAME=KEY_ONE_VALUE
KEY_TWO_NAME=KEY_TWO_VALUE

Usage:

You can now call your environment variables just as in method 1 by using:

ENV['KEY_ONE_NAME'] 

4. Figaro (another Ruby gem)

Figaro aims to build upon what dotenv does by automating some of the steps.  It handles the creation of a config/application.yml file AND then adds it to the .gitignore file as well.

The Process:

  • Add the gem to your Gemfile as follows:
gem 'figaro'
  • In the Terminal run:
bundle exec figaro install

Usage:

You can either choose to access the environment variables via the previously mentioned ENV['key_name']

# config/application.yml

twilio_app_sid: "SID_VALUE"
twilio_api_key: "API_KEY_VALUE"

Also you can add them to an initializer and have them handled for you like this:

# config/initializers/<initializer_name>.rb

<ClassName>.sid = ENV['twilio_app_sid']
<ClassName>.api_key = ENV['twilio_api_key']

 

*Note: Figaro also provides a handy way to push the configuration values up to Heroku from the configuration file via the following command:

figaro heroku:set -e production

5.  3rd Party Services

Some product environment hosting services, like Heroku, allow you to set your production environment variables via a GUI interface or via a command line tool.  Since these implementations are normally unique to the service itself I’m not going to cover them here but I highly encourage you to look over the documentation of your hosting provider and see if that might be an option.

Additionally, some of the steps of placing an environment variable file on your production site can be automated with services like Chef, Anisble, or Puppet (great job on the re-brand, Puppet!!!).

Like the hosting services, these implementations are all unique so you’ll have to look into them yourself to learn more.

Wrapping up

As you can see you have a few different options of how to handle sensitive information in your application.  While this is by no means an exhaustive list of options, it gives you the basic idea to start from.  Securing this information might not seem like a big deal for a one-off side project but when it comes time to work on a client’s project or something sensitive for a company, knowing how to handle this information is vital.

Please reach out to me via the comments or contact form if you have any questions, ideas, or criticism!

Leave a Reply

Your email address will not be published. Required fields are marked *