The go-to resource for upgrading Ruby, Rails, and your dependencies.

Resolving Rails 8 Encrypted Secrets Deprecations


“Security is a process, not a product.” — Bruce Schneier

When you upgrade an application to Ruby on Rails 8, you may encounter an error or deprecation warning regarding config.read_encrypted_secrets. This configuration option enabled the older encrypted secrets system introduced in Rails 5.1. In Rails 8, though, it has been fully deprecated and removed.

To resolve this issue and complete your Rails 8 upgrade, you must migrate your application from encrypted secrets to the modern Rails credentials system. This guide will walk you through exactly how to do that, step by step.

Understanding the Evolution of Rails Secrets

Before diving into the migration, though, let’s take a step back and talk about how Rails has historically handled sensitive information. Originally, Rails applications stored sensitive data in a plain text config/secrets.yml file. This was an improvement over hardcoding API keys, but it meant that sensitive data was often accidentally committed to version control — a significant security risk.

To address this, Rails 5.1 introduced encrypted secrets. This allowed developers to encrypt the secrets.yml file, making it safe to commit to version control. The application would then decrypt the file at runtime using a separate key file or environment variable.

This system, though, was short-lived. Rails 5.2 introduced the credentials system — which provided a more robust and flexible approach to managing encrypted configuration.

One may wonder: if encrypted secrets worked, why did Rails introduce credentials so soon after? The answer is straightforward: the new credentials system allows for multiple environments and granular encryption keys, rather than relying on a single monolithic secret file.

Of course, there are three major approaches to handling secrets in modern Ruby applications; depending on the particular circumstances you find yourself in, one of them may be more useful than the other two.

The first is relying entirely on environment variables, typically managed in development through a tool like the dotenv gem. This is most useful, in my experience, for applications deployed to containerized environments like Docker or Kubernetes, where injecting environment variables is the native way to handle configuration.

The second is using an external secrets manager, such as AWS Secrets Manager or HashiCorp Vault. This particular option is often preferred for large enterprise applications with dedicated security teams, as it centralizes secret rotation and access control outside the application code.

The third option is the Rails credentials system. It keeps configuration tightly coupled with the codebase for security and convenience, avoiding the need for separate .env files. This guide covers this approach as the direct replacement for the deprecated encrypted secrets feature.

For several major versions, Rails supported both systems. With Rails 8, however, the old encrypted secrets system has been completely removed. If your application still relies on config/secrets.yml.enc and sets config.read_encrypted_secrets = true, it will no longer boot correctly.

A Step-by-Step Migration Path

Migrating from encrypted secrets to credentials requires careful execution to avoid production downtime or lost keys. You can accomplish this by safely transferring your existing secrets into a new credentials file.

Step 1: Extracting Your Existing Secrets

First, you need to read the values currently stored in your encrypted secrets. You can do this by opening a Rails console in your current Rails environment — before upgrading to Rails 8 — and inspecting the decrypted values.

$ bin/rails console
irb(main):001:0> Rails.application.secrets
=> {:secret_key_base=>"d0c8...", :stripe_api_key=>"sk_live_123..."}

You should copy the relevant secret keys and values to a secure, temporary location. Be sure to capture the configuration for all environments, including production, staging, and development. You also may notice that the secrets hash contains a mix of nested structures and flat key-value pairs; you should reorganize these logically in the next step.

Step 2: Initializing Rails Credentials

If your project does not already have a credentials file, you can generate one using the Rails CLI.

$ EDITOR=vim bin/rails credentials:edit

This command generates two files:

  • an encrypted file for your sensitive data, config/credentials.yml.enc.
  • an encryption key for the credentials file, config/master.key.

Note: Although they have related names, these two files serve very different purposes. The .enc file contains the actual data and is safe to commit. The .key file is the cryptographic key that decrypts the data. Therefore, you must never commit config/master.key to version control. It should be added to your .gitignore file immediately.

Of course, if your application uses environment-specific credentials — a feature introduced in Rails 6.0 — you can generate a file for a specific environment like this:

$ EDITOR=vim bin/rails credentials:edit -e production

I’ve used EDITOR=vim here to ensure I get my preferred text editor, but you can also rely on your system’s default.

Step 3: Populating the New Credentials File

With the editor open, you can paste the secrets you extracted in the first step into the new credentials file. The format is standard YAML.

# config/credentials.yml.enc (decrypted view)
secret_key_base: "your_long_secret_key_base_string"
stripe:
  api_key: "sk_live_..."
aws:
  access_key_id: "AKIA..."
  secret_access_key: "..."

When you save and close the editor, Rails will automatically encrypt the file and save it to config/credentials.yml.enc.

One may wonder: how does Rails know what to do when you save and quit the editor? The answer is that the credentials:edit command pauses its execution while the editor is open. Once the editor process exits, Rails reads the temporary file you saved, encrypts its contents using the master key, writes the new encrypted payload, and finally deletes the plaintext temporary file.

Step 4: Updating Your Application Code

Next, you must update your application code to reference the new Rails.application.credentials API instead of the deprecated Rails.application.secrets.

For example, if you previously accessed a Stripe API key like this:

# Old approach
Stripe.api_key = Rails.application.secrets.stripe_api_key

You should update it to use the credentials object. There are a few different ways you could do this. You could access the credentials object directly like a hash:

# Direct hash access
Stripe.api_key = Rails.application.credentials.stripe[:api_key]

This works, but it has a significant drawback. If the stripe key is completely missing from your credentials file, Rails.application.credentials.stripe will return nil. Attempting to call [:api_key] on nil will result in a NoMethodError, crashing your application.

Instead, you can use the dig method:

# Preferred approach
Stripe.api_key = Rails.application.credentials.dig(:stripe, :api_key)

The dig method is generally preferred here as it safely returns nil if any of the nested keys are not found in the path. This prevents unexpected exceptions and allows you to handle missing configuration gracefully.

Step 5: Cleaning Up the Old Configuration

Once your code is updated and thoroughly tested, you can remove the old secrets infrastructure.

You can remove the old files with a few shell commands:

$ rm config/secrets.yml
$ rm config/secrets.yml.enc
$ rm config/secrets.yml.key

Then, you must remove the configuration line that triggered this deprecation warning in the first place. You can typically find this in config/application.rb or an environment-specific configuration file like config/environments/production.rb:

# Remove this line from your configuration
config.read_encrypted_secrets = true

How to Verify Your Migration is Successful

Before deploying these changes to production, you should verify that your application can successfully boot and access the necessary credentials. You can test this locally by running your test suite and confirming that no config.read_encrypted_secrets warnings appear in your logs.

When deploying, ensure your server environment has the RAILS_MASTER_KEY environment variable set to the contents of your config/master.key file. This allows your production application to decrypt the credentials.yml.enc file at runtime.

If you have properly managed your keys and correctly updated your code, your application will boot cleanly on Rails 8 without skipping a beat — securely handling your secrets for the long term.

Sponsored by Durable Programming

Need help maintaining or upgrading your Ruby on Rails application? Durable Programming specializes in keeping Rails apps secure, performant, and up-to-date.

Hire Durable Programming