How to get global variables from database config file in rails application? - ruby-on-rails

I want to get secret informations from other place beside rails application and the host. I made a global variable file under config/initializers to get the keys. Then set them in the database connection file. Like this:
config/initializers/get_secrets.rb
##username = 'A'
##password = 'B'
config/database.yml
development:
adapter: mysql2
encoding: utf8
database: my_db_name
username: <%= ##username %>
password: <%= ##password %>
host: 127.0.0.1
port: 3306
When ran rails console, got:
./config/initializers/get_secrets.rb:1: warning: class variable access from toplevel
(erb):10: warning: class variable access from toplevel
>
It seems not a good usage in this case. Then is there a right way?

In Rails 5.2+, we have a master.key file and a credentials YAML file. The master.key file encrypts your credentials (so never show anyone this key except your server).
You can activate this by doing:
EDITOR=vim rails credentials:edit
The file:
aws:
key: 123
google_key: 456
secret_key_base: f230ffddd1d1f151j3bchjas9a292j221...
If you want to use a credential, it looks like this:
Rails.application.credentials.google_key
or for nested resources like the AWS one:
Rails.application.credentials.aws[:key]
But if you're on Rails 5.1 or less, you don't have this ability. So, you do it in a different way:
Environment variables. Your program environment can always export an ENV and retrieve it. I always do this for simple nuisances like test email passwords:
export GMAIL_PASSWORD="1234" and its usage, ENV['GMAIL_PASSWORD']
Secrets.yml. This is a file that basically predates master.key + credentials by functioning as an in between credential handler for your environments. It's janky and often erroneously committed to repos by accident, but we do what we can:
development:
secret_key_base: 1112sdasae1d13d1tfd1d3...
GMAIL_PASSWORD: '1234'
test:
secret_key_base: _your_secret_ as above
production:
secret_key_base: <%= secure_token %>
And it is accessed like Rails.application.secrets.GMAIL_PASSWORD
If you cannot access your variables, it may be because the secrets.yml file is not being loading in or you are in the wrong environment. Notice those vars are nested in particular environments.

Related

How to set rails environment variables in database.yml file?

On my local machine, I want to set environment variables for all of the sensitive information in the database.yml file. My file looks like this:
default: &default
adapter: mysql2
encoding: utf8
pool: 5
username: <%= ENV['DATABASE_USERNAME'] %>
password: <%= ENV['DATABASE_PASSWORD'] %>
socket: <%= ENV['SOCKET'] %>
development:
<<: *default
database: <%= ENV['DEVELOPMENT_DATABASE'] %>
test:
<<: *default
database: #JetStreamIQ-2_0_test
production:
<<: *default
database: <%= ENV['PRODUCTION_DATABASE'] %>
username: <%= ENV['DATABASE_USERNAME'] %>
password: <%= ENV['DATABASE_PASSWORD'] %>
I thought that I could just set these environment variables in my .bashrc file, but that doesn't seem to be working. My .bashrc file looks like this:
export DATABASE_USERNAME="root"
export DATABASE_PASSWORD="*****"
export SOCKET="/var/run/mysqld/mysqld.sock"
export DEVELOPMENT_DATABASE="shoppe_development"
export PRODUCTION_DATABASE="#"
When I run my server with
rails s
I get an error that says:
Access denied for user 'root'#'localhost' (using password: YES)
I understand that there is a problem with the database username and password because of the way I've configured my database.yml file, but I'm just not sure what it is.
Is there something big I'm missing here? Any help would be much appreciated.
Thanks!
I'd like to offer a couple of tips here.
You can run database.yml through erb to test what you're getting. For example, erb config/database.yml. This will help you determine what the problem may be.
You can find out every environment variable set in your shell with the set command. This will allow you to confirm that the environment variables you're expecting are being set (in .bashrc).
Hope this is helpful.
It turns out that after I edited my bashrc file, I needed to exit out of that terminal session and open another terminal for the changes to be finalized :/ After I did that my application started perfectly.
If you dont want to restart your terminal, you just need to execute your .bashrc file:
source /path/to/.bashrc
in the same terminal as your rails server.
Is it a typo or are you really setting JETSTREAMIQ_DATABASE_PASSWORD but then using DATABASE_PASSWORD in your database.yml? Because that would do it.
Can you connect to mysql using the actual values directly using the mysql command line app?
you may need to put your environment variables at the top of .bashrc file. cause it has some return executed into the file. so it return before actually executing your export command
something like this:
nano ~/.bashrc
export DATABASE_VAR="my_own_var"
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
Simply set environment variable
DATABASE_URL=postgres://user:pass#localhost/dbname
It will override database.yml settings
Offcourse it supports more parameters, like
DATABASE_URL=mysql2://user:passwd#host:port/dbname?encoding=utf8mb4&collation=utf8mb4_unicode_ci
You can also source your ~/.bashrc file using the following command on your terminal:
exec $SHELL
Have you tried to access your local database with that data from the console?
Maybe you have to grant access for localhost
GRANT ALL ON shoppe_development.* TO 'root'#'localhost';
Besides that, I recommend you the gem dotenv to handle your env vars for development environment

