kms_encrypted 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +13 -0
- data/CHANGELOG.md +6 -0
- data/README.md +80 -8
- data/kms_encrypted.gemspec +1 -1
- data/lib/kms_encrypted.rb +37 -23
- data/lib/kms_encrypted/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 48601fd1b07d25fafe4a14a508511bd3237ef486
|
4
|
+
data.tar.gz: 74add3ece85f95c4e1a2b5483b772c2075def8c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1461f4cbdd77bb98eba915832ee402d1467f8ed5b3578295010ece703864da16418cc7925f78fc64ffc6ed1176e34c07cc5912556fea8b2f6726b872b669e56b
|
7
|
+
data.tar.gz: 6268c77a1f065ce79ebf1a2cf954a7d36265d96135b54be8aeabec96d5b72828b8929f69dcc2778bbee3eda8247f1735747af22ed6a814fdf2428fa5d5510673
|
data/.travis.yml
ADDED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
# KMS Encrypted
|
2
2
|
|
3
|
-
|
3
|
+
Simple, secure key management for [attr_encrypted](https://github.com/attr-encrypted/attr_encrypted)
|
4
4
|
|
5
5
|
The attr_encrypted gem is great for encryption, but:
|
6
6
|
|
7
7
|
1. Leaves you to manage the security of your keys
|
8
|
-
2. Doesn’t provide
|
8
|
+
2. Doesn’t provide an easy way to rotate your keys
|
9
|
+
3. Doesn’t have a great audit trail to see how data has been accessed
|
10
|
+
4. Doesn’t let you grant encryption and decryption permission separately
|
9
11
|
|
10
|
-
KMS addresses
|
12
|
+
[KMS](https://aws.amazon.com/kms/) addresses all of these issues and it’s easy to use them together.
|
11
13
|
|
12
|
-
|
14
|
+
[![Build Status](https://travis-ci.org/ankane/kms_encrypted.svg?branch=master)](https://travis-ci.org/ankane/kms_encrypted)
|
13
15
|
|
14
16
|
## How It Works
|
15
17
|
|
@@ -27,18 +29,28 @@ Add this line to your application’s Gemfile:
|
|
27
29
|
gem 'kms_encrypted'
|
28
30
|
```
|
29
31
|
|
30
|
-
Add
|
32
|
+
Add columns for the encrypted data and the encrypted KMS data keys
|
31
33
|
|
32
34
|
```ruby
|
33
|
-
add_column :users, :
|
35
|
+
add_column :users, :encrypted_email, :text
|
36
|
+
add_column :users, :encrypted_email_iv, :text
|
37
|
+
add_column :users, :encrypted_kms_key, :text
|
34
38
|
```
|
35
39
|
|
40
|
+
Create an [Amazon Web Services](https://aws.amazon.com/) account if you don’t have one. KMS works great whether or not you use other AWS services.
|
41
|
+
|
36
42
|
Create a [KMS master key](https://console.aws.amazon.com/iam/home#/encryptionKeys) and set it in your environment ([dotenv](https://github.com/bkeepers/dotenv) is great for this)
|
37
43
|
|
38
44
|
```sh
|
39
45
|
KMS_KEY_ID=arn:aws:kms:...
|
40
46
|
```
|
41
47
|
|
48
|
+
You can also use the alias
|
49
|
+
|
50
|
+
```sh
|
51
|
+
KMS_KEY_ID=alias/my-alias
|
52
|
+
```
|
53
|
+
|
42
54
|
And update your model
|
43
55
|
|
44
56
|
```ruby
|
@@ -137,16 +149,22 @@ Change the last line to point to your CloudTrail log bucket and query away
|
|
137
149
|
```sql
|
138
150
|
SELECT
|
139
151
|
eventTime,
|
140
|
-
eventName,
|
141
152
|
userIdentity.userName,
|
142
153
|
requestParameters
|
143
154
|
FROM
|
144
155
|
cloudtrail_logs
|
145
156
|
WHERE
|
146
157
|
eventName = 'Decrypt'
|
158
|
+
AND resources[1].arn = 'arn:aws:kms:...'
|
147
159
|
ORDER BY 1
|
148
160
|
```
|
149
161
|
|
162
|
+
There will also be `GenerateDataKey` events.
|
163
|
+
|
164
|
+
## Alerting
|
165
|
+
|
166
|
+
We recommend setting up alerts on suspicious behavior.
|
167
|
+
|
150
168
|
## Key Rotation
|
151
169
|
|
152
170
|
KMS supports [automatic key rotation](http://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html). No action is required in this case.
|
@@ -165,6 +183,58 @@ User.find_each do |user|
|
|
165
183
|
end
|
166
184
|
```
|
167
185
|
|
186
|
+
## IAM Permissions
|
187
|
+
|
188
|
+
A great feature of KMS is the ability to grant encryption and decryption permission separately.
|
189
|
+
|
190
|
+
To encrypt the data, use a policy with:
|
191
|
+
|
192
|
+
```json
|
193
|
+
{
|
194
|
+
"Version": "2012-10-17",
|
195
|
+
"Statement": [
|
196
|
+
{
|
197
|
+
"Sid": "EncryptData",
|
198
|
+
"Effect": "Allow",
|
199
|
+
"Action": "kms:GenerateDataKey",
|
200
|
+
"Resource": "arn:aws:kms:..."
|
201
|
+
}
|
202
|
+
]
|
203
|
+
}
|
204
|
+
```
|
205
|
+
|
206
|
+
If a system can only encrypt, you must clear out existing data keys before updates.
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
user.encrypted_kms_key = nil # before user.save
|
210
|
+
```
|
211
|
+
|
212
|
+
To decrypt the data, use a policy with:
|
213
|
+
|
214
|
+
```json
|
215
|
+
{
|
216
|
+
"Version": "2012-10-17",
|
217
|
+
"Statement": [
|
218
|
+
{
|
219
|
+
"Sid": "DecryptData",
|
220
|
+
"Effect": "Allow",
|
221
|
+
"Action": "kms:Decrypt",
|
222
|
+
"Resource": "arn:aws:kms:..."
|
223
|
+
}
|
224
|
+
]
|
225
|
+
}
|
226
|
+
```
|
227
|
+
|
228
|
+
Be extremely selective of systems you allow to decrypt.
|
229
|
+
|
230
|
+
## Testing
|
231
|
+
|
232
|
+
For testing, you can prevent network calls to KMS by setting:
|
233
|
+
|
234
|
+
```sh
|
235
|
+
KMS_KEY_ID=insecure-test-key
|
236
|
+
```
|
237
|
+
|
168
238
|
## Multiple Keys Per Record
|
169
239
|
|
170
240
|
You may want to protect different columns with different data keys (or even master keys).
|
@@ -172,7 +242,9 @@ You may want to protect different columns with different data keys (or even mast
|
|
172
242
|
To do this, add more columns
|
173
243
|
|
174
244
|
```ruby
|
175
|
-
add_column :users, :
|
245
|
+
add_column :users, :encrypted_phone, :text
|
246
|
+
add_column :users, :encrypted_phone_iv, :text
|
247
|
+
add_column :users, :encrypted_kms_key_phone, :text
|
176
248
|
```
|
177
249
|
|
178
250
|
And update your model
|
data/kms_encrypted.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Andrew Kane"]
|
10
10
|
spec.email = ["andrew@chartkick.com"]
|
11
11
|
|
12
|
-
spec.summary = "
|
12
|
+
spec.summary = "Simple, secure key management for attr_encrypted"
|
13
13
|
spec.homepage = "https://github.com/ankane/kms_encrypted"
|
14
14
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
data/lib/kms_encrypted.rb
CHANGED
@@ -3,45 +3,59 @@ require "active_support"
|
|
3
3
|
require "aws-sdk-kms"
|
4
4
|
|
5
5
|
module KmsEncrypted
|
6
|
+
class << self
|
7
|
+
attr_accessor :client_options
|
8
|
+
end
|
9
|
+
self.client_options = {
|
10
|
+
retry_limit: 2,
|
11
|
+
http_open_timeout: 2,
|
12
|
+
http_read_timeout: 2
|
13
|
+
}
|
14
|
+
|
6
15
|
def self.kms
|
7
|
-
@kms ||= Aws::KMS::Client.new
|
16
|
+
@kms ||= Aws::KMS::Client.new(client_options)
|
8
17
|
end
|
9
18
|
|
10
19
|
module Model
|
11
20
|
def has_kms_key(legacy_key_id = nil, name: nil, key_id: nil)
|
12
21
|
key_id ||= legacy_key_id || ENV["KMS_KEY_ID"]
|
13
|
-
raise ArgumentError, "Missing key id" unless key_id
|
14
22
|
|
15
23
|
key_method = name ? "kms_key_#{name}" : "kms_key"
|
16
24
|
|
17
25
|
class_eval do
|
18
26
|
define_method(key_method) do
|
27
|
+
raise ArgumentError, "Missing key id" unless key_id
|
28
|
+
|
19
29
|
instance_var = "@#{key_method}"
|
20
30
|
|
21
31
|
unless instance_variable_get(instance_var)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
32
|
+
if key_id == "insecure-test-key"
|
33
|
+
instance_variable_set(instance_var, "00000000000000000000000000000000")
|
34
|
+
else
|
35
|
+
key_column = "encrypted_#{key_method}"
|
36
|
+
context_method = name ? "kms_encryption_context_#{name}" : "kms_encryption_context"
|
37
|
+
context = respond_to?(context_method, true) ? send(context_method) : {}
|
38
|
+
default_encoding = "m"
|
26
39
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
40
|
+
unless send(key_column)
|
41
|
+
resp = KmsEncrypted.kms.generate_data_key(
|
42
|
+
key_id: key_id,
|
43
|
+
encryption_context: context,
|
44
|
+
key_spec: "AES_256"
|
45
|
+
)
|
46
|
+
ciphertext = resp.ciphertext_blob
|
47
|
+
instance_variable_set(instance_var, resp.plaintext)
|
48
|
+
self.send("#{key_column}=", [resp.ciphertext_blob].pack(default_encoding))
|
49
|
+
end
|
37
50
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
51
|
+
unless instance_variable_get(instance_var)
|
52
|
+
ciphertext = send(key_column).unpack(default_encoding).first
|
53
|
+
resp = KmsEncrypted.kms.decrypt(
|
54
|
+
ciphertext_blob: ciphertext,
|
55
|
+
encryption_context: context
|
56
|
+
)
|
57
|
+
instance_variable_set(instance_var, resp.plaintext)
|
58
|
+
end
|
45
59
|
end
|
46
60
|
end
|
47
61
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kms_encrypted
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-kms
|
@@ -130,6 +130,7 @@ extensions: []
|
|
130
130
|
extra_rdoc_files: []
|
131
131
|
files:
|
132
132
|
- ".gitignore"
|
133
|
+
- ".travis.yml"
|
133
134
|
- CHANGELOG.md
|
134
135
|
- Gemfile
|
135
136
|
- README.md
|
@@ -159,5 +160,5 @@ rubyforge_project:
|
|
159
160
|
rubygems_version: 2.6.13
|
160
161
|
signing_key:
|
161
162
|
specification_version: 4
|
162
|
-
summary:
|
163
|
+
summary: Simple, secure key management for attr_encrypted
|
163
164
|
test_files: []
|