Active KMS
Simple, secure key management for Active Record encryption
Note: At the moment, encryption requires three encryption requests and one decryption request. See this Rails issue for more info. As a result, there’s no way to grant encryption and decryption permission separately.
For Lockbox and attr_encrypted, check out KMS Encrypted
Installation
Add this line to your application’s Gemfile:
gem "active_kms"
And follow the instructions for your key management service:
- AWS KMS
- Google Cloud KMS
- Vault
AWS KMS
Add this line to your application’s Gemfile:
gem "aws-sdk-kms"
Create an Amazon Web Services account if you don’t have one. KMS works great whether or not you run your infrastructure on AWS.
Create a KMS master key and set it in your environment along with your AWS credentials (dotenv is great for this)
KMS_KEY_ID=alias/my-key
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
And add to config/application.rb
:
config.active_record.encryption.key_provider = ActiveKms::AwsKeyProvider.new(key_id: ENV["KMS_KEY_ID"])
Google Cloud KMS
Add this line to your application’s Gemfile:
gem "google-cloud-kms"
Create a Google Cloud Platform account if you don’t have one. KMS works great whether or not you run your infrastructure on GCP.
Create a KMS key ring and key and set it in your environment along with your GCP credentials (dotenv is great for this)
KMS_KEY_ID=projects/my-project/locations/global/keyRings/my-key-ring/cryptoKeys/my-key
And add to config/application.rb
:
config.active_record.encryption.key_provider = ActiveKms::GoogleCloudKeyProvider.new(key_id: ENV["KMS_KEY_ID"])
Vault
Add this line to your application’s Gemfile:
gem "vault"
Enable the transit secrets engine
vault secrets enable transit
And create a key
vault write -f transit/keys/my-key
Set it in your environment along with your Vault credentials (dotenv is great for this)
KMS_KEY_ID=my-key
VAULT_ADDR=http://127.0.0.1:8200
VAULT_TOKEN=secret
And add to config/application.rb
:
config.active_record.encryption.key_provider = ActiveKms::VaultKeyProvider.new(key_id: ENV["KMS_KEY_ID"])
Per-Attribute Keys
Specify per-attribute keys
class User < ApplicationRecord
encrypts :email, key_provider: ActiveKms::AwsKeyProvider.new(key_id: "...")
end
Testing
For testing, you can prevent network calls to KMS by adding to config/environments/test.rb
:
config.active_record.encryption.key_provider = ActiveKms::TestKeyProvider.new
Key Rotation
Key management services allow you to rotate the master key without any code changes.
- For AWS KMS, you can use automatic key rotation
- For Google Cloud, use the Google Cloud Console or API
- For Vault, use:
vault write -f transit/keys/my-key/rotate
New data will be encrypted with the new master key version. To encrypt existing data with new master key version, run:
User.find_each do |user|
user.encrypt
end
Switching Keys
You can change keys within your current KMS or move to a different KMS without downtime.
Set globally in config/application.rb
:
config.active_record.encryption.previous = [{key_provider: ActiveKms::AwsKeyProvider.new(key_id: "...")}]
Or per-attribute:
class User < ApplicationRecord
encrypts :email, previous: [{key_provider: ActiveKms::AwsKeyProvider.new(key_id: "...")}]
end
Reference
Specify a client
ActiveKms::AwsKeyProvider.new(client: Aws::KMS::Client.new, ...)
# or
ActiveKms::GoogleCloudKeyProvider.new(client: Google::Cloud::Kms.key_management_service, ...)
# or
ActiveKms::VaultKeyProvider.new(client: Vault::Client.new, ...)
History
View the changelog
Contributing
Everyone is encouraged to help improve this project. Here are a few ways you can help:
- Report bugs
- Fix bugs and submit pull requests
- Write, clarify, or fix documentation
- Suggest or add new features
To get started with development:
git clone https://github.com/ankane/active_kms.git
cd active_kms
bundle install
bundle exec rake test