Load environment variables in rails app without restarting server - ruby-on-rails

How can I make my rails app aware of the new environment variables after I have edited my /etc/environment file on my remote EC2 instance?
I frequently add new (minor) things in my secrets.yml but I don't want to restart my server for it, nor do I want to use an existing secret.

In linux every process inherits envvars from its parent process and the values are passed by value, not by reference. Also, they don't behave like closures. So, child process (your rails/ruby app process) will not get any new environment variables of its parent (the shell process where you started your rails/ruby app).
That's why it is not possible. However, you can use gems like dotenv and figaro to watch some file with your environment variables and reload them when they are changed.

You should be able to add a line to your config/spring.rb:
Spring.watch "config/secrets.yml"
This will allow Spring to detect when changes have occurred in your secrets.yml file.
However, if you're actually asking about how to make your app aware that you've changed environment variables in a file, then it's not possible. Config values may be detected in files, but environment variables are detected in the shell environment. You have to load those into your shell for them to take any effect, and this would require stopping your server, sourcing the new changes into the environment, and starting the server again.
Understanding the difference between a config value in a file (.yml, .xml, .ini, etc) versus an environment variable in a shell script is important, because how it's applied and made usable is entirely different.

Related

Rails settings environment variables on production - explanation

I am trying to secure my app properly by setting environment variables. I am doing it with figaro gem. I am not using heroku, just a vps I setup by myself.
Now on development all works good and makes sense. application.yml contains hardcoded database passwords which are not on database.yml anymore. application.yml is not pushed on repository and passwords are not shared. All good.
But I am having hard time making sense of it on production. If I set production section on database.yml with environment variables and then the application.yml is not on the server running on production, how can it possibly work? Or if I set them on another file that is then pushed later on repository, I just moved harcoded passwords from a file to another and are still accessible. Or are environment varibales supposed to be used only on test and development?
Could someone give me a clear explanation? I have been reading other questions and articles around but I can't make sense of it.
You want to set Unix environment variables in production. Check out this guide which states:
Variables in the config/application.yml file will override environment variables set in the Unix shell.
In other words, in development you would set these variables in application.yml which would then override any values set in Unix. In production, you would set them in the shell and that is where the values would come from. I suggest doing some more general reading regarding environment variables as they are a fundamental part of application development.

Rails config/local_env.yml vs .env vs bashrc environment variables

I was reading from this article that you can create a config/local_env.yml with environment variables and then use config/application.rb to read it to replace/take priority before the environment variables that you export in your .bashrc. What then is the .env used for then? Does it serve the same purpose as the config/local_env.yml?
All of these methods are used to feed environment variables to your rails application. So, from an app's point of view, it serves the same purpose whether you export it from .env or .bashrc or config/local_env.yml files.
The differences in these methods are really a matter of personal choice among the team members involved in maintaining the app's development and deployment environments. However, here are few things to consider while opting for either of these choices.
.bashrc - Use this if you manually configure deployment servers and really comfortable with linux/unix command line system administration. This configuration file is specific to bash shell (Bourne Again Shell). You need to configure different file if your server uses different shell (for example: .zshrc if it uses Z Shell)
.env - Use this if you want to keep your app centric environment variables within the app itself while maintaining different variations of environment variables for different runtime environments of your rails app. For example: .env.development and .env.test files with specific values of the environment variables for your development and test environments respectively. This gives you more control of your app's environment variables and do not have to rely on the platform (terminal shell) you want to deploy your app.
config/local_env.yml - This is similar to .env approach, which is provided out of the box by rails gem that allows you to configure environment variables for your app in yml format. This method also keeps your app's configuration within the app irrespective of the shell you are using to run your app.
In addition to the previous answer, another downside of using .bashrc is that it is specific to only one user, so if you're e.g. starting your app server as a systemd service then I believe it won't see your variables.
Meanwhile, .env's Github readme says that it is not the most recommended thing to use outside of the development environment, although it is OK for that purpose.
Another two options to consider are:
Rails secrets. The benefit of this approach is that you get to commit it to git since it's encrypted, so when working in a team you will all have access to the same file. The downside is that it is coupled to the RAILS_ENV variable, so you can't use it to set that e.g. to production on your production app (but you can manually pass it every time it's invoked). Another downside is that if you have a staging environment, then apparently Heroku discourages using RAILS_ENV=staging, which you sometimes really need, so if you need it then you can either do it anyway, or you'll need to set the differing variables via a different mechanism - for example my app has a variable which points to the URL of another part of my app, this URL needs to point to its staging variant on staging, and to its production variant on production, so it needs to differ between my production and staging environment.
Using an /etc/environment file - note that systemd services don't have access to it by default so you'd have to add the line EnvironmentFile=/etc/environment. Also if you're running a shell script from a non-login shell (which happens sometimes), they it won't load them either, but the solution is to just include in your script this: set -a; source /etc/environment; set +a. You should be careful not to commit this to git. If you're working in a team and you need to manage this file then it gets a little complicated since it's not committed to git, but maybe there's a way to have it encrypted. (systemd services note: you might optionally use LoadCredential= for sensitive variables such as private keys, so that other processes won't have access to them; if you do this then you can also commit to git /etc/environment which should now contain non-sensitive variables only).
In my opinion both of those are valid and it's fine to pick whatever is easier to do in your app.

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 configure Rails app for deployment to Tomcat

