legion-crypt 0.3.0 → 1.2.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.
data/NOTICE.txt ADDED
@@ -0,0 +1,9 @@
1
+ <Insert Project Name Here>
2
+ Copyright 2020 Optum
3
+
4
+ Project Description:
5
+ ====================
6
+ <Short description of your project>
7
+
8
+ Author(s):
9
+ <List the names and GitHub IDs of the original project authors>
data/README.md CHANGED
@@ -1,3 +1,56 @@
1
- # Legion::Crypt
1
+ Legion::Crypt
2
+ =====
2
3
 
3
- The Legion encryption module
4
+ Legion::Crypt is the class responsible for encryption, managing secrets and connecting with Vault
5
+
6
+ Supported Ruby versions and implementations
7
+ ------------------------------------------------
8
+
9
+ Legion::Crypt should work identically on:
10
+
11
+ * JRuby 9.2+
12
+ * Ruby 2.4+
13
+
14
+
15
+ Installation and Usage
16
+ ------------------------
17
+
18
+ You can verify your installation using this piece of code:
19
+
20
+ ```bash
21
+ gem install legion-crypt
22
+ ```
23
+
24
+ ```ruby
25
+ require 'legion/crypt'
26
+
27
+ Legion::Crypt.start
28
+ Legion::Crypt.encrypt('this is my string')
29
+ Legion::Crypt.decrypt(message)
30
+ ```
31
+
32
+ Settings
33
+ ----------
34
+
35
+ ```json
36
+ {
37
+ "vault": {
38
+ "enabled": false,
39
+ "protocol": "http",
40
+ "address": "localhost",
41
+ "port": 8200,
42
+ "token": null,
43
+ "connected": false
44
+ },
45
+ "cs_encrypt_ready": false,
46
+ "dynamic_keys": true,
47
+ "cluster_secret": null,
48
+ "save_private_key": false,
49
+ "read_private_key": false
50
+ }
51
+ ```
52
+
53
+ Authors
54
+ ----------
55
+
56
+ * [Matthew Iverson](https://github.com/Esity) - current maintainer
data/SECURITY.md ADDED
@@ -0,0 +1,9 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+ | Version | Supported |
5
+ | ------- | ------------------ |
6
+ | 1.x.x | :white_check_mark: |
7
+
8
+ ## Reporting a Vulnerability
9
+ To be added
data/attribution.txt ADDED
@@ -0,0 +1 @@
1
+ Add attributions here.
data/legion-crypt.gemspec CHANGED
@@ -3,37 +3,30 @@
3
3
  require_relative 'lib/legion/crypt/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = 'legion-crypt'
6
+ spec.name = 'legion-crypt'
7
7
  spec.version = Legion::Crypt::VERSION
8
8
  spec.authors = ['Esity']
9
- spec.email = ['matthewdiverson@gmail.com']
10
-
11
- spec.summary = 'Legion::Vault is used to keep things safe'
12
- spec.description = 'Integrates with Hashicorps vault and other encryption type things'
13
- spec.homepage = 'https://bitbucket.org/legion-io/legion-vault/'
14
- spec.license = 'MIT'
15
- spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
16
-
17
- spec.metadata['homepage_uri'] = spec.homepage
18
- spec.metadata['source_code_uri'] = 'https://bitbucket.org/legion-io/legion/'
19
- spec.metadata['changelog_uri'] = 'https://bitbucket.org/legion-io/legion/src/master/CHANGELOG.md'
20
- spec.metadata['wiki_uri'] = 'https://bitbucket.org/legion-io/legion-crypt/wiki'
21
- spec.metadata['bug_tracker_uri'] = 'https://bitbucket.org/legion-io/legion-crypt/issues'
22
-
23
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
- end
9
+ spec.email = %w[matthewdiverson@gmail.com ruby@optum.com]
10
+ spec.summary = 'Handles requests for encrypt, decrypting, connecting to Vault, among other things'
11
+ spec.description = 'A gem used by the LegionIO framework for encryption'
12
+ spec.homepage = 'https://github.com/Optum/legion-crypt'
13
+ spec.license = 'Apache-2.0'
26
14
  spec.require_paths = ['lib']
15
+ spec.required_ruby_version = '>= 2.4'
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.test_files = spec.files.select { |p| p =~ %r{^test/.*_test.rb} }
18
+ spec.extra_rdoc_files = %w[README.md LICENSE CHANGELOG.md]
19
+ spec.metadata = {
20
+ 'bug_tracker_uri' => 'https://github.com/Optum/legion-crypt/issues',
21
+ 'changelog_uri' => 'https://github.com/Optum/legion-crypt/src/main/CHANGELOG.md',
22
+ 'documentation_uri' => 'https://github.com/Optum/legion-crypt',
23
+ 'homepage_uri' => 'https://github.com/Optum/LegionIO',
24
+ 'source_code_uri' => 'https://github.com/Optum/legion-crypt',
25
+ 'wiki_uri' => 'https://github.com/Optum/legion-crypt/wiki'
26
+ }
27
27
 
28
28
  spec.add_dependency 'vault', '>= 0.15.0'
29
29
 
30
- spec.add_development_dependency 'legionio'
31
30
  spec.add_development_dependency 'legion-logging'
32
31
  spec.add_development_dependency 'legion-settings'
33
- spec.add_development_dependency 'legion-transport'
34
- spec.add_development_dependency 'rspec'
35
- spec.add_development_dependency 'rspec_junit_formatter'
36
- spec.add_development_dependency 'rubocop'
37
- spec.add_development_dependency 'simplecov', '< 0.18.0'
38
- spec.add_development_dependency 'simplecov_json_formatter'
39
32
  end
data/lib/legion/crypt.rb CHANGED
@@ -1,10 +1,7 @@
1
- # frozen_string_literal: true
2
-
3
1
  require 'openssl'
4
2
  require 'base64'
5
3
  require 'legion/crypt/version'
6
4
  require 'legion/crypt/settings'
7
-
8
5
  require 'legion/crypt/cipher'
9
6
 
10
7
  module Legion
@@ -1,8 +1,11 @@
1
1
  require 'securerandom'
2
+ require 'legion/crypt/cluster_secret'
2
3
 
3
4
  module Legion
4
5
  module Crypt
5
6
  module Cipher
7
+ include Legion::Crypt::ClusterSecret
8
+
6
9
  def encrypt(message)
7
10
  cipher = OpenSSL::Cipher.new('aes-256-cbc')
8
11
  cipher.encrypt
@@ -46,58 +49,6 @@ module Legion
46
49
  OpenSSL::PKey::RSA.new 2048
47
50
  end
48
51
  end
49
-
50
- def cs
51
- @cs ||= Digest::SHA256.digest(fetch_cs)
52
- end
53
-
54
- def fetch_cs # rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity
55
- if Legion::Settings[:crypt][:vault][:read_cluster_secret] && Legion::Settings[:crypt][:vault][:connected] && Legion::Crypt.exist?('crypt') # rubocop:disable Layout/LineLength
56
- Legion::Crypt.get('crypt')[:cluster_secret]
57
- elsif Legion::Settings[:crypt][:cluster_secret].is_a? String
58
- Legion::Settings[:crypt][:cluster_secret]
59
- elsif Legion::Transport::Queue.new('node.crypt', passive: true).consumer_count.zero?
60
- Legion::Settings[:crypt][:cluster_secret] = generate_secure_random
61
- elsif Legion::Transport::Queue.new('node.crypt', passive: true).consumer_count.positive?
62
- require 'legion/transport/messages/request_cluster_secret'
63
- Legion::Logging.info 'Requesting cluster secret via public key'
64
- start = Time.now
65
- Legion::Transport::Messages::RequestClusterSecret.new.publish
66
- sleep_time = 0.001
67
- until !Legion::Settings[:crypt][:cluster_secret].nil? || (Time.now - start) > Legion::Settings[:crypt][:cluster_secret_timeout]
68
- sleep(sleep_time)
69
- sleep_time *= 2 unless sleep_time > 0.5
70
- end
71
-
72
- if Legion::Settings[:crypt][:cluster_secret].nil?
73
- Legion::Logging.warn 'Cluster secret is still nil'
74
- else
75
- Legion::Logging.info "Received cluster secret in #{((Time.new - start) * 1000.0).round}ms"
76
- end
77
- end
78
- rescue StandardError => e
79
- Legion::Logging.error(e.message)
80
- Legion::Logging.error(e.backtrace)
81
- ensure
82
- Legion::Settings[:crypt][:cluster_secret] = generate_secure_random unless Legion::Settings[:crypt].key? :cluster_secret
83
- nil if Legion::Settings[:crypt][:cluster_secret].nil?
84
-
85
- Legion::Settings[:crypt][:cs_encrypt_ready] = true
86
- push_cs_to_vault if Legion::Settings[:crypt][:vault][:push_cs_to_vault]
87
-
88
- return Legion::Settings[:crypt][:cluster_secret] # rubocop:disable Lint/EnsureReturn
89
- end
90
-
91
- def push_cs_to_vault
92
- return false unless Legion::Settings[:crypt][:vault][:connected] && Legion::Settings[:crypt][:cluster_secret]
93
-
94
- Legion::Logging.info 'Pushing Cluster Secret to Vault'
95
- Legion::Crypt.write('cluster', secret: Legion::Settings[:crypt][:cluster_secret])
96
- end
97
-
98
- def generate_secure_random
99
- SecureRandom.uuid
100
- end
101
52
  end
102
53
  end
103
54
  end
@@ -0,0 +1,121 @@
1
+ require 'securerandom'
2
+
3
+ module Legion
4
+ module Crypt
5
+ module ClusterSecret
6
+ def find_cluster_secret
7
+ %i[from_settings from_vault from_transport generate_secure_random].each do |method|
8
+ result = send(method)
9
+ next if result.nil?
10
+
11
+ unless validate_hex(result)
12
+ Legion::Logging.warn("Legion::Crypt.#{method} gave a value but it isn't a valid hex")
13
+ next
14
+ end
15
+
16
+ set_cluster_secret(result, method != :from_vault)
17
+ return result
18
+ end
19
+ return unless only_member?
20
+
21
+ key = generate_secure_random
22
+ set_cluster_secret(key)
23
+ key
24
+ end
25
+
26
+ def from_vault
27
+ return nil unless method_defined? :get
28
+ return nil unless Legion::Settings[:crypt][:vault][:read_cluster_secret]
29
+ return nil unless Legion::Settings[:crypt][:vault][:connected]
30
+ return nil unless Legion::Crypt.exist?('crypt')
31
+
32
+ get('crypt')[:cluster_secret]
33
+ rescue StandardError
34
+ nil
35
+ end
36
+
37
+ def from_settings
38
+ Legion::Settings[:crypt][:cluster_secret]
39
+ end
40
+ alias cluster_secret from_settings
41
+
42
+ def from_transport # rubocop:disable Metrics/AbcSize
43
+ return nil unless Legion::Settings[:transport][:connected]
44
+
45
+ require 'legion/transport/messages/request_cluster_secret'
46
+ Legion::Logging.info 'Requesting cluster secret via public key'
47
+ Legion::Logging.warn 'cluster_secret already set but we are requesting a new value' unless from_settings.nil?
48
+ start = Time.now
49
+ Legion::Transport::Messages::RequestClusterSecret.new.publish
50
+ sleep_time = 0.001
51
+ until !Legion::Settings[:crypt][:cluster_secret].nil? || (Time.now - start) > cluster_secret_timeout
52
+ sleep(sleep_time)
53
+ sleep_time *= 2 unless sleep_time > 0.5
54
+ end
55
+
56
+ unless from_settings.nil?
57
+ Legion::Logging.info "Received cluster secret in #{((Time.new - start) * 1000.0).round}ms"
58
+ from_settings
59
+ end
60
+
61
+ Legion::Logging.error 'Cluster secret is still unknown!'
62
+ rescue StandardError => e
63
+ Legion::Logging.error e.message
64
+ Legion::Logging.error e.backtrace[0..10]
65
+ end
66
+
67
+ def force_cluster_secret
68
+ Legion::Settings[:crypt][:force_cluster_secret] || true
69
+ end
70
+
71
+ def settings_push_vault
72
+ Legion::Settings[:crypt][:vault][:push_cs_to_vault] || true
73
+ end
74
+
75
+ def only_member?
76
+ Legion::Transport::Queue.new('node.crypt', passive: true).consumer_count.zero?
77
+ rescue StandardError
78
+ nil
79
+ end
80
+
81
+ def set_cluster_secret(value, push_to_vault = true) # rubocop:disable Style/OptionalBooleanParameter
82
+ raise TypeError unless value.to_i(32).to_s(32) == value.downcase
83
+
84
+ Legion::Settings[:crypt][:cs_encrypt_ready] = true
85
+ push_cs_to_vault if push_to_vault && settings_push_vault
86
+
87
+ Legion::Settings[:crypt][:cluster_secret] = value
88
+ end
89
+
90
+ def push_cs_to_vault
91
+ return false unless Legion::Settings[:crypt][:vault][:connected] && Legion::Settings[:crypt][:cluster_secret]
92
+
93
+ Legion::Logging.info 'Pushing Cluster Secret to Vault'
94
+ Legion::Crypt.write('cluster', secret: Legion::Settings[:crypt][:cluster_secret])
95
+ end
96
+
97
+ def cluster_secret_timeout
98
+ Legion::Settings[:crypt][:cluster_secret_timeout] || 5
99
+ end
100
+
101
+ def secret_length
102
+ Legion::Settings[:crypt][:cluster_lenth] || 32
103
+ end
104
+
105
+ def generate_secure_random(length = secret_length)
106
+ SecureRandom.hex(length)
107
+ end
108
+
109
+ def cs
110
+ @cs ||= Digest::SHA256.digest(find_cluster_secret)
111
+ rescue StandardError => e
112
+ Legion::Logging.error e.message
113
+ Legion::Logging.error e.backtrace[0..10]
114
+ end
115
+
116
+ def validate_hex(value, length = secret_length)
117
+ value.to_i(length).to_s(length) == value.downcase
118
+ end
119
+ end
120
+ end
121
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Legion
4
4
  module Crypt
5
- VERSION = '0.3.0'
5
+ VERSION = '1.2.0'
6
6
  end
7
7
  end
data/sourcehawk.yml ADDED
@@ -0,0 +1,4 @@
1
+
2
+ config-locations:
3
+ - https://raw.githubusercontent.com/optum/.github/main/sourcehawk.yml
4
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: legion-crypt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-03 00:00:00.000000000 Z
11
+ date: 2021-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: vault
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.15.0
27
- - !ruby/object:Gem::Dependency
28
- name: legionio
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: legion-logging
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -66,125 +52,51 @@ dependencies:
66
52
  - - ">="
67
53
  - !ruby/object:Gem::Version
68
54
  version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: legion-transport
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rspec
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: rspec_junit_formatter
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: rubocop
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: simplecov
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "<"
130
- - !ruby/object:Gem::Version
131
- version: 0.18.0
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "<"
137
- - !ruby/object:Gem::Version
138
- version: 0.18.0
139
- - !ruby/object:Gem::Dependency
140
- name: simplecov_json_formatter
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
- description: Integrates with Hashicorps vault and other encryption type things
55
+ description: A gem used by the LegionIO framework for encryption
154
56
  email:
155
57
  - matthewdiverson@gmail.com
58
+ - ruby@optum.com
156
59
  executables: []
157
60
  extensions: []
158
- extra_rdoc_files: []
61
+ extra_rdoc_files:
62
+ - README.md
63
+ - LICENSE
64
+ - CHANGELOG.md
159
65
  files:
160
- - ".circleci/config.yml"
66
+ - ".github/workflows/rubocop-analysis.yml"
67
+ - ".github/workflows/sourcehawk-scan.yml"
161
68
  - ".gitignore"
162
- - ".rspec"
163
69
  - ".rubocop.yml"
70
+ - CHANGELOG.md
71
+ - CODE_OF_CONDUCT.md
72
+ - CONTRIBUTING.md
164
73
  - Gemfile
165
- - Gemfile.lock
166
- - LICENSE.txt
74
+ - INDIVIDUAL_CONTRIBUTOR_LICENSE.md
75
+ - LICENSE
76
+ - NOTICE.txt
167
77
  - README.md
168
- - Rakefile
169
- - bitbucket-pipelines.yml
78
+ - SECURITY.md
79
+ - attribution.txt
170
80
  - legion-crypt.gemspec
171
81
  - lib/legion/crypt.rb
172
82
  - lib/legion/crypt/cipher.rb
83
+ - lib/legion/crypt/cluster_secret.rb
173
84
  - lib/legion/crypt/settings.rb
174
85
  - lib/legion/crypt/vault.rb
175
86
  - lib/legion/crypt/vault_renewer.rb
176
87
  - lib/legion/crypt/version.rb
177
- - settings/transport.json
178
88
  - sonar-project.properties
179
- homepage: https://bitbucket.org/legion-io/legion-vault/
89
+ - sourcehawk.yml
90
+ homepage: https://github.com/Optum/legion-crypt
180
91
  licenses:
181
- - MIT
92
+ - Apache-2.0
182
93
  metadata:
183
- homepage_uri: https://bitbucket.org/legion-io/legion-vault/
184
- source_code_uri: https://bitbucket.org/legion-io/legion/
185
- changelog_uri: https://bitbucket.org/legion-io/legion/src/master/CHANGELOG.md
186
- wiki_uri: https://bitbucket.org/legion-io/legion-crypt/wiki
187
- bug_tracker_uri: https://bitbucket.org/legion-io/legion-crypt/issues
94
+ bug_tracker_uri: https://github.com/Optum/legion-crypt/issues
95
+ changelog_uri: https://github.com/Optum/legion-crypt/src/main/CHANGELOG.md
96
+ documentation_uri: https://github.com/Optum/legion-crypt
97
+ homepage_uri: https://github.com/Optum/LegionIO
98
+ source_code_uri: https://github.com/Optum/legion-crypt
99
+ wiki_uri: https://github.com/Optum/legion-crypt/wiki
188
100
  post_install_message:
189
101
  rdoc_options: []
190
102
  require_paths:
@@ -193,15 +105,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
193
105
  requirements:
194
106
  - - ">="
195
107
  - !ruby/object:Gem::Version
196
- version: 2.5.0
108
+ version: '2.4'
197
109
  required_rubygems_version: !ruby/object:Gem::Requirement
198
110
  requirements:
199
111
  - - ">="
200
112
  - !ruby/object:Gem::Version
201
113
  version: '0'
202
114
  requirements: []
203
- rubygems_version: 3.2.6
115
+ rubygems_version: 3.1.6
204
116
  signing_key:
205
117
  specification_version: 4
206
- summary: Legion::Vault is used to keep things safe
118
+ summary: Handles requests for encrypt, decrypting, connecting to Vault, among other
119
+ things
207
120
  test_files: []