Rails new credentials generate greater risk in case of master.key corruption? - ruby-on-rails

Until now I was handling my app secrets the usual way :
In development: my secrets are stored unencrypted in my secrets.yml file. The secrets.yml file is not commited to Github and
stays on my computer.
As per AWS reccomendations I have roles that allow me to have development specific keys. This allows to restrain my development keys to certain functions that have a different scope than production keys.
In production: My keys are stored on Heroku and called like ENV["AWS_SES_KEY"] inconfig/environments/production.rb.
I quite liked it because in case my computer is stolen, the development keys which then become corrupt can be erased at AWS without having to touch the production keys. And because the development keys can be limited to a certain scope of actions at AWS, it prevents any dangerous alterations (full bucket erasing ...)
Now we have credentials, if I am not mistaken, all keys (development and production) are inside the same encrypted file. The master key is the only environment key that is now seeded to Heroku. Though I still need this key locally to access the credentials. Then if my computer is stolen both development and production keys are corrupt and can generate a higher risk for my production app.
Is there something I am missing on the new credentials feature ? any way to avoid the above issue ?
What would be great is still using secrets.yml for dev keys and credentials.yml.enc for production keys, is it how it is intended ?

As the release notes for Rails 5.2.0 states, the future intent is to replace secrets.yml and secrets.yml.enc with credentials.yml.enc:
This will eventually replace Rails.application.secrets and the encrypted secrets introduced in Rails 5.1.
There's a very clear sense that credentials.yml.enc is meant to contain production credentials only because the Rails recommendation is to not have environment specific keys in it; i.e.,
# don't do this
development:
# ...
production:
# ...
As for the config/master.key "corruption" risk, I'm not sure how to answer that. The master key is only required when running in production mode. You can also store the master key in the RAILS_MASTER_KEY environment variable. In development, you'd only need the master key if you wanted to edit credentials.yml.enc.

Related

Hiding Rails Credentials

I have a Rails 6 application. In my credentials file, I have both development and production API keys. I want to be able to hide the production API keys since some developers don't need access to the credentials.
In previous versions of Rails, I could grab an environment variable using <%= ENV["MY_VAR"] %> and place that in the secrets.yml file. However, Rails credentials doesn't support executing Ruby in the yml file which makes sense because it's encrypted but this now puts limitations on the ability to prevent other developers from accessing production API keys. Is there anyway around this without hardcoding ENV["MY_VAR"] throughout the Rails app? Here is ultimately what I want to accomplish within my credentials file.
development:
aws: 11111111
production:
aws: <%= ENV["AWS_SECRET"] %>
You can generate credential file per environment
rails credentials:edit --environment development
rails credentials:edit --environment production
This will create the credentials file
config/credentials/development.yml.enc and config/credentials/production.yml.enc, and
encryption keys config/credentials/development.key, config/credentials/production.key
So you can share development key with other developers without need to share production.key
Checkout this commit for more details: https://github.com/rails/rails/pull/33521

How to manage credentials with a multi-stages, single-environment Rails app?

