Using Figaro and Secrets.yml to Manage Env Variables - ruby-on-rails

I have a rails 4.1 app and I'm trying to organize my env variables. As of right now I have a secrets.yml file in my config/ folder. I also installed the figaro gem. My goal was to have all my env variables in the application.yml (not checked into git) file and then use the secrets.yml (checked into git) file to map the variables from appliation.yml to the application. When I print the files using Rails.application.secrets It just shows hashes that look like this:
:salesforce_username=>"ENV['SALESFORCE_USERNAME']"
None of my external services are working with this env variables setup. When I view the traces, the actually ENV['ACCOUNT_ID'] are being passed through in the requests like this:
v2/accounts/ENV['ACCOUNT_ID']/envelopes
In addition, I cannot access my env variables using Rails.application.secrets.account_id in my app.
secrets.yml
development:
account_id: <%= ENV['ACCOUNT_ID'] %>
aplication.yml
development:
ACCOUNT_ID: "123456"
application.rb
# preload tokens in application.yml to local ENV
config = YAML.load(File.read(File.expand_path('../application.yml', __FILE__)))
config.merge! config.fetch(Rails.env, {})
config.each do |key, value|
ENV[key] = value.to_s unless value.kind_of? Hash
end

The gem provides a generator:
$ rails generate figaro:install
The generator creates a config/application.yml file and modifies the .gitignore file to prevent the file from being checked into a git repository.
You can add environment variables as key/value pairs to config/application.yml:
GMAIL_USERNAME: Your_Username
The environment variables will be available anywhere in your application as ENV variables:
ENV["GMAIL_USERNAME"]
This gives you the convenience of using the same variables in code whether they are set by the Unix shell or the figaro gem’s config/application.yml. Variables in the config/application.yml file will override environment variables set in the Unix shell.
In tests or other situations where ENV variables might not be appropriate, you can access the configuration values as Figaro method calls:
Figaro.env.gmail_username
Use this syntax for setting different credentials in development, test, or production environments:
HELLO: world
development:
HELLO: developers
production:
HELLO: users
In this case, ENV["HELLO"] will produce “developers” in development, “users” in production and “world” otherwise.

You say the ENV variables are being "passed through in the requests", but when I look at your code snippets I think the variables aren't ever being detected as such in the first place.
If you want to inject a variable into a string, double-check that you are using the following format, especially the # and {}:
important_string = "v2/accounts/#{ENV['ACCOUNT_ID']}/envelopes"
On a more general note, if you're unsure what environment variables are being set in a given environment, the easiest way to double-check is to open up the Rails console and query ENV like so:
$ rails console
> puts ENV.keys # find out what ENV vars are set
=> (returns a long list of var names)
> puts ENV['DEVISE_PEPPER']
=> "067d793e8781fa02aebd36e239c7878bdc1403d6bcb7c380beac53189ff6366be"

Related

Rails: use another .env file

I am running a mastodon server with two instances on the same server.
Mastodon is basically a rails app and has the command line tool called tootctl.
Normally you use it like so:
RAILS_ENV=production bin/tootctl accounts modify alice --role Owner
This uses the default env file .env.production that was created when installing the first instance.
But now I need to manage the second instance for which I need to use the second env file .env.production.de
Question: How do I tell rails to use another .env file than the default one?
I would need something like
RAILS_ENV=production RAILS_ENV_FILE=.env.production.de bin/tootctl accounts modify alice --role Owner .
For each of the Rails apps you can use Option Three: Use a local_env.yml File as found in this article: http://railsapps.github.io/rails-environment-variables.html
So something like:
The local_env.yml File
Create a file config/local_env.yml:
# Rename this file to local_env.yml
# Add account settings and API keys here.
# This file should be listed in .gitignore to keep your settings secret!
# Each entry gets set as a local environment variable.
# This file overrides ENV variables in the Unix shell.
# For example, setting:
# GMAIL_USERNAME: 'Your_Gmail_Username'
# makes 'Your_Gmail_Username' available as ENV["GMAIL_USERNAME"]
GMAIL_USERNAME: 'Your_Gmail_Username'
Set .gitignore
If you have created a git repository for your application, your application root directory should contain a file named .gitignore (it is a hidden file). Be sure your .gitignore file contains:
/config/local_env.yml
This prevents the config/local_env.yml file from being checked into a git repository and made available for others to see.
Rails Application Configuration File
Rails provides the config/application.rb file for specifying settings for various Rails components. We want to set our environment variables before any other settings. Rails provides a config.before_configuration method to do so.
Find the following code at the end of the config/application.rb file:
#Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
and add this code after it:
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 if File.exists?(env_file)
end
The code opens the config/local_env.yml file, reads each key/value pair, and sets environment variables.
The code only runs if the file exists. If the file exists, the code overrides ENV variables set in the Unix shell.
This way each Rails app has its own ENV variables but you can access them all with the same ENV["SOME_KEY"]
Important: Understand that since these files are in .ignore they won't get backed up to version control. But also if you are pushing to your production sever elsewhere they won't get copied over, you'd have to do that manually. And if you are storing passwords or API keys the file is not encrypted in any way so it is not secure if someone gains access to your server. I'm not sure how services like Heroku store their ENV variables that you can set. Probably encrypted in your Rails install using your profile. You will probably want to research that if you choose to go this route.