fe_sendauth: no password supplied encountered with Amazon RDS

I know many others have encountered this problem, but I'm limited in the Postgres configuration I can do since I am using Amazon RDS...
Here is the relevant section of my database.yml
default: &default
host: <%= ENV["POSTGRES_HOST"] %>
username: <%= ENV["POSTGRES_USER"] %>
password: <%= ENV["POSTGRES_PASSWORD"] %>
adapter: postgis
encoding: unicode
database: <%= ENV["POSTGRES_DB"] %>
port: 5432
pool: 5
When I hard code the host, leave everything else as is, and load localhost:3000, I get fe_sendauth: no password supplied error. However, when I hard code all of the values instead of using an ENV variable, everything loads as normal with no errors.
I'm using Amazon RDS, so I have no ability to edit pg_hba.conf, but is this just a simpler problem of RoR not having access to ENV variables?
Yup, it's pretty clear that your ENV values are returning nil. Keep in mind that environment variables are loaded a bit differently on your production server than localhost. In most deployment configurations you can't simply set a Unix environment variable and have it be detectable in ENV.
I can't really tell much about how your ENV variables are being set from your provided code, but you should consider using Figaro (https://github.com/laserlemon/figaro) or dotenv (https://github.com/bkeepers/dotenv) to manage your ENV variables for you. However, it will require the extra step of having to manage an environment variable file outside of source control.

Rails: Paypal configuration file and figaro environment variables

I´m using the gem 'paypal-sdk-adaptivepayments' to integrate Paypal in my Rails app. The configuration file is paypal.yml:
development:
# Credentials for Classic APIs
username: ENV["PAYPAL_CLASSIC_USERNAME_DEV"]
password: ENV["PAYPAL_CLASSIC_PASSWORD_DEV"]
signature: ENV["PAYPAL_CLASSIC_SIGNATURE_DEV"]
app_id: ENV["PAYPAL_CLASSIC_APP_ID_DEV"]
http_timeout: 30
# Mode can be 'live' or 'sandbox'
mode: sandbox
test:
<<: *default
production:
<<: *default
#mode: live
Cause this information is secret I want to use another gem called 'Figaro' that externalize this variables. I used this for another configuration files in my app but it doesn´t works with 'paypal.yml'. I know that doesn´t works because when I put the real information in the paypal.yml file it works.
development:
# Credentials for Classic APIs
username: *******#yahoo.com
password: *******
signature: ******
app_id: ******
http_timeout: 30
# Mode can be 'live' or 'sandbox'
mode: sandbox
test:
<<: *default
production:
<<: *default
#mode: live
Has anyone used Figaro with this file? Is there any other option to "secretize" this information in Rails?
Thanks in advance!
Okay, what you should do is replace your yaml config file with a config.rb file:
#config/initializers/paypal.rb
PayPal::SDK.configure(
username: ENV["PAYPAL_CLASSIC_USERNAME_DEV"],
password: ENV["PAYPAL_CLASSIC_PASSWORD_DEV"],
signature: ENV["PAYPAL_CLASSIC_SIGNATURE_DEV"],
app_id: ENV["PAYPAL_CLASSIC_APP_ID_DEV"],
http_timeout: 30
)
Then define these variables in a yaml file such as application.yml:
#config/application.yml
PAYPAL_CLASSIC_USERNAME_DEV: yourpaypalusername
PAYPAL_CLASSIC_PASSWORD_DEV: yourpaypalpassword
PAYPAL_CLASSIC_SIGNATURE_DEV: yourpaypaysignature
PAYPAL_CLASSIC_APP_ID_DEV: yourappid
Lastly assuming you are using git for your version control, go into your gitignore and tell it to ignore the yaml file with your secret info:
#.git_ignore
/config/application.yml
This will properly keep your environment variables out of your code base when you push it to github or other git repo.
Edit: To use different environment keys you merely specify the keys for different environments in your yaml file:
#application.yml
production:
PAYPAL_CLASSIC_USERNAME_DEV: yourpaypalusername
PAYPAL_CLASSIC_PASSWORD_DEV: yourpaypalpassword
PAYPAL_CLASSIC_SIGNATURE_DEV: yourpaypaysignature
PAYPAL_CLASSIC_APP_ID_DEV: yourappid
That being said, I highly suspect what you are doing is a violation of 12factor best practices. This yaml file is not a part of your application - when you push your code up to a server like Heroku, this file is not supposed to go with it. The yaml file with your keys should only ever exist on your local machine. It should not exist in Github, nor on your production server. To read more about this, check out this link: http://12factor.net/config
So how do you tell a server like Heroku what these config variables are? This will vary based on what service provider you use, but is typically done via the command line tools or through an admin management page. e.g., for Heroku you would run:
heroku config:set PAYPAL_CLASSIC_USERNAME_DEV=putyourusernamehere

