An open API service indexing awesome lists of open source software.

https://github.com/riboseinc/transcryptor

Assists your everyday re-encryption needs, in Rails.
https://github.com/riboseinc/transcryptor

encryptor migration rails

Last synced: about 2 months ago
JSON representation

Assists your everyday re-encryption needs, in Rails.

Awesome Lists containing this project

README

        

= Transcryptor

image:https://travis-ci.org/riboseinc/transcryptor.svg?branch=master["Build Status", link="https://travis-ci.org/riboseinc/transcryptor"]
image:https://codeclimate.com/github/riboseinc/transcryptor/badges/gpa.svg["Code Climate Quality", link="https://codeclimate.com/github/riboseinc/transcryptor"]
image:https://codeclimate.com/github/riboseinc/transcryptor/badges/coverage.svg["Code Climate Quality", link="https://codeclimate.com/github/riboseinc/transcryptor/coverage"]

Transcryptor provides utility functions to help migrate records encrypted with https://github.com/attr-encrypted/attr_encrypted[`attr_encrypted`] from one encryption configuration to another.

== Installation

Add this line to your application's Gemfile:

[source,ruby]
----
gem 'transcryptor', github: 'riboseinc/transcryptor'
----

And then execute:

----
bundle
----

Or install it yourself as:

----
gem install transcryptor
----

== Usage

=== ActiveRecord::Migration

You have a `User` with `ssn` attribute which needs to be re-encrypted. `User` has next configuration:

[source,ruby]
----
class User < ActiveRecord::Base
attr_encrypted :ssn, key: ->(u) { ENV['USER_SSN_ENC_KEY'] },
mode: :per_attribute_iv_and_salt,
algorithm: 'aes-256-gcm'
end
----

To re-ecrypt this column with new key (`ENV['NEW_USER_SSN_ENC_KEY']`), algorithm (`aes-256-cbc`) and mode (`per_attribute_iv`) you can easily define migration.

[source,ruby]
----
class ReEncryptUserSsn < ActiveRecord::Migration
def up
re_encrypt_column :users, :ssn,
{ # old configuration of attr_encrypted for :ssn column
key: ->(u) { ENV['USER_SSN_ENC_KEY'] },
mode: :per_attribute_iv_and_salt,
algorithm: 'aes-256-gcm'
},
{ # new configuration of attr_encrypted for :ssn column
key: ->(u) { ENV['NEW_USER_SSN_ENC_KEY'] },
mode: :per_attribute_iv,
algorithm: 'aes-256-cbc'
}
end
end
----
Run `bundle exec rake db:migrate`. Done!

=== DataMapper::Migration

See link:#activerecordmigration[ActiveRecord::Migration] for initial data. And then `DataMapper` migration is:

[source,ruby]
----
require 'dm-migrations/migration_runner'

migration 1, :re_encrypt_user_ssn do
up do
re_encrypt_column :users, :ssn,
{ # old configuration of attr_encrypted for :ssn column
key: ->(u) { ENV['USER_SSN_ENC_KEY'] },
mode: :per_attribute_iv_and_salt,
algorithm: 'aes-256-gcm'
},
{ # new configuration of attr_encrypted for :ssn column
key: ->(u) { ENV['NEW_USER_SSN_ENC_KEY'] },
mode: :per_attribute_iv,
algorithm: 'aes-256-cbc'
}
end
end

migrate_up!
----

=== Additional options

Taking `ActiveRecord` as an example (the following applies to `DataMapper` as well):

==== `where`

Specify an SQL string (or a `proc` returning one) inside the `where` option to
limit the range on which transcryption is run:

[source,ruby]
----
class ReEncryptUserSsn < ActiveRecord::Migration
def up
re_encrypt_column :users, :ssn,
{ # old configuration of attr_encrypted for :ssn column
key: ->(u) { ENV['USER_SSN_ENC_KEY'] },
mode: :per_attribute_iv_and_salt,
algorithm: 'aes-256-gcm'
},
{ # new configuration of attr_encrypted for :ssn column
key: ->(u) { ENV['NEW_USER_SSN_ENC_KEY'] },
mode: :per_attribute_iv,
algorithm: 'aes-256-cbc'
},
where: -> { "encrypted_ssn IS NOT NULL" }
end
end
----

