Rails 5.2 Custom Credentials — generally accepted way to segregate environments?

104 views
Skip to first unread message

Jason Fleetwood-Boldt

unread,
Jun 9, 2019, 9:40:05 PM6/9/19
to Ruby on Rails: Talk
In some apps I've worked on Rails 5.1 and prior, environment variables, saved directly into the source code.

In rails 5.2 Custom credentials encourages us to check-in only the encrypted version of our configuration, and keep our master.key keyfile outside of our repository. 

My question is this: Is there a way to segregate by environment? (i.e., development, staging, production?)

seems like the instructions for setting up AWS keys, for example, would have the dev, staging + production all pointing to & using the same AWS bucket, access key, and secret. But it seems like for many services I'd want to have different credentials for different environments. 

I found this SO post that discusses this question, but unfortunately it doesn't present a very good answer IMHO because the there are only two answers: 1) I don't quite understand and 2) a suggestion to basically check all your ENV variables against each of your environments, which seems like it could encourage a messy setup. I much like answer #1 from this SO post, but I don't understand how to implement it practically. 


any tip appreciated. 
Thanks,
Jason

Ariel Juodziukynas

unread,
Jun 10, 2019, 12:26:14 AM6/10/19
to rubyonra...@googlegroups.com
Rails 6 will have this feature https://github.com/rails/rails/pull/33521

For Rails 5.2, personally, I wouldn't add the file to the source control. I would do this steps:

1- run rails credentials:edit locally
2- add the credentials for production and save
3- upload the file to your hosting at /home/user/your_app/shared/config/
4- configure capistrano to symlink that file on each deploy (at config/deploy.rb)

set :linked_files, fetch(:linked_files, [])+%W{config/credentials.yml.enc}

Now, on each deploy, capistrano runs a task that adds some symlink to the current release pointing to /shared so they are kept between releases. Your file /home/user/your_app/current/config/credentials.yml.enc will actually be a symlink to /home/user/your_app/shared/config/credentials.yml.enc. You can just have that on production, use one on development and add it to the .gitignore file so it doesn't conflict with the symlink.


--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
To post to this group, send email to rubyonra...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/4577e3bb-754c-48bc-8fe3-f8fddda77481%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

te...@datatravels.com

unread,
Jun 10, 2019, 8:33:14 AM6/10/19
to rubyonra...@googlegroups.com

On Jun 10, 2019, at 12:25 AM, Ariel Juodziukynas <arie...@gmail.com> wrote:

Rails 6 will have this feature https://github.com/rails/rails/pull/33521

For Rails 5.2, personally, I wouldn't add the file to the source control. I would do this steps:

1- run rails credentials:edit locally
2- add the credentials for production and save
3- upload the file to your hosting at /home/user/your_app/shared/config/


You  mean, you don't even check-in the encrypted file?


4- configure capistrano to symlink that file on each deploy (at config/deploy.rb)

set :linked_files, fetch(:linked_files, [])+%W{config/credentials.yml.enc}

Now, on each deploy, capistrano runs a task that adds some symlink to the current release pointing to /shared so they are kept between releases. Your file /home/user/your_app/current/config/credentials.yml.enc will actually be a symlink to /home/user/your_app/shared/config/credentials.yml.enc. You can just have that on production, use one on development and add it to the .gitignore file so it doesn't conflict with the symlink.



I think this is interesting but sort of paradigmatically different as I am working with 12-Factor deploys (Heroku), so there isn't a symlink paradigm in these cases. 

nonetheless, thanks for the input.


-Jason



Ariel Juodziukynas

unread,
Jun 10, 2019, 9:13:00 AM6/10/19
to rubyonra...@googlegroups.com
Hmmmm I don't know if heroku lets you add custom commands during deploy, I've only used it for tests. If it does, you could have two files on your source credentials.yml.enc.prod and credentials.yml.enc.dev and during deploy just rename on of them depending on the environment you are (mv config/credentials.yml.enc config/credentials.yml.enc). It you can't add custom command then I don't know haha.

