sidekiq-field-encryptor 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/README.md +19 -2
- data/lib/sidekiq-field-encryptor/encryptor.rb +23 -4
- data/lib/sidekiq-field-encryptor/version.rb +1 -1
- data/spec/sidekiq-field-encryptor/encryptor_spec.rb +54 -8
- metadata +18 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7b580f10f55bd99cc1b08a0d41157746562b155
|
4
|
+
data.tar.gz: d93bb7059b52325809a24f161c98ec4b705f9323
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73208766812240af540b2fac93f98f4d585ffb0065dda731dbd47be7b01ee4d4b8eab048925c2254c465ce46ecaf0a775ffb6a6e010c1b52d429f04119992f02
|
7
|
+
data.tar.gz: 04f77a80f08b85d429c804a38b2244a4f5f564cd6a4a5e7704fb9727796261d7280a0fc47f80a4d3f593d9a6940be13f9b397c6d4f930a38eb294440012aa048
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
[![Build Status](https://travis-ci.org/aptible/sidekiq-field-encryptor.png?branch=master)](https://travis-ci.org/aptible/sidekiq-field-encryptor)
|
5
5
|
[![Dependency Status](https://gemnasium.com/aptible/sidekiq-field-encryptor.png)](https://gemnasium.com/aptible/sidekiq-field-encryptor)
|
6
6
|
|
7
|
-
|
7
|
+
This is a utility which is intended to be used for encrypting sensitive data in Sidekiq jobs. The data is encrypted before sending it to Redis, and decrypted right before the Sidekiq job is executed.
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
@@ -16,7 +16,24 @@ And then run `bundle install`.
|
|
16
16
|
|
17
17
|
## Usage
|
18
18
|
|
19
|
-
|
19
|
+
This middleware configures encryption of any fields that can contain sensitive
|
20
|
+
information. Keys in the hash are Sidekiq job classes and values are hashes
|
21
|
+
that map indices in the args array to either "true" (encrypt the entire arg)
|
22
|
+
or a list of keys (encrypt certain values in a hash argument). For example,
|
23
|
+
the configuration hash:
|
24
|
+
|
25
|
+
{ 'Job::Foo' => { 0 => true, 3 => [ 'secret', 'id' ] } }
|
26
|
+
|
27
|
+
When applied to the Sidekiq job:
|
28
|
+
|
29
|
+
{
|
30
|
+
'class' => 'Job::Foo',
|
31
|
+
'args' => [{'x' => 1}, 'y', 'z', { 'public' => 'a', 'secret' => 'b' }],
|
32
|
+
...
|
33
|
+
}
|
34
|
+
|
35
|
+
Will encrypt the values {'x' => 1} and 'b' when storing the job in Redis and
|
36
|
+
decrypt the values inside the client before the job is executed.
|
20
37
|
|
21
38
|
## Contributing
|
22
39
|
|
@@ -2,28 +2,47 @@ require 'base64'
|
|
2
2
|
require 'encryptor'
|
3
3
|
require 'sidekiq-field-encryptor/version'
|
4
4
|
|
5
|
+
# This middleware configures encryption of any fields that can contain sensitive
|
6
|
+
# information. Keys in the hash are Sidekiq job classes and values are hashes
|
7
|
+
# that map indices in the args array to either "true" (encrypt the entire arg)
|
8
|
+
# or a list of keys (encrypt certain values in a hash argument). For example,
|
9
|
+
# the configuration hash:
|
10
|
+
#
|
11
|
+
# { 'Job::Foo' => { 0 => true, 3 => [ 'secret', 'id' ] } }
|
12
|
+
#
|
13
|
+
# When applied to the Sidekiq job:
|
14
|
+
#
|
15
|
+
# {
|
16
|
+
# 'class' => 'Job::Foo',
|
17
|
+
# 'args' => [{'x' => 1}, 'y', 'z', { 'public' => 'a', 'secret' => 'b' }],
|
18
|
+
# ...
|
19
|
+
# }
|
20
|
+
#
|
21
|
+
# Will encrypt the values {'x' => 1} and 'b' when storing the job in Redis and
|
22
|
+
# decrypt the values inside the client before the job is executed.
|
5
23
|
module SidekiqFieldEncryptor
|
6
24
|
class Base
|
7
25
|
def initialize(options = {})
|
8
26
|
@encryption_key = options[:encryption_key]
|
9
27
|
@encrypted_fields = options[:encrypted_fields] || {}
|
28
|
+
@encryption_algorithm = options[:encryption_algorithm] || 'aes-256-gcm'
|
10
29
|
end
|
11
30
|
|
12
31
|
def assert_key_configured
|
13
|
-
|
32
|
+
raise 'Encryption key not configured' if @encryption_key.nil?
|
14
33
|
end
|
15
34
|
|
16
35
|
def encrypt(value)
|
17
36
|
plaintext = Marshal.dump(value)
|
18
|
-
iv = OpenSSL::Cipher::Cipher.new(
|
19
|
-
args = { key: @encryption_key, iv: iv }
|
37
|
+
iv = OpenSSL::Cipher::Cipher.new(@encryption_algorithm).random_iv
|
38
|
+
args = { key: @encryption_key, iv: iv, algorithm: @encryption_algorithm }
|
20
39
|
ciphertext = ::Encryptor.encrypt(plaintext, **args)
|
21
40
|
[::Base64.encode64(ciphertext), ::Base64.encode64(iv)]
|
22
41
|
end
|
23
42
|
|
24
43
|
def decrypt(encrypted)
|
25
44
|
ciphertext, iv = encrypted.map { |value| ::Base64.decode64(value) }
|
26
|
-
args = { key: @encryption_key, iv: iv }
|
45
|
+
args = { key: @encryption_key, iv: iv, algorithm: @encryption_algorithm }
|
27
46
|
plaintext = ::Encryptor.decrypt(ciphertext, **args)
|
28
47
|
Marshal.load(plaintext)
|
29
48
|
end
|
@@ -12,7 +12,8 @@ describe SidekiqFieldEncryptor::Client do
|
|
12
12
|
end
|
13
13
|
it 'fails when encryption is attempted' do
|
14
14
|
client = SidekiqFieldEncryptor::Client.new(
|
15
|
-
encrypted_fields: { 'FooJob' => { 1 => true } }
|
15
|
+
encrypted_fields: { 'FooJob' => { 1 => true } }
|
16
|
+
)
|
16
17
|
expect { client.call('FooJob', message, nil, nil) {} }
|
17
18
|
.to raise_error('Encryption key not configured')
|
18
19
|
end
|
@@ -22,9 +23,8 @@ describe SidekiqFieldEncryptor::Client do
|
|
22
23
|
subject do
|
23
24
|
SidekiqFieldEncryptor::Client.new(
|
24
25
|
encryption_key: key,
|
25
|
-
encrypted_fields: {
|
26
|
-
|
27
|
-
})
|
26
|
+
encrypted_fields: { 'FooJob' => { 1 => true, 2 => %w(b d) } }
|
27
|
+
)
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'encrypts only fields specified by the encryption config' do
|
@@ -35,6 +35,28 @@ describe SidekiqFieldEncryptor::Client do
|
|
35
35
|
expect(subject.decrypt(message['args'][2]['b'])).to eq('B')
|
36
36
|
end
|
37
37
|
end
|
38
|
+
|
39
|
+
it 'supports setting the encryption algorithm' do
|
40
|
+
key = OpenSSL::Cipher::Cipher.new('aes-128-cbc').random_key
|
41
|
+
fields = { 'FooJob' => { 1 => true, 2 => %w(b d) } }
|
42
|
+
|
43
|
+
ko = SidekiqFieldEncryptor::Client.new(
|
44
|
+
encryption_key: key,
|
45
|
+
encryption_algorithm: 'aes-256-cbc',
|
46
|
+
encrypted_fields: fields
|
47
|
+
)
|
48
|
+
|
49
|
+
ok = SidekiqFieldEncryptor::Client.new(
|
50
|
+
encryption_key: key,
|
51
|
+
encryption_algorithm: 'aes-128-cbc',
|
52
|
+
encrypted_fields: fields
|
53
|
+
)
|
54
|
+
|
55
|
+
expect { ko.call('FooJob', message, nil, nil) {} }
|
56
|
+
.to raise_error(/must be 32 bytes or longer/)
|
57
|
+
|
58
|
+
ok.call('FooJob', message, nil, nil) {}
|
59
|
+
end
|
38
60
|
end
|
39
61
|
|
40
62
|
describe SidekiqFieldEncryptor::Server do
|
@@ -49,7 +71,8 @@ describe SidekiqFieldEncryptor::Server do
|
|
49
71
|
end
|
50
72
|
it 'fails when decryption is attempted' do
|
51
73
|
server = SidekiqFieldEncryptor::Server.new(
|
52
|
-
encrypted_fields: { 'FooJob' => { 1 => true } }
|
74
|
+
encrypted_fields: { 'FooJob' => { 1 => true } }
|
75
|
+
)
|
53
76
|
expect { server.call('FooJob', message, nil) {} }
|
54
77
|
.to raise_error('Encryption key not configured')
|
55
78
|
end
|
@@ -59,9 +82,8 @@ describe SidekiqFieldEncryptor::Server do
|
|
59
82
|
subject do
|
60
83
|
SidekiqFieldEncryptor::Server.new(
|
61
84
|
encryption_key: key,
|
62
|
-
encrypted_fields: {
|
63
|
-
|
64
|
-
})
|
85
|
+
encrypted_fields: { 'FooJob' => { 1 => true, 2 => %w(b d) } }
|
86
|
+
)
|
65
87
|
end
|
66
88
|
|
67
89
|
it 'decrypts all fields specified by the encryption config' do
|
@@ -71,5 +93,29 @@ describe SidekiqFieldEncryptor::Server do
|
|
71
93
|
subject.call('FooJob', message, nil) {}
|
72
94
|
expect(message).to eq(original_message)
|
73
95
|
end
|
96
|
+
|
97
|
+
it 'supports setting the encryption algorithm' do
|
98
|
+
key = OpenSSL::Cipher::Cipher.new('aes-128-cbc').random_key
|
99
|
+
fields = { 'FooJob' => { 1 => true } }
|
100
|
+
|
101
|
+
ko = SidekiqFieldEncryptor::Server.new(
|
102
|
+
encryption_key: key,
|
103
|
+
encryption_algorithm: 'aes-256-cbc',
|
104
|
+
encrypted_fields: fields
|
105
|
+
)
|
106
|
+
|
107
|
+
ok = SidekiqFieldEncryptor::Server.new(
|
108
|
+
encryption_key: key,
|
109
|
+
encryption_algorithm: 'aes-128-cbc',
|
110
|
+
encrypted_fields: fields
|
111
|
+
)
|
112
|
+
|
113
|
+
message['args'][1] = ok.encrypt(message['args'][1])
|
114
|
+
|
115
|
+
expect { ko.call('FooJob', message, nil) {} }
|
116
|
+
.to raise_error(/key must be 32 bytes or longer/)
|
117
|
+
|
118
|
+
ok.call('FooJob', message, nil) {}
|
119
|
+
end
|
74
120
|
end
|
75
121
|
end
|
metadata
CHANGED
@@ -1,83 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-field-encryptor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Blake Pettersson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-12-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: encryptor
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: aptible-tasks
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
description: Selectively encrypt fields in Sidekiq
|
@@ -87,9 +87,9 @@ executables: []
|
|
87
87
|
extensions: []
|
88
88
|
extra_rdoc_files: []
|
89
89
|
files:
|
90
|
-
- .gitignore
|
91
|
-
- .rspec
|
92
|
-
- .travis.yml
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".travis.yml"
|
93
93
|
- Gemfile
|
94
94
|
- LICENSE.md
|
95
95
|
- README.md
|
@@ -110,17 +110,17 @@ require_paths:
|
|
110
110
|
- lib
|
111
111
|
required_ruby_version: !ruby/object:Gem::Requirement
|
112
112
|
requirements:
|
113
|
-
- -
|
113
|
+
- - ">="
|
114
114
|
- !ruby/object:Gem::Version
|
115
115
|
version: '0'
|
116
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
117
|
requirements:
|
118
|
-
- -
|
118
|
+
- - ">="
|
119
119
|
- !ruby/object:Gem::Version
|
120
120
|
version: '0'
|
121
121
|
requirements: []
|
122
122
|
rubyforge_project:
|
123
|
-
rubygems_version: 2.4.5
|
123
|
+
rubygems_version: 2.4.5.1
|
124
124
|
signing_key:
|
125
125
|
specification_version: 4
|
126
126
|
summary: Selectively encrypt fields sent into Sidekiq
|