legion-crypt 0.3.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: []