Module: Legion::Crypt::ClusterSecret
Constant Summary
Logging::Helper::CompatLogger
Instance Method Summary
collapse
#handle_exception, #log
Instance Method Details
#cluster_secret_timeout ⇒ Object
116
117
118
|
# File 'lib/legion/crypt/cluster_secret.rb', line 116
def cluster_secret_timeout
Legion::Settings[:crypt][:cluster_secret_timeout] || 5
end
|
#cluster_secret_vault_path ⇒ Object
146
147
148
|
# File 'lib/legion/crypt/cluster_secret.rb', line 146
def cluster_secret_vault_path
'crypt'
end
|
#cs ⇒ Object
128
129
130
131
132
133
|
# File 'lib/legion/crypt/cluster_secret.rb', line 128
def cs
@cs ||= Digest::SHA256.digest(find_cluster_secret)
rescue StandardError => e
handle_exception(e, level: :error, operation: 'crypt.cluster_secret.cs')
nil
end
|
#find_cluster_secret ⇒ Object
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
# File 'lib/legion/crypt/cluster_secret.rb', line 11
def find_cluster_secret
%i[from_settings from_vault from_transport generate_secure_random].each do |method|
result = send(method)
next if result.nil?
unless validate_hex(result)
log.warn("Legion::Crypt.#{method} gave a value but it isn't a valid hex")
next
end
set_cluster_secret(result, method != :from_vault)
return result
end
return unless only_member?
key = generate_secure_random
set_cluster_secret(key)
log.info 'Cluster secret generated locally because this node is the only member'
key
end
|
#force_cluster_secret ⇒ Object
78
79
80
|
# File 'lib/legion/crypt/cluster_secret.rb', line 78
def force_cluster_secret
Legion::Settings[:crypt].fetch(:force_cluster_secret, false)
end
|
#from_settings ⇒ Object
Also known as:
cluster_secret
47
48
49
|
# File 'lib/legion/crypt/cluster_secret.rb', line 47
def from_settings
Legion::Settings[:crypt][:cluster_secret]
end
|
#from_transport ⇒ Object
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
# File 'lib/legion/crypt/cluster_secret.rb', line 52
def from_transport
return nil unless Legion::Settings[:transport][:connected]
require 'legion/transport/messages/request_cluster_secret'
log.info 'Requesting cluster secret via public key'
log.warn 'cluster_secret already set but we are requesting a new value' unless from_settings.nil?
start = Time.now
Legion::Transport::Messages::RequestClusterSecret.new.publish
sleep_time = 0.001
until !Legion::Settings[:crypt][:cluster_secret].nil? || (Time.now - start) > cluster_secret_timeout
sleep(sleep_time)
sleep_time *= 2 unless sleep_time > 0.5
end
unless from_settings.nil?
log.info "Received cluster secret in #{((Time.new - start) * 1000.0).round}ms"
return from_settings
end
log.error 'Cluster secret is still unknown!'
nil
rescue StandardError => e
handle_exception(e, level: :error, operation: 'crypt.cluster_secret.from_transport')
nil
end
|
#from_vault ⇒ Object
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
# File 'lib/legion/crypt/cluster_secret.rb', line 32
def from_vault
return nil unless Legion::Crypt.respond_to?(:get) && Legion::Crypt.respond_to?(:exist?)
return nil unless Legion::Settings[:crypt][:vault][:read_cluster_secret]
return nil unless Legion::Settings[:crypt][:vault][:connected]
return nil unless Legion::Crypt.exist?(cluster_secret_vault_path)
data = Legion::Crypt.get(cluster_secret_vault_path)
return nil unless data.is_a?(Hash)
data[:cluster_secret] || data['cluster_secret']
rescue StandardError => e
handle_exception(e, level: :warn, operation: 'crypt.cluster_secret.from_vault')
nil
end
|
#generate_secure_random(length = secret_length) ⇒ Object
124
125
126
|
# File 'lib/legion/crypt/cluster_secret.rb', line 124
def generate_secure_random(length = secret_length)
SecureRandom.hex(length)
end
|
#only_member? ⇒ Boolean
89
90
91
92
93
94
|
# File 'lib/legion/crypt/cluster_secret.rb', line 89
def only_member?
Legion::Transport::Queue.new('node.crypt', passive: true).consumer_count.zero?
rescue StandardError => e
handle_exception(e, level: :warn, operation: 'crypt.cluster_secret.only_member?')
nil
end
|
#push_cs_to_vault ⇒ Object
106
107
108
109
110
111
112
113
114
|
# File 'lib/legion/crypt/cluster_secret.rb', line 106
def push_cs_to_vault
return false unless Legion::Settings[:crypt][:vault][:connected] && Legion::Settings[:crypt][:cluster_secret]
log.info 'Pushing Cluster Secret to Vault'
Legion::Crypt.write(cluster_secret_vault_path, cluster_secret: Legion::Settings[:crypt][:cluster_secret])
rescue StandardError => e
handle_exception(e, level: :warn, operation: 'crypt.cluster_secret.push_cs_to_vault')
false
end
|
#secret_length ⇒ Object
120
121
122
|
# File 'lib/legion/crypt/cluster_secret.rb', line 120
def secret_length
Legion::Settings[:crypt][:cluster_length] || Legion::Settings[:crypt][:cluster_lenth] || 32
end
|
#set_cluster_secret(value, push_to_vault = true) ⇒ Object
rubocop:disable Style/OptionalBooleanParameter
96
97
98
99
100
101
102
103
104
|
# File 'lib/legion/crypt/cluster_secret.rb', line 96
def set_cluster_secret(value, push_to_vault = true) raise TypeError unless validate_hex(value)
Legion::Settings[:crypt][:cluster_secret] = value
@cs = nil
Legion::Settings[:crypt][:cs_encrypt_ready] = true
push_cs_to_vault if push_to_vault && settings_push_vault
log.info "Cluster secret loaded into settings push_to_vault=#{push_to_vault}"
end
|
#settings_push_vault ⇒ Object
82
83
84
85
86
87
|
# File 'lib/legion/crypt/cluster_secret.rb', line 82
def settings_push_vault
vault_settings = Legion::Settings[:crypt][:vault]
return vault_settings[:push_cluster_secret] unless vault_settings[:push_cluster_secret].nil?
vault_settings.fetch(:push_cs_to_vault, false)
end
|
#validate_hex(value, length = secret_length) ⇒ Object
135
136
137
138
139
140
141
142
143
144
|
# File 'lib/legion/crypt/cluster_secret.rb', line 135
def validate_hex(value, length = secret_length)
return false unless value.is_a?(String)
return false if value.empty?
return false unless value.match?(/\A\h+\z/)
expected_length = length.to_i * 2
return true if expected_length.zero?
value.length == expected_length
end
|