My personal rails project uses a few API's for which I store the API keys/secrets in config/environments/production.yml and development.yml as global variables. I now want to push this project to github for others to use, but I don't want them to have those bits of sensitive data. I also don't want this file in .gitignore because it's required for the app to run. I've considered putting them in the DB somewhere, but am hoping to find a better solution.
5 Answers
TLDR: Use environment variables!
I think @Bryce's comment offers an answer, which I'll just flush out. It seems one approach Heroku recommends is to use environment variables to store sensitive information (API key strings, database passwords). So survey your code and see in which you have sensitive data. Then create environment variables (in your .bashrc file for example) that store the sensivite data values. For example for your database:
export MYAPP_DEV_DB_DATABASE=myapp_dev
export MYAPP_DEV_DB_USER=username
export MYAPP_DEV_DB_PW=secret
Now, in your local box, you just refer to the environment variables whenever you need the sensitive data. For example in database.yml :
development:
adapter: mysql2
encoding: utf8
reconnect: false
database: <%= ENV["MYAPP_DEV_DB_DATABASE"] %>
pool: 5
username: <%= ENV["MYAPP_DEV_DB_USER"] %>
password: <%= ENV["MYAPP_DEV_DB_PW"] %>
socket: /var/run/mysqld/mysqld.sock
I think database.yml gets parsed just at the app's initialization or restart so this shouldn't impact performance. So this would solve it for your local development and for making your repository public. Stripped of sensitive data, you can now use the same repository for the public as you do privately. It also solves the problem if you are on a VPS. Just ssh to it and set up the environment variables on your production host as you did in your development box.
Meanwhile, if your production setup involves a hands off deployment where you can't ssh to the production server, like Heroku's does, you need to look at how to remotely set up environment variables. For Heroku this is done with heroku config:add
. So, per the same article, if you had S3 integrated into your app and you had the sensitive data coming in from the environment variables:
AWS::S3::Base.establish_connection!(
:access_key_id => ENV['S3_KEY'],
:secret_access_key => ENV['S3_SECRET']
)
Just have Heroku create environment variables for it:
heroku config:add S3_KEY=8N022N81 S3_SECRET=9s83159d3+583493190
Another pro of this solution is that it's language neutral, not just Rails. Works for any app since they can all acquire the environment variables.
-
1This is by far the best solution presented here. Secure, simple, effective cross-platform, and performant. Couldn't ask for more. – piersadrian Mar 18 '13 at 15:55
-
2@yuvilio I have a follow-up question: How would one make said environment variables accessable to Ruby on Rails running on Ubuntu with Apache2/Phusion Passenger? – Yo Ludke Mar 20 '13 at 17:39
-
1@YoLudke For an app that's directed to through Apache, I would use the [SetEnv](http://httpd.apache.org/docs/2.4/mod/mod_env.html#setenv) directive in my Apache host file for the app. For example: ```SetEnv S3_KEY THESECRETKEY```. The environment variable would be available through the ENV global variable as ENV['S3_KEY'] as well. – yuvilio Mar 21 '13 at 18:29
-
1Just to mention it - when your using Phusion Passenger with Apache2 you can direct Phusion Passenger in its Apache configs to a script that exports the variables before running ruby - instead of directly running ruby, and this works perfectly for me `#!/bin/sh export EXAMPLE_VAR=example_value exec "/path/to/rvm/.rvm/wrappers/ruby-1.9.3-p371/ruby" "$@"` – Yo Ludke Mar 22 '13 at 10:13
-
Worth mentioning Foreman (part of Heroku's toolbelt) here: http://ddollar.github.io/foreman/#ENVIRONMENT – tybro0103 Feb 19 '14 at 21:45
-
I provided this same answer, hopefully, a little more concisely... see below. – tybro0103 Jun 03 '14 at 19:44
-
There could be a bug that shows env variables, for example when app crashes (hello php). Don't you think it's better to store secrets in config files and put the files to the server manually (or using scripts). – Zhomart Apr 20 '15 at 23:57
How about this...
Create a new project and check it into GitHub with placeholder values in the production.yml and development.yml files.
Update .gitignore to include production.yml and development.yml.
Replace the placeholder values with your secrets.
Now you can check your code into GitHub without compromising your secrets.
And anyone can clone your repo without any extra steps to create missing files (they'll just replace the placeholder values as you did).
Does that meet your goals?

- 1
- 1

- 10,952
- 6
- 63
- 82
-
Not really, because then what happens when I add something to those files that does needs to make its way to other repositories? – tybro0103 May 24 '11 at 20:12
-
If that won't happen often, just restore the placeholder values, remove the line from .gitignore, commit to GitHub with the changes, edit the files to restore your secrets and edit .gitignore to once again hide your secrets. There may be solutions that are more clever but this approach is simple. – Daniel Kehoe May 24 '11 at 20:59
Use environment variables.
In Ruby, they're accessible like so:
ENV['S3_SECRET']
Two reasons:
- The values will not make it into source control.
- "sensitive data" aka passwords tend to change on a per-environment basis anyways. e.g. you should be using different S3 credentials for development vs production.
Is this a best practice?
Yes: http://12factor.net/config
How do I use them locally?
foreman and dotenv are both easy. Or, edit your shell.
How do I use them in production?
Largely, it depends. But for Rails, dotenv is an easy win.
What about platform-as-a-service?
Any PaaS should give you a way to set them. Heroku for example: https://devcenter.heroku.com/articles/config-vars
Doesn't this make it more complicated to set up a new developer for the project?
Perhaps, but it's worth it. You can always check a .env.sample file into source control with some example data in it. Add a note about it to your project's readme.
Rails 4.1 has now a convention for it. You store this stuff in secrets.yml. So you don't end up with some global ENV calls scattered across Your app.
This yaml file is like database.yml erb parsed, so you are still able to use ENV calls here. In that case you can put it under version control, it would then serve just as a documentation which ENV vars has to be used. But you also can exlcude it from version control and store the actual secrets there. In that case you would put some secrets.yml.default or the like into the public repo for documentation purposes.
development:
s3_secret: 'foo'
production:
s3_secret: <%= ENV['S3_SECRET']%>
Than you can access this stuff under
Rails.application.secrets.s3_secret
Its discussed in detail at the beginning of this Episode

- 7,840
- 2
- 33
- 44
They're probably best put in initializers (config/initializers/api.yaml) though I think what you've got cooked up is fine. Add the actual keys to your .gitignore file and run git rm config/environments/production.yml
to remove that sensitive data from your repo. Fair warning, it will remove that file too so back it up first.
Then, just create a config/environments/production.yml.example file next to your actual file with the pertinent details but with the sensitive data left out. When you pull it out to production, just copy the file without the .example and substitute the appropriate data.

- 4,343
- 3
- 26
- 29
-
Yeah I hear you, but as said, I'm trying to find a solution that doesn't involve removing those files from the repository. – tybro0103 May 24 '11 at 16:03
-
Out of interest, why? Are you deploying to heroku or somewhere similar that doesn't easily let you copy files directly onto a server? – Max Williams May 24 '11 at 16:34
-
Yes. That, and I want it to be as simple as possible for others to get my code running. – tybro0103 May 24 '11 at 16:49
-
2the config files are conventional and wouldn't add any stumbling blocks to someone who needed to get your code running. Heroku has provided some docs on how to get them set up in their environment: http://devcenter.heroku.com/articles/config-vars – brycemcd May 26 '11 at 15:59