How to Rotate Keys

Many organizations rotate their keys on a regular schedule for security reasons. Cloak can do this with zero downtime.

Add Your New Key

You will need to add your new key to your vault configuration, as the first key in the :ciphers list. Demote and re-label existing keys.

For example, if your config currently looks like this:

config :my_app, MyApp.Vault,
  ciphers: [
    default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: <<...>>},
  ]

Then change the :default label to the new key, and demote the existing key to the :retired label.

config :my_app, MyApp.Vault,
  ciphers: [
    default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V2", key: <<...>>},
    retired: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V1", key: <<...>>}
  ]

Migrate Data To New Key

For each schema that uses your vault, run mix cloak.migrate:

mix cloak.migrate -r MyApp.Repo -s MyApp.Schema

Alternatively, you can migrate multiple schemas at once by configuring the following values in config/config.exs:

config :my_app,
  cloak_repo: MyApp.Repo,
  cloak_schemas: [...]

With that in place, you can simply run:

mix cloak.migrate

Remove Retired Key

Once you are confident that all data have been converted over to use the new key, you may remove the :retired key from your configuration.

config :my_app, MyApp.Vault,
  ciphers: [
    default: {Cloak.Ciphers.AES.GCM, tag: "AES.GCM.V2", key: <<...>>},
  ]

How It Works

Every ciphertext generated by Cloak is tagged with the :tag of the configured cipher that produced it.

As a result, Cloak will be able to find and use the correct cipher to decrypt any old ciphertext as long as you leave its cipher configured.

When you add a new default key, Cloak will immediately begin encrypting new data with the new key. Every time existing data are fetched from the database, it will be decrypted with the old key, and if changed, will be encrypted with the new key.

Even if you don’t run mix cloak.migrate, data will gradually be converted over to the new key as the data are used. The migration task simply speeds up the process.

This allows you to perform key migrations with zero dowtime, with both the new key and old key active at the same time.