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 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: []