Module: Legion::Crypt::ClusterSecret
Instance Method Summary collapse
- #cluster_secret_timeout ⇒ Object
- #cluster_secret_vault_path ⇒ Object
- #cs ⇒ Object
- #find_cluster_secret ⇒ Object
- #force_cluster_secret ⇒ Object
- #from_settings ⇒ Object (also: #cluster_secret)
- #from_transport ⇒ Object
- #from_vault ⇒ Object
- #generate_secure_random(length = secret_length) ⇒ Object
- #only_member? ⇒ Boolean
- #push_cs_to_vault ⇒ Object
- #secret_length ⇒ Object
-
#set_cluster_secret(value, push_to_vault = true) ⇒ Object
rubocop:disable Style/OptionalBooleanParameter.
- #settings_push_vault ⇒ Object
- #validate_hex(value, length = secret_length) ⇒ Object
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) # rubocop:disable Style/OptionalBooleanParameter 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 |