kms_encrypted 1.7.0 → 1.8.0
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 +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +19 -14
- data/lib/kms_encrypted/box.rb +11 -4
- data/lib/kms_encrypted/client.rb +3 -2
- data/lib/kms_encrypted/clients/aws.rb +6 -2
- data/lib/kms_encrypted/clients/base.rb +2 -1
- data/lib/kms_encrypted/clients/google.rb +10 -4
- data/lib/kms_encrypted/clients/vault.rb +6 -2
- data/lib/kms_encrypted/database.rb +8 -2
- data/lib/kms_encrypted/model.rb +3 -2
- data/lib/kms_encrypted/version.rb +1 -1
- data/lib/kms_encrypted.rb +2 -0
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff4007985837815789e565e18c75fa56cf140d9fe80de15116da853f9ac97b8a
|
4
|
+
data.tar.gz: d7107117b2b91d20e30bb3fae1ccb56f1c488b47e9be336db43dd76bef62c92d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36c756e49dabdce4f82b48d75bef9fceb8fbb91c2fc90b6137f9869d61d113464a9e10ff3db0ccd24a882b1746c19821113d64b23f3a9b5f27ecdd36f3c980c2
|
7
|
+
data.tar.gz: 94140b294489883bbb558a0f15d15c170193398ea0b629d7bf45d606b7de227d43afa6822c08490b388c8d4869016a009b58bc4f7ef1cd10c83ceffe9347e803
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -10,7 +10,7 @@ With KMS Encrypted:
|
|
10
10
|
- Decryption can be disabled if an attack is detected
|
11
11
|
- It’s easy to rotate keys
|
12
12
|
|
13
|
-
Supports [AWS KMS](https://aws.amazon.com/kms/), [Google Cloud KMS](https://cloud.google.com/kms/),
|
13
|
+
Supports [AWS KMS](https://aws.amazon.com/kms/), [Google Cloud KMS](https://cloud.google.com/kms/), [Vault](https://developer.hashicorp.com/vault), and [OpenBao](https://openbao.org/)
|
14
14
|
|
15
15
|
Check out [this post](https://ankane.org/sensitive-data-rails) for more info on securing sensitive data with Rails
|
16
16
|
|
@@ -36,7 +36,7 @@ And follow the instructions for your key management service:
|
|
36
36
|
|
37
37
|
- [AWS KMS](#aws-kms)
|
38
38
|
- [Google Cloud KMS](#google-cloud-kms)
|
39
|
-
- [Vault](#vault)
|
39
|
+
- [Vault and OpenBao](#vault-and-openbao)
|
40
40
|
|
41
41
|
### AWS KMS
|
42
42
|
|
@@ -78,7 +78,7 @@ Create a [KMS key ring and key](https://console.cloud.google.com/iam-admin/kms)
|
|
78
78
|
KMS_KEY_ID=projects/my-project/locations/global/keyRings/my-key-ring/cryptoKeys/my-key
|
79
79
|
```
|
80
80
|
|
81
|
-
### Vault
|
81
|
+
### Vault and OpenBao
|
82
82
|
|
83
83
|
Add this line to your application’s Gemfile:
|
84
84
|
|
@@ -86,19 +86,23 @@ Add this line to your application’s Gemfile:
|
|
86
86
|
gem "vault"
|
87
87
|
```
|
88
88
|
|
89
|
-
Enable the [
|
89
|
+
Enable the transit secrets engine for [Vault](https://developer.hashicorp.com/vault/docs/secrets/transit) or [OpenBao](https://openbao.org/docs/secrets/transit/)
|
90
90
|
|
91
91
|
```sh
|
92
92
|
vault secrets enable transit
|
93
|
+
# or
|
94
|
+
bao secrets enable transit
|
93
95
|
```
|
94
96
|
|
95
97
|
And create a key
|
96
98
|
|
97
99
|
```sh
|
98
100
|
vault write -f transit/keys/my-key derived=true
|
101
|
+
# or
|
102
|
+
bao write -f transit/keys/my-key derived=true
|
99
103
|
```
|
100
104
|
|
101
|
-
Set it in your environment along with your
|
105
|
+
Set it in your environment along with your credentials ([dotenv](https://github.com/bkeepers/dotenv) is great for this)
|
102
106
|
|
103
107
|
```sh
|
104
108
|
KMS_KEY_ID=vault/my-key
|
@@ -218,11 +222,11 @@ You should also use other tools to detect breaches, like an [IDS](https://www.al
|
|
218
222
|
|
219
223
|
Follow the [instructions here](https://cloud.google.com/kms/docs/logging) to set up data access logging. There is not currently a way to see what data is being decrypted, since the additional authenticated data is not logged. For this reason, we recommend another KMS provider.
|
220
224
|
|
221
|
-
### Vault
|
225
|
+
### Vault and OpenBao
|
222
226
|
|
223
|
-
Follow the
|
227
|
+
Follow the instructions for [Vault](https://developer.hashicorp.com/vault/docs/audit) or [OpenBao](https://openbao.org/docs/audit/) to set up data access logging.
|
224
228
|
|
225
|
-
**Note:** Vault will only verify this value if `derived` was set to true when creating the key. If this is not done, the context cannot be trusted.
|
229
|
+
**Note:** Vault and OpenBao will only verify this value if `derived` was set to true when creating the key. If this is not done, the context cannot be trusted.
|
226
230
|
|
227
231
|
Context will show up hashed in the audit logs. To get the hash for a record, use:
|
228
232
|
|
@@ -289,7 +293,7 @@ To decrypt the data, use an IAM policy with:
|
|
289
293
|
|
290
294
|
todo: document
|
291
295
|
|
292
|
-
### Vault
|
296
|
+
### Vault and OpenBao
|
293
297
|
|
294
298
|
To encrypt the data, use a policy with:
|
295
299
|
|
@@ -313,12 +317,16 @@ Apply a policy with:
|
|
313
317
|
|
314
318
|
```sh
|
315
319
|
vault policy write encrypt encrypt.hcl
|
320
|
+
# or
|
321
|
+
bao policy write encrypt encrypt.hcl
|
316
322
|
```
|
317
323
|
|
318
324
|
And create a token with specific policies with:
|
319
325
|
|
320
326
|
```sh
|
321
327
|
vault token create -policy=encrypt -policy=decrypt -no-default-policy
|
328
|
+
# or
|
329
|
+
bao token create -policy=encrypt -policy=decrypt -no-default-policy
|
322
330
|
```
|
323
331
|
|
324
332
|
## Testing
|
@@ -341,11 +349,8 @@ Key management services allow you to rotate the master key without any code chan
|
|
341
349
|
|
342
350
|
- For AWS KMS, you can use [automatic key rotation](https://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html)
|
343
351
|
- For Google Cloud, use the Google Cloud Console or API
|
344
|
-
- For Vault, use
|
345
|
-
|
346
|
-
```sh
|
347
|
-
vault write -f transit/keys/my-key/rotate
|
348
|
-
```
|
352
|
+
- For Vault, use `vault write -f transit/keys/my-key/rotate`
|
353
|
+
- For OpenBao, use `bao write -f transit/keys/my-key/rotate`
|
349
354
|
|
350
355
|
New data will be encrypted with the new master key version. To encrypt existing data with new master key version, run:
|
351
356
|
|
data/lib/kms_encrypted/box.rb
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
module KmsEncrypted
|
2
2
|
class Box
|
3
|
-
attr_reader :key_id, :version, :previous_versions
|
3
|
+
attr_reader :key_id, :version, :previous_versions, :client
|
4
4
|
|
5
|
-
def initialize(key_id: nil, version: nil, previous_versions: nil)
|
5
|
+
def initialize(key_id: nil, version: nil, previous_versions: nil, client: nil)
|
6
6
|
@key_id = key_id || KmsEncrypted.key_id
|
7
7
|
@version = version || 1
|
8
8
|
@previous_versions = previous_versions || {}
|
9
|
+
@client = client
|
9
10
|
end
|
10
11
|
|
11
12
|
def encrypt(plaintext, context: nil)
|
12
13
|
context = version_context(context, version)
|
13
14
|
key_id = version_key_id(version)
|
14
|
-
ciphertext = KmsEncrypted::Client.new(key_id: key_id, data_key: true).encrypt(plaintext, context: context)
|
15
|
+
ciphertext = KmsEncrypted::Client.new(key_id: key_id, data_key: true, client: client).encrypt(plaintext, context: context)
|
15
16
|
"v#{version}:#{encode64(ciphertext)}"
|
16
17
|
end
|
17
18
|
|
@@ -43,11 +44,13 @@ module KmsEncrypted
|
|
43
44
|
key_id ||= version_key_id(version)
|
44
45
|
ciphertext = decode64(ciphertext)
|
45
46
|
context = version_context(context, version)
|
47
|
+
client = version_client(version)
|
46
48
|
|
47
49
|
KmsEncrypted::Client.new(
|
48
50
|
key_id: key_id,
|
49
51
|
data_key: true,
|
50
|
-
legacy_context: legacy_context
|
52
|
+
legacy_context: legacy_context,
|
53
|
+
client: client
|
51
54
|
).decrypt(ciphertext, context: context)
|
52
55
|
end
|
53
56
|
|
@@ -68,6 +71,10 @@ module KmsEncrypted
|
|
68
71
|
key_id
|
69
72
|
end
|
70
73
|
|
74
|
+
def version_client(version)
|
75
|
+
previous_versions.dig(version, :client) || self.client
|
76
|
+
end
|
77
|
+
|
71
78
|
def version_context(context, version)
|
72
79
|
if context.respond_to?(:call)
|
73
80
|
if context.arity == 0
|
data/lib/kms_encrypted/client.rb
CHANGED
@@ -2,10 +2,11 @@ module KmsEncrypted
|
|
2
2
|
class Client
|
3
3
|
attr_reader :key_id, :data_key
|
4
4
|
|
5
|
-
def initialize(key_id: nil, legacy_context: false, data_key: false)
|
5
|
+
def initialize(key_id: nil, legacy_context: false, data_key: false, client: nil)
|
6
6
|
@key_id = key_id || KmsEncrypted.key_id
|
7
7
|
@legacy_context = legacy_context
|
8
8
|
@data_key = data_key
|
9
|
+
@service_client = client
|
9
10
|
end
|
10
11
|
|
11
12
|
def encrypt(plaintext, context: nil)
|
@@ -60,7 +61,7 @@ module KmsEncrypted
|
|
60
61
|
KmsEncrypted::Clients::Aws
|
61
62
|
end
|
62
63
|
|
63
|
-
klass.new(key_id: key_id, legacy_context: @legacy_context)
|
64
|
+
klass.new(key_id: key_id, legacy_context: @legacy_context, client: @service_client)
|
64
65
|
end
|
65
66
|
end
|
66
67
|
end
|
@@ -8,7 +8,7 @@ module KmsEncrypted
|
|
8
8
|
}
|
9
9
|
options[:encryption_context] = generate_context(context) if context
|
10
10
|
|
11
|
-
|
11
|
+
client.encrypt(options).ciphertext_blob
|
12
12
|
end
|
13
13
|
|
14
14
|
def decrypt(ciphertext, context: nil)
|
@@ -18,7 +18,7 @@ module KmsEncrypted
|
|
18
18
|
options[:encryption_context] = generate_context(context) if context
|
19
19
|
|
20
20
|
begin
|
21
|
-
|
21
|
+
client.decrypt(options).plaintext
|
22
22
|
rescue ::Aws::KMS::Errors::InvalidCiphertextException
|
23
23
|
decryption_failed!
|
24
24
|
end
|
@@ -26,6 +26,10 @@ module KmsEncrypted
|
|
26
26
|
|
27
27
|
private
|
28
28
|
|
29
|
+
def client
|
30
|
+
@client ||= KmsEncrypted.aws_client
|
31
|
+
end
|
32
|
+
|
29
33
|
# make integers strings for convenience
|
30
34
|
def generate_context(context)
|
31
35
|
raise ArgumentError, "Context must be a hash" unless context.is_a?(Hash)
|
@@ -3,9 +3,10 @@ module KmsEncrypted
|
|
3
3
|
class Base
|
4
4
|
attr_reader :key_id
|
5
5
|
|
6
|
-
def initialize(key_id: nil, legacy_context: false)
|
6
|
+
def initialize(key_id: nil, legacy_context: false, client: nil)
|
7
7
|
@key_id = key_id
|
8
8
|
@legacy_context = legacy_context
|
9
|
+
@client = client
|
9
10
|
end
|
10
11
|
|
11
12
|
protected
|
@@ -10,9 +10,9 @@ module KmsEncrypted
|
|
10
10
|
options[:additional_authenticated_data] = generate_context(context) if context
|
11
11
|
|
12
12
|
# ensure namespace gets loaded
|
13
|
-
client =
|
13
|
+
client = self.client
|
14
14
|
|
15
|
-
if defined?(::Google::Apis::CloudkmsV1::CloudKMSService) &&
|
15
|
+
if defined?(::Google::Apis::CloudkmsV1::CloudKMSService) && client.is_a?(::Google::Apis::CloudkmsV1::CloudKMSService)
|
16
16
|
request = ::Google::Apis::CloudkmsV1::EncryptRequest.new(**options)
|
17
17
|
response = client.encrypt_crypto_key(key_id, request)
|
18
18
|
@last_key_version = response.name
|
@@ -32,9 +32,9 @@ module KmsEncrypted
|
|
32
32
|
options[:additional_authenticated_data] = generate_context(context) if context
|
33
33
|
|
34
34
|
# ensure namespace gets loaded
|
35
|
-
client =
|
35
|
+
client = self.client
|
36
36
|
|
37
|
-
if defined?(::Google::Apis::CloudkmsV1::CloudKMSService) &&
|
37
|
+
if defined?(::Google::Apis::CloudkmsV1::CloudKMSService) && client.is_a?(::Google::Apis::CloudkmsV1::CloudKMSService)
|
38
38
|
request = ::Google::Apis::CloudkmsV1::DecryptRequest.new(**options)
|
39
39
|
begin
|
40
40
|
client.decrypt_crypto_key(key_id, request).plaintext
|
@@ -52,6 +52,12 @@ module KmsEncrypted
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def client
|
59
|
+
@client ||= KmsEncrypted.google_client
|
60
|
+
end
|
55
61
|
end
|
56
62
|
end
|
57
63
|
end
|
@@ -7,7 +7,7 @@ module KmsEncrypted
|
|
7
7
|
}
|
8
8
|
options[:context] = generate_context(context) if context
|
9
9
|
|
10
|
-
response =
|
10
|
+
response = client.logical.write(
|
11
11
|
"transit/encrypt/#{key_id.sub("vault/", "")}",
|
12
12
|
options
|
13
13
|
)
|
@@ -23,7 +23,7 @@ module KmsEncrypted
|
|
23
23
|
|
24
24
|
response =
|
25
25
|
begin
|
26
|
-
|
26
|
+
client.logical.write(
|
27
27
|
"transit/decrypt/#{key_id.sub("vault/", "")}",
|
28
28
|
options
|
29
29
|
)
|
@@ -42,6 +42,10 @@ module KmsEncrypted
|
|
42
42
|
|
43
43
|
private
|
44
44
|
|
45
|
+
def client
|
46
|
+
@client ||= KmsEncrypted.vault_client
|
47
|
+
end
|
48
|
+
|
45
49
|
# turn hash into json
|
46
50
|
def generate_context(context)
|
47
51
|
Base64.encode64(super)
|
@@ -20,6 +20,10 @@ module KmsEncrypted
|
|
20
20
|
@previous_versions ||= evaluate_option(:previous_versions)
|
21
21
|
end
|
22
22
|
|
23
|
+
def client
|
24
|
+
@client ||= evaluate_option(:client)
|
25
|
+
end
|
26
|
+
|
23
27
|
def context(version)
|
24
28
|
name = options[:name]
|
25
29
|
context_method = name ? "kms_encryption_context_#{name}" : "kms_encryption_context"
|
@@ -36,7 +40,8 @@ module KmsEncrypted
|
|
36
40
|
KmsEncrypted::Box.new(
|
37
41
|
key_id: key_id,
|
38
42
|
version: version,
|
39
|
-
previous_versions: previous_versions
|
43
|
+
previous_versions: previous_versions,
|
44
|
+
client: client
|
40
45
|
).encrypt(plaintext, context: context)
|
41
46
|
end
|
42
47
|
|
@@ -49,7 +54,8 @@ module KmsEncrypted
|
|
49
54
|
KmsEncrypted::Box.new(
|
50
55
|
key_id: key_id,
|
51
56
|
version: version,
|
52
|
-
previous_versions: previous_versions
|
57
|
+
previous_versions: previous_versions,
|
58
|
+
client: client
|
53
59
|
).decrypt(ciphertext, context: context)
|
54
60
|
end
|
55
61
|
|
data/lib/kms_encrypted/model.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module KmsEncrypted
|
2
2
|
module Model
|
3
|
-
def has_kms_key(name: nil, key_id: nil, eager_encrypt: false, version: 1, previous_versions: nil, upgrade_context: false)
|
3
|
+
def has_kms_key(name: nil, key_id: nil, eager_encrypt: false, version: 1, previous_versions: nil, upgrade_context: false, client: nil)
|
4
4
|
key_id ||= KmsEncrypted.key_id
|
5
5
|
|
6
6
|
key_method = name ? "kms_key_#{name}" : "kms_key"
|
@@ -28,7 +28,8 @@ module KmsEncrypted
|
|
28
28
|
name: name,
|
29
29
|
version: version,
|
30
30
|
previous_versions: previous_versions,
|
31
|
-
upgrade_context: upgrade_context
|
31
|
+
upgrade_context: upgrade_context,
|
32
|
+
client: client
|
32
33
|
}
|
33
34
|
|
34
35
|
if @kms_keys.size == 1
|
data/lib/kms_encrypted.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kms_encrypted
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: activesupport
|
@@ -15,14 +15,14 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - ">="
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: '7.
|
18
|
+
version: '7.2'
|
19
19
|
type: :runtime
|
20
20
|
prerelease: false
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version: '7.
|
25
|
+
version: '7.2'
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: base64
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
@@ -75,7 +75,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
75
75
|
- !ruby/object:Gem::Version
|
76
76
|
version: '0'
|
77
77
|
requirements: []
|
78
|
-
rubygems_version: 3.6.
|
78
|
+
rubygems_version: 3.6.9
|
79
79
|
specification_version: 4
|
80
80
|
summary: Simple, secure key management for Lockbox and attr_encrypted
|
81
81
|
test_files: []
|