Search code examples
ruby-on-railsherokucredentialsruby-on-rails-6

Rails encrypted credentials with Heroku staging environment (using production setting)


Heroku recommends not using a custom environment called staging; instead, they suggest using the production environment but with a different set of ENV variables. This makes sense (see this question).

However, I am wondering how I can integrate this practice with Rails 6 encrypted credentials feature. Encrypted credentials does support multiple environments, so we can keep our development and production credentials separate; however, using Heroku's recommendation would mean that the production credentials would be shared between the actual production server and the actual staging server. Which I don't want.

What I do want is the staging server to use the development credentials in the production environment!

Keeping all the different credentials uploaded and up to date (between production, staging, and all our developers) is a hassle and the encrypted file seems like an much needed improvement; I just can't sort out how to get staging to use the non-production crednetials.


PS: perhaps one could override the config.credentials.content_path per the docs based on an environmental variable set in Heroku that indicates whether to use the production or development credentials. Curious what others are doing or might do.


Solution

  • Overriding is the solution indeed. Here's my setup.

    Since RAILS_ENV is set to production per Heroku's recommendation, I use another environment variable that I called PIPE_ENV and which is set to the position in the pipeline, so staging, edge (for development), etc.

    Now in application.rb, I set the content_path.

    module MyAppName
      class Application < Rails::Application
        …
        if ENV["PIPE_ENV"].present?
          Rails.application.config.credentials.content_path = Rails.root.join("config/credentials/#{ENV["PIPE_ENV"]}.yml.enc")
        end
      end
    end
    

    I don't like having things in here but config/environments/production.rb uses credentials to set the mailer, so it has to be set earlier.

    Also, don't forget to set the RAILS_MASTER_KEY to the corresponding environment, so for staging you call

    heroku config:set RAILS_MASTER_KEY=your-staging-key -a your-staging-app
    

    Of course, your-staging-key is the string in config/credentials/staging.key

    Bonus, for the rest of your app, you can add this in config/initializer/pipe_env.rb so that you can call Rails.pipe_env just like you call Rails.env:

    module Rails
      class << self
        def pipe_env
          @_pipe_env = ActiveSupport::StringInquirer.new(ENV["PIPE_ENV"].presence || Rails.env)
        end
      end
    end