secrets.yml when cloning, how to amke a new secrets.yml file

Using Rails 4.1.1, I created a project. Got it up and runnning, and now I want to share it with my research dev team. Of course, the .gitignore hides the secrets.yml file from source control, but their versions won't run without their own version of a secrets.yml file, getting the following error:
Unexpected error while processing request: Missing secret_key_base for 'development' environment, set this value in `config/secrets.yml
Do we need to share the secret tokens? (thus just copy and paste it over to their local machines)
Should they be separate random keys? (What is the process when cloning a repo?)
Since you should avoid storing private keys in source control, I would recommend that you instead add a config/secrets.sample.yml to your repository containing a template for the secrets like:
development:
secret_key_base:
some_random_key:
test:
secret_key_base:
some_random_key:
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
secret_key_base: <%= ENV["SOME_RANDOM_KEY"] %>
Then you would just need to give them the values to fill in a secure way (voice, piece of paper, etc.)
There is an interesting blog post that you can read here about how to deploy your app's ENV variables.
You don't need to share the secrets.yml keys and you can actually generate new secret keys using the following rake command:
rake secret
That should output a 128-digit pseudorandom hex value similar to this:
b00dbff430b2c5596d10b3434ecd8a25515db481dccf818869a21d0c276ad159f00680aac38957ad57a73c9254754b32c42ef4fe2f76ee48d6e4ad8d4dc6a203
Have each research dev team member run that command for each secret_key_base in the secrets.yml file.
If this is for a production environment, you'd want to set the value you get from rake secret into an environment variable.

How to dynamically generate secret tokens in Rails 4.1 with secrets.yml?

New to rails. Followed Hartl's tutorial where he uses this code to dynamically generate secret token for config/initializers/secret_token.rb
require 'securerandom'
def secure_token
token_file = Rails.root.join('.secret')
if File.exist?(token_file)
# Use the existing token.
File.read(token_file).chomp
else
# Generate a new token and store it in token_file.
token = SecureRandom.hex(64)
File.write(token_file, token)
token
end
end
SampleApp::Application.config.secret_key_base = secure_token
I'm trying to follow the new Rails 4.1 way by using secrets.yml, and delete the secret_token.rb:
development:
secret_key_base: 79c1389c2fadc5a5a1918a5104ab34eb700c
test:
secret_key_base: fdb4edcde14173d62963705ca4d7876b5307790924
production:
secret_key_base: 85172605030a8225c083d886d066da2cb4aac1f0
But I think you cannot run ruby script like the one in secret_token.rb in a yml file. How would you have rails dynamically generate the secret tokens in secret. How should this be done? What is best practice?
Given a function secret_token whose only job is to generate a new token string each time one's application accesses the secrets.yml file, cookies and most likely other session-like behavior will not work correctly as the secret token changes each call to the function.
The preferred & secure way is to use any old secret key in the secrets.yml file for development and test environments (you can generate a secret string by issuing rake secret on the command line), then use an environment variable that your production server knows, so the secrets.yml file looks like:
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
For example, on Heroku, use heroku config:set SECRET_KEY_BASE="insert key here" to set the environment variable and there you have it. Don't be afraid to check the secrets.yml file into scm...as long as you haven't saved your production key to the file (and are instead using the environment variable method I just described), checking the file into scm poses no threat.
You can actually run ERB code in YML files. Something like:
development:
secret_key_base: <%= secret_token %>
should work (if whatever process reads the YML file can access the secure_token method).

Resources