Set environment variables with AWS Opsworks - ruby-on-rails

I'm using AWS Opsworks to host my Rails App (Ruby 2.0/Rails 3.2).
For assets compilation process, I am using AssetSync to upload the compiled assets automatically on S3. I used to store the credentials as environment variables.
Do you have any idea how can I do this with Chef/Opsworks?
Thanks.

I know this is an older post, but I'm posting this in case this helps someone else.
I found the easiest way actually was to use one of Chef's deploy hooks (http://docs.opscode.com/resource_deploy.html#deploy-phases).
Add a directory called 'deploy' at the Rails project root.
In it add a file called before_restart.rb, with the code:
Chef::Log.info("Running deploy/before_restart.rb")
# map the environment_variables node to ENV
node[:deploy].each do |application, deploy|
deploy[:environment_variables].each do |key, value|
Chef::Log.info("Setting ENV[#{key}] to #{value}")
ENV[key] = value
end
end
When you trigger the OpsWorks deploy, you should be able to see the ENV vars being set in the Rails App Server instance log.

I ended up using https://github.com/joeyAghion/opsworks_custom_env.
It works pretty well.

I used a slightly different approach, using OpsWorks hook to copy JSON to application.yml. you can read more about it here: http://zaman.io/how-to-import-aws-opsworks-json-into-rails-app/