TL; DR
How to use production.yml.enc and staging.yml.enc credential files in two production- and staging- Rails apps, while the app has only the regular development, test and production environments?
I'm using Heroku and refer to it in this question. Yet this is not specific to this vendor.
In detail
An application is often deployed multiple times. An instance serves as the production, while another is the staging app, expected to be put in production. Rails facilitates this pattern, since creating new environments is easy.
However, Heroku suggests not to do this, with good reasons. For example, one can be tempted to put some if Rails.env.production? here and there, paving the way for some "but it works in staging!?" on Friday evening. It is better to have a single production environment, with different sets of parameters to actually differentiate the stages (eg. a different AWS S3 bucket name, a different API key, etc.). To achieve this, Heroku's advice is to rely on environment variables.
Since Rails 5.2 and later in Rails 6, credentials are conveniently handled via encrypted Yaml files in config/credentials. This is typically where one would like to store all these variables that change from an environment to another, instead of using messy environment variables. This mechanism can be used in Heroku thanks to a single RAILS_MASTER_KEY environment variable that contains the key used to decrypt the credentials file.
But these pieces do not fit well. How can we have a single production environment, whereas credentials files are per-environment?
This can be implemented with a staging credentials file and key, and a switch in application.rb based on an environment variable:
Create and populate a staging credentials file and key with EDITOR=vi rails credentials:edit --environment staging.
In application.rb, add:
# Introduce the environment variable RAILS_CREDENTIALS_ENVIRONMENT to specify a custom
# environment name of which to use the credentials file. Specifically aimed to use in staging,
# where the environment is set to "production", but we need to use the "staging" environment variables.
# This environment variable is also used to select the corresponding key file or -if that does not exist-
# the corresponding environment variable.
if ENV['RAILS_CREDENTIALS_ENVIRONMENT'].present?
new_filename_no_ext = Rails.root.join 'config', 'credentials', ENV['RAILS_CREDENTIALS_ENVIRONMENT']
config.credentials.content_path = "#{new_filename_no_ext}.yml.enc"
if File.exist? "#{new_filename_no_ext}.key"
config.credentials.key_path = "#{new_filename_no_ext}.key"
end
end
Set an environment variable RAILS_CREDENTIALS_ENVIRONMENT to production or staging, depending on the case. For example, Heroku does this with:
heroku config:set -a theapp-staging RAILS_CREDENTIALS_ENVIRONMENT=staging
If on staging or produciton you want to store your key in an environment variable instead of a key file, then simply assign the key to the RAILS_MASTER_KEY environment variable. As documented, this takes precendence over keys stored in files. Note that on your development machine you wouldn't want to have a RAILS_MASTER_KEY set, otherwise the credential files for all environments still get the same key and are thus accessible by everyone that needs to have access to (e.g.) only the development credentials.
Have several files one by each environment in your source code repository o local server disk, works but you will have several files with hardcoded values.
But, if you expect several teams with several requirements on your single app, you will need several development and test environments in order to keep an independent teams which are fully responsible for their Services:
Development
Release / Deployment
Ops (not platform/system administration)
An approach to management this is : externalize your configurations on platforms called: Configurations Manager
This platforms, must have the following features:
key-vaue pair creation by app. Like heroku web dashboard
expose http endpoint to get this variables from remote apps
security
Your rails app must get the variables at the startup stage or instantaneous if your language support hot reload variables.
Here some Configurations Managers:
Zookeeper : http://www.therore.net/java/2015/05/03/distributed-configuration-with-zookeeper-curator-and-spring-cloud-config.html
Consul : https://www.consul.io
Spring Cloud : https://www.baeldung.com/spring-cloud-configuration
Confignet: https://github.com/software-architect-tools/confignet
Whit this approach you will have a platform to management several apps for several environments like heroku web variables creation but more sophisticated.

secret_key_base in Rails 6.0 best practices