How do I get Rails to recognize environment variables defined in config/environment_variables.yml?

With Rails 5, if I create a file, config/environment_variables.yml, that contains
development:
MY_VAR: abcdef
What do I need to do to get the Rails environment to recognized that environment variable? Right now, when I go to my console (by typing "rails console") on my local machine, it isn't turning up anything ...
2.4.0 :001 > ENV['MY_VAR']
=> nil
If you don't wish to use a gem, you can place this in your config/application.rb
# Load application ENV vars and merge with existing ENV vars. Loaded here so you can use the values in initializers.
ENV.update YAML.load_file('config/application.yml')[Rails.env] rescue {}
Then your config/application.yml file should look like:
development:
API_KEY: 12345
staging:
API_KEY: 67890
Be sure to restart your server, then you can access the variables as you desire with ENV['API_KEY'].

Where is SECRET_KEY_BASE environment variable located when I start Rails app in Production

In the Rails 4 In Action Book, it states that after doing some other setup: the final setup to boot up your rails app in production mode (with web brick) is to enter this command in terminal:
SECRET_KEY_BASE='rake secret' rails s -e production
I am trying to see where the environment variable of SECRET_KEY_BASE is stored.
Within /app/config/secrets.yml it says that the secret_key_base variable is an environment variable:
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
But I looked within .bashrc and .bash_profile and the variable SECRET_KEY_BASE is not there.
Ultimately I want to know: where is environment variable and its value? Is it stored somewhere in my rails app? I hope not for security purposes if I push this app to github. I assume it is not stored in the app but in my computer system somewhere. Within a different terminal window I do echo $SECRET_KEY_BASE but nothing gets returned.
Thanks in advance for helping me understand the missing pieces.
As a side note: I am aware of this question, but the question is not as detailed and there is no provided answer.
When you run this:
SECRET_KEY_BASE='rake secret' rails s -e production
you are not actually 'saving' the secret key for future you. You're defining it on a one-time basis. Whenever you run a Ruby command you can set temporary environment variables:
# from shell
KEY="VAL" OTHER_KEY=OTHER_VAL ruby my_command.rb
# from the ruby script
puts ENV["KEY"] # => "VAL"
puts ENV["OTHER_KEY"] # => "OTHER_VAL"
To persist the environment variables you have a couple options. You could hard code them in your source code, but this is probably not a good idea because if you push your code to Github, anyone will be able to see it. That's kind of the point of environment variables, anyway, that you can keep them system specific.
Option A
You can set them in .bashrc or .bash_profile
First get the result of rake secret (will be a random string) and set a shell variable:
KEY=`rake secret` # uses backticks to get command result
Then add a line in bashrc to export it:
echo -e "export SECRET_KEY_BASE=$KEY" >> ~/.bashrc
Option B
This is the one I'd recommend, you can use dotenv or figaro to manage your environment variables in an app-specific way, i.e. without cluttering up your bashrc.
For example with dotenv you'd create a .env file which contains:
# change this to the result of rake secret
SECRET_KEY_BASE=j3e2dd293d
This would be excluded from source control by adding it to gitignore.
Then in your ruby app you call
require 'dotenv'
Dotenv.load
and your ENV["SECRET_KEY_BASE"] will be set.
If you want you can make a .env.example file (included in source control) which shows which environment variables need to be defined. Then when the app is cloned you can run mv .env.example .env and customize .env.

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. :-)
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.
Rails.application.secrets.key_name
One way to do it is to store those secret keys in environment variables. How to set an environment variable is different depending on what operating system you're on. For a linux machine, usually you're editing a .bashrc or .bash_profile file in your home directory and adding a line that looks like:
export API_KEYS=apikeygoeshere
You'll have to edit the file for whatever user will run rails.
Then in production.rb, you can refer to those environment variables as:
ENV["API_KEYS"]
Another option is to use a ruby gem that essentially takes care of that for you, like figaro. The way it works is that you create another file that you don't check in and figaro takes care of setting them up as environment variables, which you can then refer to in your development.rb/production.rb scripts using the ENV["API_KEYS"] above. Because you aren't checking in the file that has all of the environment variables, you'll have to find some way to get that file onto whatever machines are running the code.
I know this question is specific to Rails 4.1, but those who upgrade to Rails 5.1 it now includes built in secret generation. Which seems a much better way to handle sensitive data in your rails app.
See: http://edgeguides.rubyonrails.org/5_1_release_notes.html#encrypted-secrets
A nice approach to deal with different environments would be to:
EDITOR=vim rails credentials:edit
development:
cloudinary:
cloud_name: dxe1hjkoi
api_key: 361019726125669
api_secret: Cn6tHfSf019278367sZoO083eOI
production:
cloudinary:
cloud_name: oiajsu98u
api_key: 091828812791872
api_secret: KJS98182kjaksh89721jhS9812j
Then use it as:
Cloudinary.config do |config|
config.cloud_name =
Rails.application.credentials.dig(Rails.env.to_sym, :cloudinary, :cloud_name)
config.api_key =
Rails.application.credentials.dig(Rails.env.to_sym, :cloudinary, :api_key)
config.api_secret =
Rails.application.credentials.dig(Rails.env.to_sym, :cloudinary, :api_secret)
end