I have a Rails app that I package as a war file for deploying to Tomcat using Warbler. And it works, but the problem is I don't know how to configure the runtime properties like secret_key_base. I use the standard setup of using secrets.yml, with production variables coming from environment variables. But I don't know how to set the variables while still keeping them out of source control.
Ideally I'd still like to be able to deploy the war file automatically, by just dropping it into the webapps/ directory, but I suppose I could edit the server config file? Or is there a better way of handling this?
either do it the same way as you would in a Rails server ... let it read from ENV (of course you will need to make sure Tomcat has the environment variable set).
alternatively you can set it in a web.xml if you're packaging and than do a $servlet_context.getAttribute('foo') in secrets.yml ... or read it from a file location that only the server's tomcat username can access etc.
sky is the limit here - you basically need to decide what fits your deployments the best.

How do you manage secret keys and heroku with Ruby on Rails 4.1.0beta1?

With the release of the secrets.yml file, I removed my reliance on Figaro and moved all of my keys to secrets.yml and added that file to .gitignore.
But when I tried to push to Heroku, Heroku said they needed that file in my repo in order to deploy the website. which makes sense, but I don't want my keys in git if I can avoid it.
With Figaro, I would run a rake task to deploy the keys to heroku as env variables and keep application.yml in the .gitignore. Obviously, I can't do that any more. So how do I handle this?
Secrets isn't a full solution to the environment variables problem and it's not a direct replacement for something like Figaro. Think of Secrets as an extra interface you're now supposed to use between your app and the broader world of environment variables. That's why you're now supposed to call variables by using Rails.application.secrets.your_variable instead of ENV["your_variable"].
The secrets.yml file itself is that interface and it's not meant to contain actual secrets (it's not well named). You can see this because, even in the examples from the documentation, Secrets imports environment variables for any sensitive values (e.g. the SECRET_KEY_BASE value) and it's automatically checked into source control.
So rather than trying to hack Secrets into some sort of full-flow environment variable management solution, go with the flow:
Pull anything sensitive out of secrets.yml.
Check secrets.yml into source control like they default you to.
For all sensitive values, import them from normal environment variables into secrets ERB (e.g. some_var: <%= ENV["some_var"] %>)
Manage those ENV vars as you normally would, for instance using the Figaro gem.
Send the ENV vars up to Heroku as you normally would, for instance using the Figaro gem's rake task.
The point is, it doesn't matter how you manage your ENV vars -- whether it's manually, using Figaro, a .env file, whatever... secrets.yml is just an interface that translates these ENV vars into your Rails app.
Though it adds an extra step of abstraction and some additional work, there are advantages to using this interface approach.
Whether you believe it's conceptually a good idea or not to use Secrets, it'll save you a LOT of headache to just go with the flow on this one.
PS. If you do choose to hack it, be careful with the heroku_secrets gem. As of this writing, it runs as a before_initialize in the startup sequence so your ENV vars will NOT be available to any config files in your config/environments/ directory (which is where you commonly would put them for things like Amazon S3 keys).
An equivalent for secrets.yml of that Figaro task is provided by the heroku_secrets gem, from https://github.com/alexpeattie/heroku_secrets:
gem 'heroku_secrets', github: 'alexpeattie/heroku_secrets'
This lets you run
rake heroku:secrets RAILS_ENV=production
to make the contents of secrets.yml available to heroku as environment variables.
see this link for heroku settings
if u want to run on local use like this
KEY=xyz OTHER_KEY=123 rails s

Resources