DEV Community

Anag
Anag

Posted on • Edited on

Active Record Encryption and Rollover with ENV's instead of credentials

If you want to use environment variables (ENVs) instead of the credentials files because you're in a cloud service like AWS or Heroku you can still do it and rollover your keys.

Just add your ENVs to your .env and/or .env.development , etc. like so...

PRIMARY_KEY=EGY8WhulUOXixybod7ZWwMIL68R9o5kC
PRIMARY_KEY_ROLLOVER= <- empty until you need to rollover
DETERMINISTIC_KEY="aPA5XyALhf75NNnMzaspW7akTfZp0lPY"
KEY_DERIVATION_SALT=xEY0dt6TZcAMg52K7O84wYzkjvbA62Hz
Enter fullscreen mode Exit fullscreen mode

You don't need the deterministic key if you're not going to use it. I just have it for incase I want to.

You can create your keys in the console:

SecureRandom.alphanumeric(32)

Now that you have the ENVs you can enter them into your Parameter Store however your cloud provider allows.

Now lets boot up our app with the correct configuration.

If you added ENVs to the .env file and you're not going to care about per environment basis then add these configs to your application.rb

  config.active_record.encryption.primary_key = ENV["PRIMARY_KEY"]
  config.active_record.encryption.deterministic_key = ENV["DETERMINISTIC_KEY"]
  config.active_record.encryption.key_derivation_salt = ENV["KEY_DERIVATION_SALT"]
Enter fullscreen mode Exit fullscreen mode

However you probably should do everything by environment and add this to your (environment).rb unless your deploy process imports different ENVs based on the environment it's deploying.

# development.rb
  config.active_record.encryption.primary_key = ENV["PRIMARY_KEY"]
  config.active_record.encryption.deterministic_key = ENV["DETERMINISTIC_KEY"]
  config.active_record.encryption.key_derivation_salt = ENV["KEY_DERIVATION_SALT"]
Enter fullscreen mode Exit fullscreen mode

But what about rollover?

Lets make a change to your primary key.

# development.rb

  config.active_record.encryption.primary_key = [ENV["PRIMARY_KEY"], ENV["PRIMARY_KEY_ROLLOVER"]].compact_blank
  config.active_record.encryption.deterministic_key = ENV["DETERMINISTIC_KEY"]
  config.active_record.encryption.key_derivation_salt = ENV["KEY_DERIVATION_SALT"]
Enter fullscreen mode Exit fullscreen mode

If you don't want a rollover you can just add PRIMARY_KEY_V2, etc. and keep the array growing.

As rails initializes the environment, it will have a single value or an array of values, the last index will be the newest key.

.compact_blank will clear the array of "" values in the array for when your rollover key is empty. You only need a rollover key when you're going to rollover.

Save a new 32 char random value to your rollover ENV

PRIMARY_KEY_ROLLOVER=LsnKbJ3Gyg9Ee2Klfq1gKa6UUR54aCh6

Every time my rails app deploys it will load ENVs so now the rollover key isn't blank.

Now you need to write a script to encrypt your data to the rollover key.

You can call this script from an admin or write a data migration to run it.

Example:

  Documents.find_each do |document| #encrypt in batches of 1000
    document.encrypt
  end
Enter fullscreen mode Exit fullscreen mode

Calling .encrypt on a document will decrypt with any key it finds that works and re-encrypt with a new key (highest array index).

For the rollover approach I would copy the primary key temporarily, and then move the rollover key to the primary key env.

PRIMARY_KEY=(ROLLOVER_KEY value)
PRIMARY_KEY_ROLLOVER= (empty)
Enter fullscreen mode Exit fullscreen mode

Re deploy and all code should now be decrypting with the new rolled over key. If it didn't work add that encrypted_key that you temporarily saved back to the ENVs and fix your code, you dummy.

Remember you must add the new keys to the end of the array config.

Now you're set to rollover your keys at whatever interval you decide. Without credential.yml.

Thanks for reading.

Top comments (0)