--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
To post to this group, send email to rubyonra...@googlegroups.com.

Eric Anderson

unread,
Jun 10, 2019, 9:31:32 AM6/10/19
to Ruby on Rails: Talk
I've found the rails-env-credentials gem useful for this. Not sure how compatible it will be with the upcoming Rails 6 support but its been working great for my app.

Eric

Sampson Crowley

unread,
Jun 10, 2019, 8:38:36 PM6/10/19
to rubyonra...@googlegroups.com
for rails 5, just nest environment specific credentials under a key for said environment

then all you have to do when accessing said config is add the environment to the party that pulls in config, e.g.:

credentials.yml.enc
```
main_key:
    development:
        sub_key:
            value_key: 'development'
    production:
        sub_key:
            value_key: 'production'
    test:
        sub_key:
            value_key: 'test'
```

code:
```
my_credential = Rails.application.credentials.dig(:main_key, Rails.env.to_sym, :subkey, :value_key)`
```



--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
To post to this group, send email to rubyonra...@googlegroups.com.

Sampson Crowley

unread,
Jun 10, 2019, 8:40:27 PM6/10/19
to Ruby on Rails: Talk
for rails 5, just nest environment specific credentials under a key for said environment

then all you have to do when accessing said config is add the environment to the party that pulls in config, e.g.:

credentials.yml.enc:

main_key:
  development
:
    sub_key
:
      value_key
: 'development'
  production
:
    sub_key
:
      value_key
: 'production'
  test
:
    sub_key
:
      value_key
: 'test'

code:


my_credential
= Rails.application.credentials.dig(:main_key, Rails.env.to_sym, :sub_key, :value_key)
```

te...@datatravels.com

unread,
Jun 12, 2019, 9:09:53 AM6/12/19
to rubyonra...@googlegroups.com
I think this solution seems the most Rails 5.2 friendly, but ideally isn't the perfect solution as ideally you could in fact (one day, in Rails 6, say), separate the 3 files themselves, so you could, say, give junior developers access to only development+staging credentials by giving the only the keys for the development + staging master keys (but continuing to check-in all 3 .yml.enc files into source-code. the 3 keys are of course, not checked-in)

But if you have a team where you don't care if all the devs have the same (full) credentials then I like this solution best.

-Jason





--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
To post to this group, send email to rubyonra...@googlegroups.com.

Sampson Crowley

unread,
Jun 14, 2019, 3:19:56 AM6/14/19
to rubyonra...@googlegroups.com
In the mean time you can add a rake task to the lib folder to rename credentials, or a bash/Ruby script to the bin folder:

Given: development.yml.enc, test.yml.enc, production.yml.enc

lib/tasks/credentials.rake

namespace : credentials do
  namespace :set_env do
    task production: : environment do
      Rake::Task['credentials:set_env'].invoke('production')
    end

    task test: : environment do
      Rake::Task['credentials:set_env'].invoke('test')
    end

    task development: : environment do
      Rake::Task['credentials:set_env'].invoke('development')
    end
  end

  task :set_env, [ :env_name ] => : environment do |_, args|
    File.open(Rails.root.join('config', 'credentials.yml.enc'), 'w') do |f|
      f.write(File.read(Rails.root.join('config', "#{args[:env_name]}.ym.enc")))
    end
  end
end

For something dynamic you could do

namespace : credentials do
  namespace :set_env do
    Dir['config/*.yml.enc'].each do |path|
      f_name = path[/(\w+)\.yml\.enc$/, 1].to_sym
      next if f_name == :credentials

      task f_name => : environment do
        File.open(Rails.root.join('config', 'credentials.yml.enc'), 'w') do |f|
          f.write(File.read(path))
        end
     end
  end
end


Reply all
Reply to author
Forward
0 new messages