kms_encrypted 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4319f0f40f5294c89119d36ebaba64696eb9abeb
4
- data.tar.gz: 46933afe998badcf3b95814e0d9c1144f432d822
3
+ metadata.gz: 48601fd1b07d25fafe4a14a508511bd3237ef486
4
+ data.tar.gz: 74add3ece85f95c4e1a2b5483b772c2075def8c4
5
5
  SHA512:
6
- metadata.gz: 2ca6b3da8040d329ee3a4bac21e0a06e82c9c423fed259e62508dd92332196eac46034d3803760baffc3c312a7618594fd1c0caefe7b25ebc8b57305e176501d
7
- data.tar.gz: 56520a00ea21504b321e6e93f8f43283cd37a1b75d84661cb4e2a85d2ead8dda11062eb307bb8b4258c26ebdc3b0fcad017d335e9e9471314e0f393e69632f50
6
+ metadata.gz: 1461f4cbdd77bb98eba915832ee402d1467f8ed5b3578295010ece703864da16418cc7925f78fc64ffc6ed1176e34c07cc5912556fea8b2f6726b872b669e56b
7
+ data.tar.gz: 6268c77a1f065ce79ebf1a2cf954a7d36265d96135b54be8aeabec96d5b72828b8929f69dcc2778bbee3eda8247f1735747af22ed6a814fdf2428fa5d5510673
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ rvm: 2.4.2
3
+ gemfile:
4
+ - Gemfile
5
+ sudo: false
6
+ before_install: gem install bundler
7
+ script: bundle exec rake test
8
+ env:
9
+ - KMS_KEY_ID=insecure-test-key
10
+ notifications:
11
+ email:
12
+ on_success: never
13
+ on_failure: change
@@ -1,3 +1,9 @@
1
+ ## 0.1.3
2
+
3
+ - Added test key
4
+ - Added `client_options`
5
+ - Allow private or protected `kms_encryption_context` method
6
+
1
7
  ## 0.1.2
2
8
 
3
9
  - Use `KMS_KEY_ID` env variable by default
data/README.md CHANGED
@@ -1,15 +1,17 @@
1
1
  # KMS Encrypted
2
2
 
3
- [KMS](https://aws.amazon.com/kms/) + [attr_encrypted](https://github.com/attr-encrypted/attr_encrypted)
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 a great audit trail to see how data has been accessed
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 both issues and it’s easy to use them together.
12
+ [KMS](https://aws.amazon.com/kms/) addresses all of these issues and it’s easy to use them together.
11
13
 
12
- **Note:** This has not been battle-tested in a production environment, so use with caution
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 a column to store encrypted KMS data keys
32
+ Add columns for the encrypted data and the encrypted KMS data keys
31
33
 
32
34
  ```ruby
33
- add_column :users, :encrypted_kms_key, :string
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, :encrypted_kms_key_phone, :string
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
@@ -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 = "KMS + attr_encrypted"
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|
@@ -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
- key_column = "encrypted_#{key_method}"
23
- context_method = name ? "kms_encryption_context_#{name}" : "kms_encryption_context"
24
- context = respond_to?(context_method) ? send(context_method) : {}
25
- default_encoding = "m"
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
- unless send(key_column)
28
- resp = KmsEncrypted.kms.generate_data_key(
29
- key_id: key_id,
30
- encryption_context: context,
31
- key_spec: "AES_256"
32
- )
33
- ciphertext = resp.ciphertext_blob
34
- instance_variable_set(instance_var, resp.plaintext)
35
- self.send("#{key_column}=", [resp.ciphertext_blob].pack(default_encoding))
36
- end
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
- unless instance_variable_get(instance_var)
39
- ciphertext = send(key_column).unpack(default_encoding).first
40
- resp = KmsEncrypted.kms.decrypt(
41
- ciphertext_blob: ciphertext,
42
- encryption_context: context
43
- )
44
- instance_variable_set(instance_var, resp.plaintext)
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
 
@@ -1,3 +1,3 @@
1
1
  module KmsEncrypted
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
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.2
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-09-26 00:00:00.000000000 Z
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: KMS + attr_encrypted
163
+ summary: Simple, secure key management for attr_encrypted
163
164
  test_files: []