== Zero Downtime Migration

=== ActiveRecord

Create new columns in database.

[source,ruby]
----
class Migration1 < ActiveRecord::Migration
def up
add_column :users, :encrypted_new_ssn
add_column :users, :encrypted_new_ssn_iv
end
end
----

Add `attr_encrypted` for new columns, `include Transcryptor::ActiveRecord::ZeroDowntime`, and `transcryptor_migrate :old_attribute_name, :new_attribute_name`.

[source,ruby]
----
class User < ActiveRecord::Base
include Transcryptor::ActiveRecord::ZeroDowntime

attr_encrypted :ssn, key: '1qwe1qwe1qwe1qwe1qwe1qwe1qwe1qwe', algorithm: 'aes-256-cbc'
attr_encrypted :new_ssn, key: '2asd2asd2asd2asd2asd2asd2asd2asd', algorithm: 'aes-256-gcm'

transcryptor_migrate :ssn, :new_ssn
end
----

Create `rake` task for zero downtime migration. Or any other way you prefer.

[source,ruby]
----
namespace :zero_downtime
desc 'migrate attr_encrypted for User'
task user: :environment do
User.find_each { |user| user.save! }
end
end
----

Remove & rename columns in database after finishing of `rake` task.

[source,ruby]
----
class Migration2 < ActiveRecord::Migration
def up
remove_column :users, :encrypted_ssn
remove_column :users, :encrypted_ssn_iv

rename_column :users, :encrypted_new_ssn, :encrypted_ssn
rename_column :users, :encrypted_new_ssn_iv, :encrypted_ssn_iv
end
end
----

Move `attr_encrypted` configuration to original attribute and remove all migration code.

[source,ruby]
----
class User < ActiveRecord::Base
attr_encrypted :ssn, key: '2asd2asd2asd2asd2asd2asd2asd2asd', algorithm: 'aes-256-gcm'
end
----

Done!

== Default Options

Default options for old and new configuration are absolutelly the same as it is defined in `attr_encrypted` gem.

[source,ruby]
----
{
prefix: 'encrypted_',
suffix: '',
if: true,
unless: false,
encode: true, # changed from false to true as transcryptor works with DB rows
encode_iv: true,
encode_salt: true,
default_encoding: 'm',
marshal: false,
marshaler: Marshal,
dump_method: 'dump',
load_method: 'load',
encryptor: Encryptor,
encrypt_method: 'encrypt',
decrypt_method: 'decrypt',
mode: :per_attribute_iv,
algorithm: 'aes-256-gcm',
}
----

== Zero downtime migration using VersionedFields (from version 0.3.0)

You can use transcryptor to migrate your encrypted fields in zero downtime
using https://github.com/riboseinc/versioned_fields[versioned_fields] gem.

Just include `Transcryptor::Decoder` module and use `decode_with_previous_settings`
to decode your fields with specific settings:

```ruby
# db/migrate_versioned_fields/user/ssn.rb

VersionedFields::Migration.draw_for(User, :ssn) do
config.include Transcryptor::Decoder

version 1
version(2) do
decode_with_previous_settings(migration,
key: '67c3800d1572d9d964a6ff3bd821ed02',
algorithm: 'aes-256-gcm'
)
end

version(3) do |migration|
decode_with_previous_settings(migration,
key: '94dd7e2c40a3d51a8dd0a9137356a18e',
algorithm: 'RC2-64-CBC'
)
end
```

== Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run
`rake spec` to run the tests. You can also run `bin/console` for an interactive
prompt that will allow you to experiment.

== Contributing

Bug reports and pull requests are welcome on GitHub at
https://github.com/riboseinc/transcryptor. This project is intended to be a
safe, welcoming space for collaboration, and contributors are expected to
adhere to the http://contributor-covenant.org[Contributor Covenant] code of
conduct.

== License

The gem is available as open source under the terms of the
http://opensource.org/licenses/MIT[MIT License].