I am trying to store my stripe live key via Credentials as shown in the Securing Rails Application Guide: https://guides.rubyonrails.org/security.html#custom-credentials
I'm not sure what I'm doing wrong, the keys are written to the credentials file and in the test and development environments they work but when pushing to production I get errors that say my API Keys are not set. Here are what my credentials file and production config look like:
Credentials file ->
stripe_live: xxx.xxx.xxx
config/environments/production:
Stripe.api_key = Rails.application.credentials.stripe_live
I've also tried setting the keys with this command
rails credentials:edit --environment production and still no luck in the production environment.
How do I set rails credentials for the production environment? Do I need to set the RAILS_MASTER_KEY as an env variable in my production environemtn?
Set RAILS_MASTER_KEY to the string located within config/master.key . Rails automatically will use this value to decrypt your credentials file. A separate credentials file is optional, but if you do chose to use the separate credentials file you need to be sure that you use that key for the RAILS_MASTER_KEY env variable.
Related
I am encoding and decoding JSON web tokens using Rails secret_key_base, my secret_key_base is in the credentials.yml.enc file. In one of the test, I am using this function to decode JWT,locally the tests are running fine but on github action it is failing, I found out the the value of Rails.application.crendentials.secret_key_base is nil when running the test on github action. I fixed those tests by mocking like this
allow(Rails.application.credentials).to receive(:secret_key_base).
and_return("secret")
Is there a way I don't have to do this on github action for other credentials. Also since the master.key was not committed I hoped that I would see this error
ActiveSupport::MessageEncryptor::InvalidMessage
while reading from the credentials file but that also didn't happen.
This is a link to my project if that clears things up.
In Rails 6, you can create credentials.yml.enc file per environment.
In vscode:
EDITOR="code --wait" rails credentials:edit --environment production
EDITOR="code --wait" rails credentials:edit --environment test
it gives you production.key, production.yml.enc, test.key, test.yml.enc.
You can then commit test.key to github for testing or even better, set this key in RAILS_TEST_KEY env.
Though it gets a little bit tricky to maintain both env files. You can create credenetials.yml.example file with empty envs for reference
I think 'the cleanest/right way' to do this is to add master key(value from config/master.key) into github secrets.
Go to repository settings->secrets(left side menu)->new repository secret.
It makes sense to name it RAILS_MASTER_KEY.
And then in your workflow file add
env:
RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
And that's it, Rails will be smart enough to use that variable in credentials decryption.
No need to make additional credentials files. For me it's working with only one credentials.yml.enc
EDIT: Even better, if you can skip using credentials, add heroku config variable SECRET_KEY_BASE and in config/application.rb add
config.secret_key_base = ENV['SECRET_KEY_BASE']
and for production use Rails.configuration.secret_key_base,
for test/development Rails.application.secrest.secret_key_base that's set by rails
ex.
SECRET_KEY = Rails.env.production? ? Rails.configuration.secret_key_base : Rails.application.secrets.secret_key_base
This way you don't have to store master key on every machine that's running your app. ex. coworkers, github actions, staging, production.
I deployed my project on Heroku for production testing.
In development environment I can use Rails.application.credentials.dig(:secret_key_base) to get secret key base for JWT authentication:
# example
def decode(token)
key = Rails.application.credentials.dig(:secret_key_base)
JWT.decode(token, key)
end
But when I use that in Heroku it returns "nil". I tried entering it in the console via rails console and it returned "nil".
What do I do to make it available in production?
In order to decrypt the credentials file, you need to have RAILS_MASTER_KEY set in your environment.
You need to get the value from config/master.key and add it to the environment in Heroku's dashboard.
I want Heroku to not set SECRET_KEY_BASE so I can use the one from credentials, but despite me deleting it from the UI, verifying it doesn't exist by running heroku config, I still get it set as an environment variable on my dynos. And it's the same in all the dynos:
SECRET_KEY_BASE=d2753b472abb...
I also tried setting it to a blank string by running heroku config:set SECRET_KEY_BASE="" and Heroku insist on setting it up as I can see by running bash and then env within bash.
How can I prevent that from happening?
Unfortunately, the Heroku Ruby buildpack generates and sets SECRET_KEY_BASE via the shell if it doesn't exist in your Heroku config vars.
It currently doesn't seem possible to directly use the secret key set in credentials.yml. You could make credentials.yml and SECRET_KEY_BASE align though.
Source: https://github.com/heroku/heroku-buildpack-ruby/issues/1143
And here is a short extract from that issue:
If you set your own SECRET_KEY_BASE, we do nothing.
If you do not set a SECRET_KEY_BASE we generate and set one for you.
We recommend using our heroku config interface for storing secrets rather than using the encrypted file storage that ships with rails.
If you want to use encrypted file storage locally with rails you could copy our secret key base heroku run echo $SECRET_KEY_BASE or you can set your own
value manually locally and then again via heroku config.
I am trying to push a app on heroku, Its gets pushed but none of my assets gets uploaded on heroku.
Its works all good locally. So I check with rails s -e --production and It gives me error in secrets.yml
It says
Missing secret_token and secret_key_base for '--production' environment, set these values in config/secrets.yml
I am not sure what It is. Please help..
I believe that for a heroku app to run in production Rails expects the secret configuration to exist. Remove the line within your .gitignore that prevents secrets.yml from updating within version control and then make sure you use ENV variables for your secret tokens. If you don't have any secret tokens that aren't just tests then you shouldn't have to worry about it, but if you do you can use gems like figaro to configure your Environment variables that will keep your tokens off VCM.
Edit: If you look within your config directory you should see a secrets.yml that was generated with your app. Within the app you should see your secret_key_base variables within dev, test, and production. Within production though you should have:
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> <- This being your Environment variable
Just pushed my first app to Heroku using Git and straight away got an Interanl Server Error.
You must set config.secret_key_base in your app's config.
This is because on my .gitignore file the following file is included:
config/initializers/secret_token.rb
I am using a standard template for my .gitignore file found here: https://github.com/github/gitignore/blob/master/Rails.gitignore
My Question: Should I set this key via Heroku directly for added security and if so how?
OR
should I just remove this line from my .gitignore file?
In addition to setting the secret token as an ENV variable on Heroku, as outlined by Nick Ginanto, you also need the following to make this work.
Remove the config/initializers/secret_token.rb from .gitignore
Change the line in this file to:
MyApp::Application.config.secret_token = ENV['SECRET_TOKEN']
This will then pick up the secret token you have set with Heroku's config vars.
In order for the token to be picked up in your local environment you will need to add it. There are a number of options here but the one closest to Heroku is to use the foreman gem along with a .env file in your project root. The .env will need to have the secret_token
SECRET_TOKEN=NKUd7gisd7fueAISDfg....
You can use the rake secret command to generate tokens. Make sure your .env file is added to .gitignore.
With all this in place you will have different tokens for Heroku and local and your token will not be in your source control.
Set it as a Heroku environment variable, & provide a fallback for development
Remove the hardcoded secret, check the secret initialiser into version control, set an environment variable on Heroku, and provide a fallback for development and stage.
1. Remove the hardcoded secret, and optionally provide a fallback:
Edit your config/initializers/secure_random.rb to remove the hardcoded secret for production. Optionally include a fallback for non-production environments if you'd rather not change the way you start your server.
secret = Rails.env.production? ? ENV['SECRET_TOKEN'] : "top_secret_token"
YourApp::Application.config.secret_key_base = secret
2. Check config/initializers/secure_random.rb into git
Edit .gitignore and remove the line:
config/initializers/secret_token.rb
Now commit the file.
3. Set the secret key for Heroku
Run:
rake secret
to generate a random alphanumeric string. I like to make doubly sure by mixing the key up a little by hand as well, just in case a future weakness is discovered in the key generation algorithm, as happened for Debian not so long ago. Probably this is unnecessary.
Next run:
heroku config:set SECRET_TOKEN=paste_random_string_here
to set the secret as a Heroku environment variable. Deploy to Heroku and you're done.
Its best to use an ENV variable for this..
This way you can invalidate all the cookies quickly if needed, have a separate secret per environment and no need to deal with the file in a special way
heroku config:set SECRET_TOKEN=ertbs45tnsb3aw5bsxdrt54...
if you duplicated the app or have another app setup in heroku, each app will have its own secret_token.
on your localmachine just setup the same variable