kms_encrypted 0.3.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/LICENSE.txt +1 -1
- data/README.md +40 -13
- data/lib/kms_encrypted/client.rb +69 -0
- data/lib/kms_encrypted/clients/aws.rb +36 -0
- data/lib/kms_encrypted/clients/base.rb +45 -0
- data/lib/kms_encrypted/clients/google.rb +40 -0
- data/lib/kms_encrypted/clients/test.rb +29 -0
- data/lib/kms_encrypted/clients/vault.rb +48 -0
- data/lib/kms_encrypted/database.rb +93 -0
- data/lib/kms_encrypted/log_subscriber.rb +14 -6
- data/lib/kms_encrypted/model.rb +70 -122
- data/lib/kms_encrypted/version.rb +1 -1
- data/lib/kms_encrypted.rb +26 -2
- metadata +13 -15
- data/.gitignore +0 -9
- data/.travis.yml +0 -11
- data/Gemfile +0 -3
- data/Rakefile +0 -11
- data/guides/Amazon.md +0 -262
- data/guides/Google.md +0 -131
- data/guides/Vault.md +0 -143
- data/kms_encrypted.gemspec +0 -34
data/guides/Google.md
DELETED
@@ -1,131 +0,0 @@
|
|
1
|
-
# Google KMS
|
2
|
-
|
3
|
-
Add this line to your application’s Gemfile:
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
gem 'google-api-client'
|
7
|
-
gem 'kms_encrypted'
|
8
|
-
```
|
9
|
-
|
10
|
-
Add columns for the encrypted data and the encrypted KMS data keys
|
11
|
-
|
12
|
-
```ruby
|
13
|
-
add_column :users, :encrypted_email, :text
|
14
|
-
add_column :users, :encrypted_email_iv, :text
|
15
|
-
add_column :users, :encrypted_kms_key, :text
|
16
|
-
```
|
17
|
-
|
18
|
-
Create a [Google Cloud Platform](https://cloud.google.com/) account if you don’t have one. KMS works great whether or not you run your infrastructure on GCP.
|
19
|
-
|
20
|
-
Create a [KMS key ring and key](https://console.cloud.google.com/iam-admin/kms) and set it in your environment along with your GCP credentials ([dotenv](https://github.com/bkeepers/dotenv) is great for this)
|
21
|
-
|
22
|
-
```sh
|
23
|
-
KMS_KEY_ID=projects/.../locations/.../keyRings/.../cryptoKeys/...
|
24
|
-
```
|
25
|
-
|
26
|
-
And update your model
|
27
|
-
|
28
|
-
```ruby
|
29
|
-
class User < ApplicationRecord
|
30
|
-
has_kms_key
|
31
|
-
|
32
|
-
attr_encrypted :email, key: :kms_key
|
33
|
-
end
|
34
|
-
```
|
35
|
-
|
36
|
-
For each encrypted attribute, use the `kms_key` method for its key.
|
37
|
-
|
38
|
-
## Auditing
|
39
|
-
|
40
|
-
Follow the [instructions here](https://cloud.google.com/kms/docs/logging) to set up data access logging. To know what data is being decrypted, you’ll need to add context.
|
41
|
-
|
42
|
-
Add a `kms_encryption_context` method to your model.
|
43
|
-
|
44
|
-
```ruby
|
45
|
-
class User < ApplicationRecord
|
46
|
-
def kms_encryption_context
|
47
|
-
# some hash
|
48
|
-
end
|
49
|
-
end
|
50
|
-
```
|
51
|
-
|
52
|
-
The context is used as part of the encryption and decryption process, so it must be a value that doesn’t change. Otherwise, you won’t be able to decrypt.
|
53
|
-
|
54
|
-
The primary key is a good choice, but auto-generated ids aren’t available until a record is created, and we need to encrypt before this. One solution is to preload the primary key. Here’s what it looks like with Postgres:
|
55
|
-
|
56
|
-
```ruby
|
57
|
-
class User < ApplicationRecord
|
58
|
-
def kms_encryption_context
|
59
|
-
self.id ||= self.class.connection.execute("select nextval('#{self.class.sequence_name}')").first["nextval"]
|
60
|
-
{"Record" => "#{model_name}/#{id}"}
|
61
|
-
end
|
62
|
-
end
|
63
|
-
```
|
64
|
-
|
65
|
-
## Alerting
|
66
|
-
|
67
|
-
We recommend setting up alerts on suspicious behavior.
|
68
|
-
|
69
|
-
## Key Rotation
|
70
|
-
|
71
|
-
To manually rotate keys, replace the old key id with the new key id in your model. Your app does not need the old key id to perform rotation (however, the key must still be enabled in your GCP account).
|
72
|
-
|
73
|
-
```sh
|
74
|
-
KMS_KEY_ID=...
|
75
|
-
```
|
76
|
-
|
77
|
-
and run
|
78
|
-
|
79
|
-
```ruby
|
80
|
-
User.find_each do |user|
|
81
|
-
user.rotate_kms_key!
|
82
|
-
end
|
83
|
-
```
|
84
|
-
|
85
|
-
## Testing
|
86
|
-
|
87
|
-
For testing, you can prevent network calls to KMS by setting:
|
88
|
-
|
89
|
-
```sh
|
90
|
-
KMS_KEY_ID=insecure-test-key
|
91
|
-
```
|
92
|
-
|
93
|
-
## Multiple Keys Per Record
|
94
|
-
|
95
|
-
You may want to protect different columns with different data keys (or even master keys).
|
96
|
-
|
97
|
-
To do this, add more columns
|
98
|
-
|
99
|
-
```ruby
|
100
|
-
add_column :users, :encrypted_phone, :text
|
101
|
-
add_column :users, :encrypted_phone_iv, :text
|
102
|
-
add_column :users, :encrypted_kms_key_phone, :text
|
103
|
-
```
|
104
|
-
|
105
|
-
And update your model
|
106
|
-
|
107
|
-
```ruby
|
108
|
-
class User < ApplicationRecord
|
109
|
-
has_kms_key
|
110
|
-
has_kms_key name: :phone, key_id: "..."
|
111
|
-
|
112
|
-
attr_encrypted :email, key: :kms_key
|
113
|
-
attr_encrypted :phone, key: :kms_key_phone
|
114
|
-
end
|
115
|
-
```
|
116
|
-
|
117
|
-
For context, use:
|
118
|
-
|
119
|
-
```ruby
|
120
|
-
class User < ApplicationRecord
|
121
|
-
def kms_encryption_context_phone
|
122
|
-
# some hash
|
123
|
-
end
|
124
|
-
end
|
125
|
-
```
|
126
|
-
|
127
|
-
To rotate keys, use:
|
128
|
-
|
129
|
-
```ruby
|
130
|
-
user.rotate_kms_key_phone!
|
131
|
-
```
|
data/guides/Vault.md
DELETED
@@ -1,143 +0,0 @@
|
|
1
|
-
# Vault
|
2
|
-
|
3
|
-
Add this line to your application’s Gemfile:
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
gem 'vault'
|
7
|
-
gem 'kms_encrypted'
|
8
|
-
```
|
9
|
-
|
10
|
-
Add columns for the encrypted data and the encrypted KMS data keys
|
11
|
-
|
12
|
-
```ruby
|
13
|
-
add_column :users, :encrypted_email, :text
|
14
|
-
add_column :users, :encrypted_email_iv, :text
|
15
|
-
add_column :users, :encrypted_kms_key, :text
|
16
|
-
```
|
17
|
-
|
18
|
-
Enable the [transit](https://www.vaultproject.io/docs/secrets/transit/index.html) backend
|
19
|
-
|
20
|
-
```sh
|
21
|
-
vault secrets enable transit
|
22
|
-
```
|
23
|
-
|
24
|
-
And create a key
|
25
|
-
|
26
|
-
```sh
|
27
|
-
vault write -f transit/keys/my-key
|
28
|
-
```
|
29
|
-
|
30
|
-
Set it in your environment along with your Vault credentials ([dotenv](https://github.com/bkeepers/dotenv) is great for this)
|
31
|
-
|
32
|
-
```sh
|
33
|
-
KMS_KEY_ID=vault/my-key
|
34
|
-
VAULT_ADDR=http://127.0.0.1:8200
|
35
|
-
VAULT_TOKEN=secret
|
36
|
-
```
|
37
|
-
|
38
|
-
And update your model
|
39
|
-
|
40
|
-
```ruby
|
41
|
-
class User < ApplicationRecord
|
42
|
-
has_kms_key
|
43
|
-
|
44
|
-
attr_encrypted :email, key: :kms_key
|
45
|
-
end
|
46
|
-
```
|
47
|
-
|
48
|
-
For each encrypted attribute, use the `kms_key` method for its key.
|
49
|
-
|
50
|
-
## Auditing
|
51
|
-
|
52
|
-
Follow the [instructions here](https://www.vaultproject.io/docs/audit/) to set up data access logging. To know what data is being decrypted, you’ll need to add context.
|
53
|
-
|
54
|
-
Add a `kms_encryption_context` method to your model.
|
55
|
-
|
56
|
-
```ruby
|
57
|
-
class User < ApplicationRecord
|
58
|
-
def kms_encryption_context
|
59
|
-
# some hash
|
60
|
-
end
|
61
|
-
end
|
62
|
-
```
|
63
|
-
|
64
|
-
The context is used as part of the encryption and decryption process, so it must be a value that doesn’t change. Otherwise, you won’t be able to decrypt. Read more about [encryption context here](https://docs.aws.amazon.com/kms/latest/developerguide/encryption-context.html).
|
65
|
-
|
66
|
-
The primary key is a good choice, but auto-generated ids aren’t available until a record is created, and we need to encrypt before this. One solution is to preload the primary key. Here’s what it looks like with Postgres:
|
67
|
-
|
68
|
-
```ruby
|
69
|
-
class User < ApplicationRecord
|
70
|
-
def kms_encryption_context
|
71
|
-
self.id ||= self.class.connection.execute("select nextval('#{self.class.sequence_name}')").first["nextval"]
|
72
|
-
{"Record" => "#{model_name}/#{id}"}
|
73
|
-
end
|
74
|
-
end
|
75
|
-
```
|
76
|
-
|
77
|
-
## Alerting
|
78
|
-
|
79
|
-
We recommend setting up alerts on suspicious behavior.
|
80
|
-
|
81
|
-
## Key Rotation
|
82
|
-
|
83
|
-
To manually rotate keys, replace the old key id with the new key id in your model.
|
84
|
-
|
85
|
-
```sh
|
86
|
-
KMS_KEY_ID=...
|
87
|
-
```
|
88
|
-
|
89
|
-
and run
|
90
|
-
|
91
|
-
```ruby
|
92
|
-
User.find_each do |user|
|
93
|
-
user.rotate_kms_key!
|
94
|
-
end
|
95
|
-
```
|
96
|
-
|
97
|
-
## Testing
|
98
|
-
|
99
|
-
For testing, you can prevent network calls to KMS by setting:
|
100
|
-
|
101
|
-
```sh
|
102
|
-
KMS_KEY_ID=insecure-test-key
|
103
|
-
```
|
104
|
-
|
105
|
-
## Multiple Keys Per Record
|
106
|
-
|
107
|
-
You may want to protect different columns with different data keys (or even master keys).
|
108
|
-
|
109
|
-
To do this, add more columns
|
110
|
-
|
111
|
-
```ruby
|
112
|
-
add_column :users, :encrypted_phone, :text
|
113
|
-
add_column :users, :encrypted_phone_iv, :text
|
114
|
-
add_column :users, :encrypted_kms_key_phone, :text
|
115
|
-
```
|
116
|
-
|
117
|
-
And update your model
|
118
|
-
|
119
|
-
```ruby
|
120
|
-
class User < ApplicationRecord
|
121
|
-
has_kms_key
|
122
|
-
has_kms_key name: :phone, key_id: "..."
|
123
|
-
|
124
|
-
attr_encrypted :email, key: :kms_key
|
125
|
-
attr_encrypted :phone, key: :kms_key_phone
|
126
|
-
end
|
127
|
-
```
|
128
|
-
|
129
|
-
For context, use:
|
130
|
-
|
131
|
-
```ruby
|
132
|
-
class User < ApplicationRecord
|
133
|
-
def kms_encryption_context_phone
|
134
|
-
# some hash
|
135
|
-
end
|
136
|
-
end
|
137
|
-
```
|
138
|
-
|
139
|
-
To rotate keys, use:
|
140
|
-
|
141
|
-
```ruby
|
142
|
-
user.rotate_kms_key_phone!
|
143
|
-
```
|
data/kms_encrypted.gemspec
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require "kms_encrypted/version"
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "kms_encrypted"
|
8
|
-
spec.version = KmsEncrypted::VERSION
|
9
|
-
spec.authors = ["Andrew Kane"]
|
10
|
-
spec.email = ["andrew@chartkick.com"]
|
11
|
-
|
12
|
-
spec.summary = "Simple, secure key management for attr_encrypted"
|
13
|
-
spec.homepage = "https://github.com/ankane/kms_encrypted"
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
-
f.match(%r{^(test|spec|features)/})
|
18
|
-
end
|
19
|
-
spec.bindir = "exe"
|
20
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
-
spec.require_paths = ["lib"]
|
22
|
-
|
23
|
-
spec.add_dependency "activesupport"
|
24
|
-
|
25
|
-
spec.add_development_dependency "bundler"
|
26
|
-
spec.add_development_dependency "rake"
|
27
|
-
spec.add_development_dependency "minitest"
|
28
|
-
spec.add_development_dependency "sqlite3"
|
29
|
-
spec.add_development_dependency "activerecord"
|
30
|
-
spec.add_development_dependency "attr_encrypted"
|
31
|
-
spec.add_development_dependency "aws-sdk-kms"
|
32
|
-
spec.add_development_dependency "google-api-client"
|
33
|
-
spec.add_development_dependency "vault"
|
34
|
-
end
|