Another option outside of environment variables is you can generate a file with the variables in it at deploy time.
For example, for a Rails app, the config/secrets.yml is a reasonable place to put these. I created a deploy/before_restart.rb deploy hook with the following content:
def create_secrets(secrets, release_path)
Chef::Log.info("Creating secrets")
file_path = ::File.join(release_path, 'config/secrets.yml')
::File.open(file_path, 'w') do |f|
f.write("production:\n")
secrets.each do |k,v|
f.write(" #{k}: #{v}\n")
end
end
end
node[:deploy].each do |application, deploy|
create_secrets(deploy[:secrets], release_path)
end
And then in your OpsWorks stack Custom JSON you can add your secrets:
"deploy": {
"super_cool_app": {
"secrets": {
"some_service_id": "foo",
"some_password": "bar"
}
}

You can create a deploy folder in the root of your application, create a file before_restart.rb inside it, then in your file run the precompile task
run "cd /srv/www/myapp/current && /usr/local/bin/bundle exec rake assets:precompile"
This file will run on every deployment
Source:
https://www.youtube.com/watch?v=nHu8fCp9GR4&list=WL&index=7

This can now be done directly from the AWS Console, on the application configuration, as per documentation : http://docs.aws.amazon.com/opsworks/latest/userguide/workingapps-creating.html#workingapps-creating-environment

I already answered here: AWS OpsWorks Environment variables not working
Is important to understand that from OpsWorks dashboard we can pass all declared environment variables to Chef, then we need to handle these variables with a Chef recipe to let them available to Rails environment.
Here you can find what you are looking for: https://medium.com/#diego_durante/opsworks-rails-and-environment-variables-30c6a143253c#.696grsgg9

Related

how to add environment variable in linux for rails app?

i need to set an environment variable for the rails app to use
SECRET_KEY_BASE=9941144eb255ff0ffecasdlkjqweqwelkjasdlkjasd
the config settings for production is as shown below
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
how can i set the environment variable using the linux command
export VARNAME="my value"
I tried to set the variable but looks like it needs to be for the right user. Sorry i am not an expert in linux.
I appreciate any help! Thanks!
export VARNAME="my value"
Well the above works for your current terminal session. After this command, all the subsequent commands can access this variable. Try running this:
echo $VARNAME
It will print the value my value in the console. If you want this behaviour to be persisted, you need to place the export command in your OS' config file (~/.bashrc in case of Ubuntu).
After editing this file, either restart your terminal, or run this:
source ~/.bashrc
This will reload the file in your current terminal session. Alternatively, you can try running your Rails server (or a rake command) as follows:
VARNAME="my value" rails s
For your local development I suggest you to use dotenv (https://github.com/bkeepers/dotenv) or figaro (https://github.com/laserlemon/figaro) and follow the README you find in the gem itself. This gives you much more flexibility than using directly environment variables because you set them only for this specific project and each project can have different of them.
You need to have either a .env file or a application.yml file where you will define your environment variables.
Remember to not commit or push this file to your repository because it contains sensible information!
When you will deploy to production you can use real environment variables or use admin panel control (on Heroku for example)

How to set up and use Rails environment variables in production server?

I need to set up an environment variable for my rails app. Both in my local machine and in the production server. I read some tutorials on the internet but NONE has given the complete instruction on how to set and use these variable in the actual production server. I use digital ocean and linux server to host my rails app.
I have spent days trying to figure this out, but still haven't found a clear and complete instruction from setting the variables on my local machine -> push it to git repo -> set and use the variables in production server. So, hope somebody can help me here, thanks!
UPDATE:
This is how I currently setup the environment variables in my rails app by using figoro gem:
You can set system-wide environment variables in the /etc/rc.local file (which is executed when the system boots). If your Rails app is the sole user of the Linux system, that is a good place to store credentials such as API keys because there is no risk of including this file in a public Git repository, as it is outside the application directory. The secrets will only be vulnerable if the attacker gains shell access to your Linux server.
Set the environment variables within /etc/rc.local (do not include the <> characters):
export SOME_LOGIN=<username>
export SOME_PASS=<password>
To see the value of an environment variable, use one of the following commands in the Linux shell:
printenv MY_VAR
echo $MY_VAR
To access those environment variables within Rails, use the following syntax:
Inside .rb files or at the rails console
ENV['MY_VAR']
Inside .yml files:
<%= ENV['MY_VAR'] %>
For anyone still having this issue, figaro now has an easy method in setting the production variables in heroku. Just run:
$ figaro heroku:set -e production
ryzalyusoff.
For Unix
You can use LINUX ENV in rails application.
# .env
GITHUB_SECRET_KEY=SECRET
TWITTER_ACCESS_KEY=XXXXXXXXXXXX
# in rails code
puts ENV["TWITTER_ACCESS_KEY"] # => SECRET
Create .env files for local machine and your production server. Export environment variables like this(on server with ssh):
export GITHUB_SECRET_KEY="XXXXXXXXXXXXXXXXXX"
Anyway, storing keys in config - bad idea. Just add .env.example, others keys configs add to .gitignore. Goodluck.
Example with Rails
For Windows
Syntax
SET variable
SET variable=string
SET /A "variable=expression"
SET "variable="
SET /P variable=[promptString]
SET "
Key
variable : A new or existing environment variable name e.g. _num
string : A text string to assign to the variable.
expression : Arithmetic expression
Windows CMD
I believe we should not push a secret file on git.
To ignore such file use gitignore file and push other code on the git.
On the server side just copy the secret file and create a symlink for that file.
You can find demo here http://www.elabs.se/blog/57-handle-secret-credentials-in-ruby-on-rails
You can set your environment variables in production in the same way, you do it for local system. However, there are couple of gems, which make it easier to track and push to production. Have a look at figaro. This will help you in setting up and deployment of env vars.
You can do this with figaro gem
or in rails 4 there is a file named secret.yml in config folder where you can define your environment variables this file is by default in .gitignore file.For production you need to manually copy that file to server for security reason so that your sensitive information is not available to any one
First create your variable like:
MY_ENV_VAR="this is my var"
And then make it global:
export MY_ENV_VAR
You can check if the process succeeded with:
printenv
Or:
echo MY_ENV_VAR

AWS OpsWorks Environment variables not working

I am running Ubuntu 14.04 LTS 64 bit Rails Application and I am unable to access my App environment variables.
In OpsWorks App panel, I set my environment variables, say:
MYKEY: 1234
Then I save and deploy my app again to make these visible.
In my Rails app, or the rails console I get nil:
$ bundle exec rails c production
>ENV["MYKEY"]
=> nil
I have tried restarting the server. I'm not sure what I am missing, I have been using environment variables in other services.
How can I trace where these should be set?
OpsWorks stores environmental variables in different places depending on what kind of app you're deploying. On Rails / Passenger they should be saved in the Apache config file #{your_app_name}.conf. (Source)
This means they aren't available in your normal shell environment.
I know the Node.js recipes stored everything in an /srv/www/#{app_name}/shared/app.env file... which is then sourced to pull in the environment to run the Node server. This implementation detail also meant you could write shell scripts that sourced that app.env file, then called some Node script or whatever.
Of course, Rails isn't Node. I have no idea if the environmental variables are also stored somewhere else or not: a quick look at the Rails recipes in the OpsWorks cookbooks didn't find anything obvious, but maybe I missed something.
Depending on the amount of modifications you have going on in your OpsWorks cookbook, you could create a deploy recipe that does something like this:
application_environment_file do
user deploy[:user]
group deploy[:group]
path ::File.join(deploy[:deploy_to], "shared")
environment_variables deploy[:environment_variables]
end
(maybe adjusting the path)
Then to run your console, when you're SSHed into the server, do something like
sudo source /srv/www/my_app_name/shared/app.env; bundle exec rails console -e production or whatever.
AWS OpsWorks console lets you declare environment variables but to let them be available for our Rails app we need to use a Chef cookbook recipe plus some precautions.
In a nutshell we use the config/secrets.yml file combined with config/application.yml file, Figaro gem and a Chef cookbook recipe.
The chef cookbook recipe read the variables defined in OpsWorks console and let them available to Rails app writing the config/application.yml file.
I have published a detailed guide to explain how exactly do it. Link here.
These are the core points that I covered:
Use config/secrets.yml file (added from Rails 4.1)
Use Figaro gem to load variables in the environment
Declare environment variables inside AWS OpsWorks Console
Use a custom Chef recipe to create a config/application.yml file that Figaro will use to let variables available
I (with some help from Bruno at the AWS PopUp Loft in NYC) added some custom Chef code inside the after_restart.rb deploy hook, simply add the folder "deploy" to your apps root directory and inside add "after_restart.eb." In it ....
Chef::Log.info("Running deploy/after_restart.rb")
contents = []
node[:deploy].each do |application, deploy|
deploy[:environment_variables].each do |key, value|
contents << "export #{key}=\"'#{value}'\""
end
end
Chef::Log.info("Adding the environment variables to /etc/profile.d/startup_env_config.sh")
bash "create_startup_env_config.sh" do
user "root"
cwd "/etc/profile.d"
code <<-EOH
echo \''#{contents.join(" ")}\'' > startup_env_config.sh
source startup_env_config.sh
cd #{release_path}
EOH
end
And that's it. If you update the environment variables inside the OpsWorks panel remember to restart your instances.

Where to put environment variables on the server?

I have a Rails app on a production server and an .rb file where I do this:
Rails.configuration.my_sect = if Rails.env.development? || Rails.env.test?
{
secret_key: 'some_secrete',
public_key: 'some_public'
}
else
{
secret_key: ENV['key1'],
public_key: ENV['key2']
}
end
The application is on a Linux server. What's the best place to put the values of those secret_key and public_key on the server so ENV['key1'] and ENV['key2'] can always be accessible?
I don't want to use any gem or Capistrano.
I would put them in the server script, because, for example, shell configuration files like ~/.bashrc are not loaded in cron scripts or other scenarios.
The "server script" could be as simple as key1=foo key2=baz rails s.
Add /config/en_vars.rb to .gitignore
Create a file config/en_vars.rb and put your variables there:
ENV['key1']='foo'
ENV['key2']='bar'
Then in config/environment.rb add the lines below the require line:
en_vars = File.join(Rails.root, 'config/en_vars.rb')
load(en_vars) if File.exists?(en_vars)
Even if you say you don't want to use any gem, I recommend you to use dotenv; even if it's not suggested to use it on a production environment.
Otherwise, the simplest plain solution is:
create a per-project environment variables file (let's say "$PROJECT_DIR/.env")
Add it to .gitignore
execute it before the application server starting, with something like
source "$PROJECT_DIR/.env" && rails server
But that's what dotenv is created for, so why reinvent the wheel?

How to solve error "Missing `secret_key_base` for 'production' environment" (Rails 4.1)

I created a Rails application, using Rails 4.1, from scratch and I am facing a strange problem that I am not able to solve.
Every time I try to deploy my application on Heroku I get an error 500:
Missing `secret_key_base` for 'production' environment, set this value in `config/secrets.yml`
The secret.yml file contains the following configuration:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
On Heroku I configured the "SECRET_KEY_BASE" environment variable with the result of the rake secret command. If I launch heroku config, I can see the variable with the correct name and value.
Why am I still getting this error?
I had the same problem and solved it by creating an environment variable to be loaded every time I logged in to the production server, and made a mini-guide of the steps to configure it:
I was using Rails 4.1 with Unicorn v4.8.2 and when I tried to deploy my application it didn't start properly and in the unicorn.log file I found this error message:
app error: Missing `secret_key_base` for 'production' environment, set this value in `config/secrets.yml` (RuntimeError)
After some research I found out that Rails 4.1 changed the way to manage the secret_key, so if you read the secrets.yml file located at exampleRailsProject/config/secrets.yml you'll find something like this:
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
This means that Rails recommends you to use an environment variable for the secret_key_base in your production server. In order to solve this error you should follow these steps to create an environment variable for Linux (in my case Ubuntu) in your production server:
In the terminal of your production server execute:
$ RAILS_ENV=production rake secret
This returns a large string with letters and numbers. Copy that, which we will refer to that code as GENERATED_CODE.
Login to your server
If you login as the root user, find this file and edit it:
$ vi /etc/profile
Go to the bottom of the file using Shift+G (capital "G") in vi.
Write your environment variable with the GENERATED_CODE, pressing i to insert in vi. Be sure to be in a new line at the end of the file:
$ export SECRET_KEY_BASE=GENERATED_CODE
Save the changes and close the file using Esc and then ":x" and Enter for save and exit in vi.
But if you login as normal user, let's call it "example_user" for this gist, you will need to find one of these other files:
$ vi ~/.bash_profile
$ vi ~/.bash_login
$ vi ~/.profile
These files are in order of importance, which means that if you have the first file, then you wouldn't need to edit the others. If you found these two files in your directory ~/.bash_profile and ~/.profile you only will have to write in the first one ~/.bash_profile, because Linux will read only this one and the other will be ignored.
Then we go to the bottom of the file using Shift+G again and write the environment variable with our GENERATED_CODE using i again, and be sure add a new line at the end of the file:
$ export SECRET_KEY_BASE=GENERATED_CODE
Having written the code, save the changes and close the file using Esc again and ":x" and Enter to save and exit.
You can verify that our environment variable is properly set in Linux with this command:
$ printenv | grep SECRET_KEY_BASE
or with:
$ echo $SECRET_KEY_BASE
When you execute this command, if everything went ok, it will show you the GENERATED_CODE from before. Finally with all the configuration done you should be able to deploy without problems your Rails application with Unicorn or some other tool.
When you close your shell and login again to the production server you will have this environment variable set and ready to use it.
And that's it! I hope this mini-guide helps you solve this error.
Disclaimer: I'm not a Linux or Rails guru, so if you find something wrong or any error I will be glad to fix it.
I'm going to assume that you do not have your secrets.yml checked into source control (ie. it's in the .gitignore file). Even if this isn't your situation, it's what many other people viewing this question have done because they have their code exposed on Github and don't want their secret key floating around.
If it's not in source control, Heroku doesn't know about it. So Rails is looking for Rails.application.secrets.secret_key_base and it hasn't been set because Rails sets it by checking the secrets.yml file which doesn't exist. The simple workaround is to go into your config/environments/production.rb file and add the following line:
Rails.application.configure do
...
config.secret_key_base = ENV["SECRET_KEY_BASE"]
...
end
This tells your application to set the secret key using the environment variable instead of looking for it in secrets.yml. It would have saved me a lot of time to know this up front.
Add config/secrets.yml to version control and deploy again. You might need to remove a line from .gitignore so that you can commit the file.
I had this exact same issue and it just turned out that the boilerplate .gitignore Github created for my Rails application included config/secrets.yml.
This worked for me.
SSH into your production server and cd into your current directory, run bundle exec rake secret or rake secret, you will get a long string as an output, copy that string.
Now run sudo nano /etc/environment.
Paste at the bottom of the file
export SECRET_KEY_BASE=rake secret
ruby -e 'p ENV["SECRET_KEY_BASE"]'
Where rake secret is the string you just copied, paste that copied string in place of rake secret.
Restart the server and test by running echo $SECRET_KEY_BASE.
While you can use initializers like the other answers, the conventional Rails 4.1+ way is to use the config/secrets.yml. The reason for the Rails team to introduce this is beyond the scope of this answer but the TL;DR is that secret_token.rb conflates configuration and code as well as being a security risk since the token is checked into source control history and the only system that needs to know the production secret token is the production infrastructure.
You should add this file to .gitignore much like you wouldn't add config/database.yml to source control either.
Referencing Heroku's own code for setting up config/database.yml from DATABASE_URL in their Buildpack for Ruby, I ended up forking their repo and modified it to create config/secrets.yml from SECRETS_KEY_BASE environment variable.
Since this feature was introduced in Rails 4.1, I felt it was appropriate to edit ./lib/language_pack/rails41.rb and add this functionality.
The following is the snippet from the modified buildpack I created at my company:
class LanguagePack::Rails41 < LanguagePack::Rails4
# ...
def compile
instrument "rails41.compile" do
super
allow_git do
create_secrets_yml
end
end
end
# ...
# writes ERB based secrets.yml for Rails 4.1+
def create_secrets_yml
instrument 'ruby.create_secrets_yml' do
log("create_secrets_yml") do
return unless File.directory?("config")
topic("Writing config/secrets.yml to read from SECRET_KEY_BASE")
File.open("config/secrets.yml", "w") do |file|
file.puts <<-SECRETS_YML
<%
raise "No RACK_ENV or RAILS_ENV found" unless ENV["RAILS_ENV"] || ENV["RACK_ENV"]
%>
<%= ENV["RAILS_ENV"] || ENV["RACK_ENV"] %>:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
SECRETS_YML
end
end
end
end
# ...
end
You can of course extend this code to add other secrets (e.g. third party API keys, etc.) to be read off of your environment variable:
...
<%= ENV["RAILS_ENV"] || ENV["RACK_ENV"] %>:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
third_party_api_key: <%= ENV["THIRD_PARTY_API"] %>
This way, you can access this secret in a very standard way:
Rails.application.secrets.third_party_api_key
Before redeploying your app, be sure to set your environment variable first:
Then add your modified buildpack (or you're more than welcome to link to mine) to your Heroku app (see Heroku's documentation) and redeploy your app.
The buildpack will automatically create your config/secrets.yml from your environment variable as part of the dyno build process every time you git push to Heroku.
EDIT: Heroku's own documentation suggests creating config/secrets.yml to read from the environment variable but this implies you should check this file into source control. In my case, this doesn't work well since I have hardcoded secrets for development and testing environments that I'd rather not check in.
You can export the secret keys to as environment variables on the ~/.bashrc or ~/.bash_profile of your server:
export SECRET_KEY_BASE = "YOUR_SECRET_KEY"
And then, you can source your .bashrc or .bash_profile:
source ~/.bashrc
source ~/.bash_profile
Never commit your secrets.yml
For rails6, I was facing the same problem as I was missing the following files. Once I added them the issue was resolved:
1. config/master.key
2. config/credentials.yml.enc
Make sure you have these files!
What I did :
On my production server, I create a config file (confthin.yml) for Thin (I'm using it) and add the following information :
environment: production
user: www-data
group: www-data
SECRET_KEY_BASE: mysecretkeyproduction
I then launch the app with
thin start -C /whereeveristhefieonprod/configthin.yml
Work like a charm and then no need to have the secret key on version control
Hope it could help, but I'm sure the same thing could be done with Unicorn and others.
I have a patch that I've used in a Rails 4.1 app to let me continue using the legacy key generator (and hence backwards session compatibility with Rails 3), by allowing the secret_key_base to be blank.
Rails::Application.class_eval do
# the key_generator will then use ActiveSupport::LegacyKeyGenerator.new(config.secret_token)
fail "I'm sorry, Dave, there's no :validate_secret_key_config!" unless instance_method(:validate_secret_key_config!)
def validate_secret_key_config! #:nodoc:
config.secret_token = secrets.secret_token
if config.secret_token.blank?
raise "Missing `secret_token` for '#{Rails.env}' environment, set this value in `config/secrets.yml`"
end
end
end
I've since reformatted the patch are submitted it to Rails as a Pull Request
I've created config/initializers/secret_key.rb file and I wrote only following line of code:
Rails.application.config.secret_key_base = ENV["SECRET_KEY_BASE"]
But I think that solution posted by #Erik Trautman is more elegant ;)
Edit:
Oh, and finally I found this advice on Heroku: https://devcenter.heroku.com/changelog-items/426 :)
Enjoy!
this is works good https://gist.github.com/pablosalgadom/4d75f30517edc6230a67
for root user should edit
$ /etc/profile
but if you non root should put the generate code in the following
$ ~/.bash_profile
$ ~/.bash_login
$ ~/.profile
On Nginx/Passenger/Ruby (2.4)/Rails (5.1.1) nothing else worked except:
passenger_env_var in /etc/nginx/sites-available/default in the server block.
Source: https://www.phusionpassenger.com/library/config/nginx/reference/#passenger_env_var
Demi Magus answer worked for me until Rails 5.
On Apache2/Passenger/Ruby (2.4)/Rails (5.1.6), I had to put
export SECRET_KEY_BASE=GENERATED_CODE
from Demi Magus answer in /etc/apache2/envvars, cause /etc/profile seems to be ignored.
Source: https://www.phusionpassenger.com/library/indepth/environment_variables.html#apache
In my case, the problem was that config/master.key was not in version control, and I had created the project on a different computer.
The default .gitignore that Rails creates excludes this file. Since it's impossible to deploy without having this file, it needs to be in version control, in order to be able to deploy from any team member's computer.
Solution: remove the config/master.key line from .gitignore, commit the file from the computer where the project was created, and now you can git pull on the other computer and deploy from it.
People are saying not to commit some of these files to version control, without offering an alternative solution. As long as you're not working on an open source project, I see no reason not to commit everything that's required to run the project, including credentials.
I had the same problem after I used the .gitignore file from https://github.com/github/gitignore/blob/master/Rails.gitignore
Everything worked out fine after I commented the following lines in the .gitignore file.
config/initializers/secret_token.rb
config/secrets.yml

Resources