Ruby setting ENV variables on a mac

I would like to try an keep my development machine as close as the production server (heroku in this case).
Heroku lets you define config vars ie.
config:add key=val
This is now pretty secure as secret key values are not stored in my code.
Do you know how and where can I create such environment variables per app on my local mac machine.
I have googled this and as of yet not found a good solution. Any ideas ?
Thanks in advance.
Thanks Zabba, But I have actually found a great way for me.
I am using POW to run my local apps and reading the docs I have found out that you can set Environment Vars by adding a .powenv file in the root of my app ie.
export API_KEY='abcdef123456'
You can then use in your app like normal ie.
api_key = ENV['API_KEY']
Pretty kool stuff.
Here's a way:
Go to http://railswizard.org/ and add only "EnvYAML" to the template. Click finish and then click on the generated .rb file. See how that code is using a file config/env.yml to set ENV vars.
Here is how it is done, thanks to http://railswizard.org/:
In your app's directory:
Append in config/application.rb:
require 'env_yaml'
Create a file called lib/env_yaml.rb:
require 'yaml'
begin
env_yaml = YAML.load_file(File.dirname(__FILE__) + '/../config/env.yml')
if env_hash = env_yaml[ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development']
env_hash.each_pair do |k,v|
ENV[k] = v.to_s
end
end
rescue StandardError => e
end
Create a file called config/env.yml:
defaults: &defaults
ENV_YAML: true
some_key: value
development:
<<: *defaults
test:
<<: *defaults
production:
<<: *defaults
Note that ENV is not a Hash - it only appears so because of the use of []. That is why in lib/env_yaml.rb an each loop is setting in ENV the value of each value found in the config/env.yml - because we cannot assign a Hash directly to ENV.
I'm not using pow but rvm and bash. I was able to set environmental variables by following the instructions at this Peachpit blog post.
Like the other answers, I had to add commands like export TWILIO_ACCOUNT_SID="XXX"but to my ~/.profile file.
Then, accessed the variables in my code with:
account_sid = ENV["TWILIO_ACCOUNT_SID"]
Put your environment variables in a .env file and foreman will pick them up automatically.

Resources