In Previous rails versions, the secrets file wasn't encrypted. So the best practice was to read, e.g. secret_key_base, from the environment.
This makes sense and it was pretty simple:
# config/secrets.yml
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
The Secrets served then as a simple logical directory for the keys.
in Rails 6.0 the file is encrypted and is not parsed, which means it must contain hard coded strings, i.e. the real secrets.
Is the best practice to have the value hardcoded and use the same key for all environments? This doesn't seem right.
When secure credentials where introduced in 5.2 you only had a single credentials file.
By popular demand Rails 6 will load a seperate config/credentials/*.yml.enc file - where * is the name of the environment if the file is present. This file takes complete precedence over config/credentials.yml.enc - the two are not merged.
You can edit the credentials for a specific environment by passing the environment option:
rails credentials:edit --environment development
See:
Rails PR #335219

Separate secret_key_base in Rails 5.2?

I just upgraded from 5.1 to 5.2 and I'm quite confused about this 'better' methodology to storing secrets...
Maybe I'm not understanding, but it seems like now development and production have been 'merged' into a SINGLE SECRET_KEY_BASE as well as master.key... is this correct?
If not, how do I use a separate master key and SECRET_KEY_BASE in development?
What if I have developers helping me and I don't want them to know my master key (or secrets) I use in production?
Rails 5.2 changed this quite a bit. For development and test enivoronments, the secret_key_base is generated automatically, so you can just remove it from secrets.yml or wherever you have it set.
As for production, there is the credentials file which you can generate and edit it by running rails credentials:edit. This will also create the master key in config/master.key which is only used for encrypting and decrypting this file. Add this to gitignore so it's not shared with anyone else, which should take care of sharing it with fellow devs.
If all of this sounds a bit tedious, and it is, you can just ignore it and provide the secret_key_base in ENV. Rails will check if it's present in ENV["SECRET_KEY_BASE"] before it complains.
There are two ways to access secret_key_base:
Rails.application.credentials.secret_key_base
Rails.application.secrets.secret_key_base
Rails 5 took the first way by default.
you can change Rails.application.credentials.secret_key_base by rails credentials:edit. for all other environments, remember to set environment variable RAILS_MASTER_KEY to be the same content of config/master.key. the master.key is git ignored by default. this way uses the same secret key for all environments. if you want to use different keys, you need to control namespaces by yourself.
If you prefer the second way Rails.application.secrets.secret_key_base. you need to create config/secrets.yml:
development:
secret_key_base: ...
test:
secret_key_base: ...
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
remember to set environment variable SECRET_KEY_BASE on production.
if config/secrets.yml file is secret enough, changing <%= ENV["SECRET_KEY_BASE"] %> to plain text is fine.
rake secret can generate a random secret key for you.
I prefer the second way(old way), because of simple.
I used this gem when I didn't want to share the production master.key with my friend developers which I think is the exact same purpose as the OP.
https://github.com/sinsoku/rails-env-credentials
You can have a master key for each evironment as below, so you can have a discretion as to which key you want to share with which developers/deployers.
config/credentials-development.yml.enc
config/credentials-test.yml.enc
config/credentials.yml.enc
master-development.key
master-test.key
master.key
Each key will be generated when you first run something like:
rails env_credentials:edit -e development
If you switch from one master.key setup to this, one error you might encounter will be related to config/database.yml in which Rails tries to evaluate all environment information no matter which environment you are on.
(Even if you comment them out, Rails still tries to evaluate the erb parts.)

Does Rails 4.2 use secret_token?

Are both secret_key_base and secret_token needed for production in Rails 4.2? Setting neither causes the following exception message:
Missing secret_token and secret_key_base for 'production'
environment, set these values in config/secrets.yml
The 4.2 upgrade guide (http://railsapps.github.io/updating-rails.html) says this:
When you create a new Rails application using the rails new command, a
unique secret key is generated and written to the
config/initializers/secret_token.rb file.
But no such file was created when I generated my app, and there is no reference to secret_token in config/secrets.yml
I'm assuming that the error message is wrong, and that only secret_key_base is needed. When I run my app in production on my dev machine, it starts with just secret_key_base, but in Engineyard, setting secret_key_base (via an environment variable) isn't working. I still get the error.
The problem you're seeing on Engine Yard is because the secret_key_base environment variable doesn't (yet) exist by default. That's something we're working on. You can put that in place on your own using custom chef; I suggest talking to our support team for more info on that.
As for the actual error you're getting, I just tested a brand new Rails 4.2 app ("rails new foo") to see if it's generating secret_token.rb, which it's not. I think what you need here is to create config/secrets.yml, and that file should look like this:
development:
secret_key_base: somekey
test:
secret_key_base: someotherkey
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
Now, when you see ENV["SECRET_KEY_BASE"], that's where Engine Yard has a bit of a twist - we don't provide that out of the box yet. As long as your repo is private, you can hard-code something in there on your own. Otherwise, using custom chef could get you squared away by creating a secret key base and putting it in the wrapper script responsible for launching your app worker processes (so config/env.custom on our platform, for example).
Hope this helps.
4.2 does use the secret key and the link you posted has the solution you are looking for.
In an environment that doesn't end up with the secret key active, you need to generate it using rake secret then place the output from the console into your config/initializers/secret_token.rb file (you can make one if there isn't one).
You have the option to avoid using secrets.yml. Many people prefer to use another gem/procedure (e.g. figaro) for handling secret info. To simplify your life you could just put this information into the secret_token.rb file and move on - or you can learn the various other idiomatic ways of handling the situation.
At least Rails 4.2.2 gave me the same error, but setting the environment variable SECRET_KEY_BASE in the rails user's .bash_profile file solved the problem for me, so the bit about secret_token seems to be bogus -- a holdover from earlier versions, probably.
Generate the secret by commanding rake secret, then use the generated string in file .bash_profile like this:
export SECRET_KEY_BASE='the_output_of_the_rake_secret_command'
I'd suggest re-generating a new app with the latest version of Rails installed.
This file was auto-generated in my last project:
# config/secrets.yml
# Be sure to restart your server when you modify this file.
# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rake secret` to generate a secure secret key.
# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.
development:
secret_key_base: fooooo
test:
secret_key_base: fooooo
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
I'd also recommend that you compare the generated files via the railsdiff site (example: http://railsdiff.org/4.1.10.rc2/4.2.1.rc2) as it sounds like you're upgrading from an older version.

Resources