legion-crypt 1.4.28 → 1.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/Gemfile +1 -0
- data/legion-crypt.gemspec +1 -0
- data/lib/legion/crypt/attestation.rb +18 -8
- data/lib/legion/crypt/cert_rotation.rb +54 -42
- data/lib/legion/crypt/cipher.rb +106 -15
- data/lib/legion/crypt/cluster_secret.rb +41 -39
- data/lib/legion/crypt/ed25519.rb +58 -18
- data/lib/legion/crypt/erasure.rb +21 -8
- data/lib/legion/crypt/jwks_client.rb +37 -9
- data/lib/legion/crypt/jwt.rb +75 -31
- data/lib/legion/crypt/kerberos_auth.rb +23 -13
- data/lib/legion/crypt/ldap_auth.rb +12 -4
- data/lib/legion/crypt/lease_manager.rb +126 -73
- data/lib/legion/crypt/mtls.rb +14 -1
- data/lib/legion/crypt/partition_keys.rb +15 -5
- data/lib/legion/crypt/settings.rb +18 -12
- data/lib/legion/crypt/spiffe/identity_helpers.rb +18 -11
- data/lib/legion/crypt/spiffe/svid_rotation.rb +23 -33
- data/lib/legion/crypt/spiffe/workload_api_client.rb +61 -17
- data/lib/legion/crypt/spiffe.rb +18 -4
- data/lib/legion/crypt/tls.rb +14 -10
- data/lib/legion/crypt/token_renewer.rb +29 -26
- data/lib/legion/crypt/vault.rb +57 -45
- data/lib/legion/crypt/vault_cluster.rb +35 -17
- data/lib/legion/crypt/vault_jwt_auth.rb +17 -4
- data/lib/legion/crypt/vault_kerberos_auth.rb +11 -1
- data/lib/legion/crypt/version.rb +1 -1
- data/lib/legion/crypt.rb +69 -32
- data/lib/legion/logging/helper.rb +98 -0
- data/lib/legion/logging.rb +58 -0
- metadata +17 -1
data/lib/legion/crypt/vault.rb
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'legion/logging/helper'
|
|
3
4
|
require 'uri'
|
|
4
5
|
require 'vault'
|
|
5
6
|
|
|
6
7
|
module Legion
|
|
7
8
|
module Crypt
|
|
8
9
|
module Vault
|
|
10
|
+
include Legion::Logging::Helper
|
|
11
|
+
|
|
9
12
|
attr_accessor :sessions
|
|
10
13
|
|
|
11
14
|
def settings
|
|
@@ -16,16 +19,17 @@ module Legion
|
|
|
16
19
|
@sessions = []
|
|
17
20
|
vault_settings = Legion::Settings[:crypt][:vault]
|
|
18
21
|
::Vault.address = resolve_vault_address(vault_settings)
|
|
22
|
+
namespace = vault_settings[:vault_namespace]
|
|
23
|
+
log.info "Vault connection requested address=#{::Vault.address} namespace=#{namespace || 'none'}"
|
|
19
24
|
|
|
20
25
|
Legion::Settings[:crypt][:vault][:token] = ENV['VAULT_DEV_ROOT_TOKEN_ID'] if ENV.key? 'VAULT_DEV_ROOT_TOKEN_ID'
|
|
21
26
|
return nil if Legion::Settings[:crypt][:vault][:token].nil?
|
|
22
27
|
|
|
23
28
|
::Vault.token = Legion::Settings[:crypt][:vault][:token]
|
|
24
|
-
namespace = vault_settings[:vault_namespace]
|
|
25
29
|
::Vault.namespace = namespace if namespace
|
|
26
30
|
if vault_healthy?
|
|
27
31
|
Legion::Settings[:crypt][:vault][:connected] = true
|
|
28
|
-
|
|
32
|
+
log.info "Vault connected at #{::Vault.address} (namespace=#{namespace || 'none'})"
|
|
29
33
|
end
|
|
30
34
|
rescue StandardError => e
|
|
31
35
|
log_vault_connection_error(e)
|
|
@@ -43,10 +47,10 @@ module Legion
|
|
|
43
47
|
raise
|
|
44
48
|
end
|
|
45
49
|
|
|
46
|
-
def read(path, type = 'legion')
|
|
47
|
-
full_path = type.nil? || type.empty? ? "#{type}/#{path}"
|
|
48
|
-
log_read_context(full_path)
|
|
49
|
-
lease = logical_client.read(full_path)
|
|
50
|
+
def read(path, type = 'legion', cluster_name: nil)
|
|
51
|
+
full_path = type.nil? || type.empty? ? path : "#{type}/#{path}"
|
|
52
|
+
log_read_context(full_path, cluster_name: cluster_name)
|
|
53
|
+
lease = logical_client(cluster_name: cluster_name).read(full_path)
|
|
50
54
|
if lease.nil?
|
|
51
55
|
log_vault_debug("Vault read: #{full_path} returned nil")
|
|
52
56
|
return nil
|
|
@@ -57,43 +61,45 @@ module Legion
|
|
|
57
61
|
log_vault_debug("Vault read: #{full_path} returned keys=#{data&.keys&.inspect}")
|
|
58
62
|
unwrap_kv_v2(data, full_path)
|
|
59
63
|
rescue StandardError => e
|
|
60
|
-
|
|
64
|
+
handle_exception(e, level: :error, operation: 'crypt.vault.read', path: full_path)
|
|
61
65
|
raise
|
|
62
66
|
end
|
|
63
67
|
|
|
64
|
-
def get(path)
|
|
65
|
-
|
|
66
|
-
result = kv_client.read(path)
|
|
68
|
+
def get(path, cluster_name: nil)
|
|
69
|
+
log.debug "Vault kv get: path=#{path}"
|
|
70
|
+
result = kv_client(cluster_name: cluster_name).read(path)
|
|
67
71
|
if result.nil?
|
|
68
|
-
|
|
72
|
+
log.debug "Vault kv get: #{path} returned nil"
|
|
69
73
|
return nil
|
|
70
74
|
end
|
|
71
75
|
|
|
72
|
-
|
|
76
|
+
log.debug "Vault kv get: #{path} returned keys=#{result.data&.keys&.inspect}"
|
|
73
77
|
result.data
|
|
74
78
|
rescue StandardError => e
|
|
75
|
-
|
|
79
|
+
handle_exception(e, level: :error, operation: 'crypt.vault.get', path: path)
|
|
76
80
|
raise
|
|
77
81
|
end
|
|
78
82
|
|
|
79
|
-
def write(path, **hash)
|
|
80
|
-
|
|
81
|
-
kv_client.write(path, **hash)
|
|
83
|
+
def write(path, cluster_name: nil, **hash)
|
|
84
|
+
log.info "Vault kv write requested path=#{path}"
|
|
85
|
+
kv_client(cluster_name: cluster_name).write(path, **hash)
|
|
86
|
+
log.info "Vault kv write complete path=#{path}"
|
|
82
87
|
rescue StandardError => e
|
|
83
|
-
|
|
88
|
+
handle_exception(e, level: :error, operation: 'crypt.vault.write', path: path)
|
|
84
89
|
raise
|
|
85
90
|
end
|
|
86
91
|
|
|
87
|
-
def delete(path)
|
|
88
|
-
logical_client.delete(path)
|
|
92
|
+
def delete(path, cluster_name: nil)
|
|
93
|
+
logical_client(cluster_name: cluster_name).delete(path)
|
|
94
|
+
log.info "Vault delete complete path=#{path}"
|
|
89
95
|
{ success: true, path: path }
|
|
90
96
|
rescue StandardError => e
|
|
91
|
-
|
|
97
|
+
handle_exception(e, level: :error, operation: 'crypt.vault.delete', path: path)
|
|
92
98
|
{ success: false, path: path, error: e.message }
|
|
93
99
|
end
|
|
94
100
|
|
|
95
|
-
def exist?(path)
|
|
96
|
-
!kv_client.read_metadata(path).nil?
|
|
101
|
+
def exist?(path, cluster_name: nil)
|
|
102
|
+
!kv_client(cluster_name: cluster_name).read_metadata(path).nil?
|
|
97
103
|
end
|
|
98
104
|
|
|
99
105
|
def add_session(path:)
|
|
@@ -104,7 +110,7 @@ module Legion
|
|
|
104
110
|
def close_sessions
|
|
105
111
|
return if @sessions.nil?
|
|
106
112
|
|
|
107
|
-
|
|
113
|
+
log.info 'Closing all Legion::Crypt vault sessions'
|
|
108
114
|
|
|
109
115
|
@sessions.each do |session|
|
|
110
116
|
close_session(session: session)
|
|
@@ -115,7 +121,7 @@ module Legion
|
|
|
115
121
|
return unless Legion::Settings[:crypt][:vault][:connected]
|
|
116
122
|
return if @renewer.nil?
|
|
117
123
|
|
|
118
|
-
|
|
124
|
+
log.info 'Shutting down Legion::Crypt::Vault::Renewer'
|
|
119
125
|
@renewer.cancel
|
|
120
126
|
end
|
|
121
127
|
|
|
@@ -128,7 +134,7 @@ module Legion
|
|
|
128
134
|
end
|
|
129
135
|
|
|
130
136
|
def renew_sessions(**_opts)
|
|
131
|
-
|
|
137
|
+
log.debug 'Vault renewal cycle start'
|
|
132
138
|
result = if respond_to?(:connected_clusters) && connected_clusters.any?
|
|
133
139
|
renew_cluster_tokens
|
|
134
140
|
else
|
|
@@ -136,15 +142,18 @@ module Legion
|
|
|
136
142
|
renew_session(session: session)
|
|
137
143
|
end
|
|
138
144
|
end
|
|
139
|
-
|
|
145
|
+
log.debug 'Vault renewal cycle complete'
|
|
140
146
|
result
|
|
147
|
+
rescue StandardError => e
|
|
148
|
+
handle_exception(e, level: :error, operation: 'crypt.vault.renew_sessions')
|
|
149
|
+
raise
|
|
141
150
|
end
|
|
142
151
|
|
|
143
152
|
def renew_cluster_tokens
|
|
144
153
|
connected_clusters.each_key do |name|
|
|
145
154
|
client = vault_client(name)
|
|
146
155
|
client.auth_token.renew_self
|
|
147
|
-
|
|
156
|
+
log.info "Vault token renewed for cluster #{name}"
|
|
148
157
|
rescue StandardError => e
|
|
149
158
|
log_vault_error(name, e)
|
|
150
159
|
end
|
|
@@ -156,32 +165,41 @@ module Legion
|
|
|
156
165
|
|
|
157
166
|
private
|
|
158
167
|
|
|
159
|
-
def kv_client
|
|
168
|
+
def kv_client(cluster_name: nil)
|
|
160
169
|
if respond_to?(:connected_clusters) && connected_clusters.any?
|
|
161
|
-
|
|
170
|
+
connected_vault_client(cluster_name).kv(settings[:kv_path])
|
|
162
171
|
else
|
|
163
|
-
|
|
172
|
+
raise ArgumentError, "Vault cluster not connected: #{cluster_name}" if cluster_name
|
|
173
|
+
|
|
174
|
+
::Vault.kv(settings[:kv_path])
|
|
164
175
|
end
|
|
165
176
|
end
|
|
166
177
|
|
|
167
|
-
def logical_client
|
|
178
|
+
def logical_client(cluster_name: nil)
|
|
168
179
|
if respond_to?(:connected_clusters) && connected_clusters.any?
|
|
169
|
-
|
|
180
|
+
connected_vault_client(cluster_name).logical
|
|
170
181
|
else
|
|
182
|
+
raise ArgumentError, "Vault cluster not connected: #{cluster_name}" if cluster_name
|
|
183
|
+
|
|
171
184
|
::Vault.logical
|
|
172
185
|
end
|
|
173
186
|
end
|
|
174
187
|
|
|
175
|
-
def log_read_context(full_path)
|
|
176
|
-
return unless defined?(Legion::Logging)
|
|
177
|
-
|
|
188
|
+
def log_read_context(full_path, cluster_name: nil)
|
|
178
189
|
namespace = if respond_to?(:connected_clusters) && connected_clusters.any?
|
|
179
|
-
client =
|
|
190
|
+
client = connected_vault_client(cluster_name)
|
|
180
191
|
client.respond_to?(:namespace) ? client.namespace : 'n/a'
|
|
181
192
|
else
|
|
182
193
|
'n/a (global client)'
|
|
183
194
|
end
|
|
184
|
-
|
|
195
|
+
log.debug "Vault read: path=#{full_path}, namespace=#{namespace}"
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def connected_vault_client(cluster_name = nil)
|
|
199
|
+
selected_cluster = selected_connected_cluster_name(cluster_name)
|
|
200
|
+
raise ArgumentError, "Vault cluster not connected: #{cluster_name}" if selected_cluster.nil? && cluster_name
|
|
201
|
+
|
|
202
|
+
selected_cluster ? vault_client(selected_cluster) : nil
|
|
185
203
|
end
|
|
186
204
|
|
|
187
205
|
def unwrap_kv_v2(data, full_path)
|
|
@@ -207,17 +225,11 @@ module Legion
|
|
|
207
225
|
end
|
|
208
226
|
|
|
209
227
|
def log_vault_connection_error(error)
|
|
210
|
-
|
|
211
|
-
Legion::Logging.log_exception(error, lex: 'crypt', component_type: :helper)
|
|
212
|
-
elsif defined?(Legion::Logging) && Legion::Logging.respond_to?(:error)
|
|
213
|
-
Legion::Logging.error "Vault connection failed: #{error.class}=#{error.message}\n#{Array(error.backtrace).first(10).join("\n")}"
|
|
214
|
-
else
|
|
215
|
-
warn "Vault connection failed: #{error.class}=#{error.message}"
|
|
216
|
-
end
|
|
228
|
+
handle_exception(error, level: :error, operation: 'crypt.vault.connect_vault', address: ::Vault.address)
|
|
217
229
|
end
|
|
218
230
|
|
|
219
231
|
def log_vault_debug(message)
|
|
220
|
-
|
|
232
|
+
log.debug(message)
|
|
221
233
|
end
|
|
222
234
|
end
|
|
223
235
|
end
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# Ruby 4.0 freezes OpenSSL::SSL::SSLContext::DEFAULT_PARAMS by default.
|
|
4
4
|
# The vault gem (0.18.x) mutates this hash in Vault.setup! — replace it
|
|
5
5
|
# with a mutable dup so the require succeeds on Ruby 4.0+.
|
|
6
|
+
require 'legion/logging/helper'
|
|
6
7
|
require 'openssl'
|
|
7
8
|
if OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.frozen?
|
|
8
9
|
unfrozen = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.dup
|
|
@@ -15,6 +16,8 @@ require 'vault'
|
|
|
15
16
|
module Legion
|
|
16
17
|
module Crypt
|
|
17
18
|
module VaultCluster
|
|
19
|
+
include Legion::Logging::Helper
|
|
20
|
+
|
|
18
21
|
def vault_client(name = nil)
|
|
19
22
|
name = resolve_cluster_name(name)
|
|
20
23
|
@vault_clients ||= {}
|
|
@@ -40,6 +43,7 @@ module Legion
|
|
|
40
43
|
end
|
|
41
44
|
|
|
42
45
|
def connect_all_clusters
|
|
46
|
+
log.info "Vault cluster connect requested configured_clusters=#{clusters.size}"
|
|
43
47
|
log_vault_debug("connect_all_clusters: #{clusters.size} cluster(s) configured")
|
|
44
48
|
results = {}
|
|
45
49
|
clusters.each do |name, config|
|
|
@@ -60,12 +64,13 @@ module Legion
|
|
|
60
64
|
rescue StandardError => e
|
|
61
65
|
config[:connected] = false
|
|
62
66
|
results[name] = false
|
|
63
|
-
log_vault_error(name, e)
|
|
67
|
+
log_vault_error(name, e, operation: 'crypt.vault_cluster.connect_all_clusters')
|
|
64
68
|
end
|
|
65
69
|
|
|
66
70
|
connected = results.select { |_, v| v }
|
|
71
|
+
log.info "Vault cluster connect complete connected=#{connected.size} attempted=#{results.size}"
|
|
67
72
|
log_vault_debug("connect_all_clusters: #{connected.size}/#{results.size} connected")
|
|
68
|
-
|
|
73
|
+
sync_vault_connected(connected.any?)
|
|
69
74
|
results
|
|
70
75
|
end
|
|
71
76
|
|
|
@@ -79,10 +84,27 @@ module Legion
|
|
|
79
84
|
raise
|
|
80
85
|
end
|
|
81
86
|
|
|
82
|
-
def
|
|
87
|
+
def sync_vault_connected(connected)
|
|
83
88
|
return unless defined?(Legion::Settings)
|
|
84
89
|
|
|
85
|
-
Legion::Settings[:crypt][:vault][:connected] =
|
|
90
|
+
Legion::Settings[:crypt][:vault][:connected] = connected
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def selected_connected_cluster_name(name = nil)
|
|
94
|
+
active_clusters = connected_clusters
|
|
95
|
+
return nil if active_clusters.empty?
|
|
96
|
+
|
|
97
|
+
if name
|
|
98
|
+
cluster_name = name.to_sym
|
|
99
|
+
raise ArgumentError, "Vault cluster not connected: #{cluster_name}" unless active_clusters.key?(cluster_name)
|
|
100
|
+
|
|
101
|
+
return cluster_name
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
default_name = vault_settings[:default]&.to_sym
|
|
105
|
+
return default_name if default_name && active_clusters.key?(default_name)
|
|
106
|
+
|
|
107
|
+
active_clusters.keys.first
|
|
86
108
|
end
|
|
87
109
|
|
|
88
110
|
def resolve_cluster_name(name)
|
|
@@ -95,6 +117,7 @@ module Legion
|
|
|
95
117
|
return nil unless config.is_a?(Hash)
|
|
96
118
|
|
|
97
119
|
addr = "#{config[:protocol]}://#{config[:address]}:#{config[:port]}"
|
|
120
|
+
log.info "Building Vault client address=#{addr} namespace=#{config[:namespace].inspect}"
|
|
98
121
|
log_vault_debug("build_vault_client: address=#{addr}")
|
|
99
122
|
client = ::Vault::Client.new(
|
|
100
123
|
address: addr,
|
|
@@ -112,12 +135,8 @@ module Legion
|
|
|
112
135
|
client
|
|
113
136
|
end
|
|
114
137
|
|
|
115
|
-
def log_vault_error(name, error)
|
|
116
|
-
|
|
117
|
-
Legion::Logging.error("Vault cluster #{name}: #{error.message}")
|
|
118
|
-
else
|
|
119
|
-
warn("Vault cluster #{name}: #{error.message}")
|
|
120
|
-
end
|
|
138
|
+
def log_vault_error(name, error, operation: 'crypt.vault_cluster.error')
|
|
139
|
+
handle_exception(error, level: :error, operation: operation, cluster_name: name)
|
|
121
140
|
end
|
|
122
141
|
|
|
123
142
|
def connect_kerberos_cluster(name, config)
|
|
@@ -136,6 +155,7 @@ module Legion
|
|
|
136
155
|
require 'legion/crypt/kerberos_auth'
|
|
137
156
|
client = vault_client(name)
|
|
138
157
|
log_vault_debug("connect_kerberos_cluster[#{name}]: client.namespace=#{client.respond_to?(:namespace) ? client.namespace.inspect : 'n/a'}")
|
|
158
|
+
log.info "Connecting Vault cluster #{name} via Kerberos auth_path=#{auth_path}"
|
|
139
159
|
|
|
140
160
|
result = Legion::Crypt::KerberosAuth.login(
|
|
141
161
|
vault_client: client,
|
|
@@ -152,29 +172,27 @@ module Legion
|
|
|
152
172
|
log_cluster_connected(name, config)
|
|
153
173
|
true
|
|
154
174
|
rescue Legion::Crypt::KerberosAuth::GemMissingError => e
|
|
175
|
+
handle_exception(e, level: :warn, operation: 'crypt.vault_cluster.connect_kerberos_cluster', cluster_name: name)
|
|
155
176
|
log_vault_warn(name, e.message)
|
|
156
177
|
config[:connected] = false
|
|
157
178
|
false
|
|
158
179
|
rescue Legion::Crypt::KerberosAuth::AuthError => e
|
|
180
|
+
handle_exception(e, level: :warn, operation: 'crypt.vault_cluster.connect_kerberos_cluster', cluster_name: name)
|
|
159
181
|
log_vault_warn(name, "Kerberos auth failed: #{e.message}")
|
|
160
182
|
config[:connected] = false
|
|
161
183
|
false
|
|
162
184
|
end
|
|
163
185
|
|
|
164
186
|
def log_cluster_connected(name, config)
|
|
165
|
-
|
|
187
|
+
log.info "Vault cluster connected: #{name} at #{config[:address]}"
|
|
166
188
|
end
|
|
167
189
|
|
|
168
190
|
def log_vault_warn(name, message)
|
|
169
|
-
|
|
170
|
-
Legion::Logging.warn("Vault cluster #{name}: #{message}")
|
|
171
|
-
else
|
|
172
|
-
warn("Vault cluster #{name}: #{message}")
|
|
173
|
-
end
|
|
191
|
+
log.warn("Vault cluster #{name}: #{message}")
|
|
174
192
|
end
|
|
175
193
|
|
|
176
194
|
def log_vault_debug(message)
|
|
177
|
-
|
|
195
|
+
log.debug(message)
|
|
178
196
|
end
|
|
179
197
|
end
|
|
180
198
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'legion/logging/helper'
|
|
4
|
+
|
|
3
5
|
module Legion
|
|
4
6
|
module Crypt
|
|
5
7
|
# Vault JWT auth backend integration.
|
|
@@ -18,6 +20,8 @@ module Legion
|
|
|
18
20
|
|
|
19
21
|
class AuthError < StandardError; end
|
|
20
22
|
|
|
23
|
+
extend Legion::Logging::Helper
|
|
24
|
+
|
|
21
25
|
# Authenticate to Vault using a JWT token.
|
|
22
26
|
# Returns a Vault token string on success.
|
|
23
27
|
#
|
|
@@ -28,6 +32,7 @@ module Legion
|
|
|
28
32
|
def self.login(jwt:, role: DEFAULT_ROLE, auth_path: DEFAULT_AUTH_PATH)
|
|
29
33
|
raise AuthError, 'Vault is not connected' unless vault_connected?
|
|
30
34
|
|
|
35
|
+
log.info "[crypt:vault_jwt] authenticating role=#{role} auth_path=#{auth_path}"
|
|
31
36
|
response = ::Vault.logical.write(
|
|
32
37
|
auth_path,
|
|
33
38
|
role: role,
|
|
@@ -44,11 +49,18 @@ module Legion
|
|
|
44
49
|
metadata: response.auth.metadata
|
|
45
50
|
}
|
|
46
51
|
rescue ::Vault::HTTPClientError => e
|
|
47
|
-
|
|
52
|
+
handle_exception(e, level: :warn, operation: 'crypt.vault_jwt_auth.login', role: role, auth_path: auth_path,
|
|
53
|
+
category: 'client_error')
|
|
48
54
|
raise AuthError, "Vault JWT auth failed: #{e.message}"
|
|
49
55
|
rescue ::Vault::HTTPServerError => e
|
|
50
|
-
|
|
56
|
+
handle_exception(e, level: :warn, operation: 'crypt.vault_jwt_auth.login', role: role, auth_path: auth_path,
|
|
57
|
+
category: 'server_error')
|
|
51
58
|
raise AuthError, "Vault server error during JWT auth: #{e.message}"
|
|
59
|
+
rescue StandardError => e
|
|
60
|
+
handle_exception(e, level: :error, operation: 'crypt.vault_jwt_auth.login', role: role, auth_path: auth_path)
|
|
61
|
+
raise if e.is_a?(AuthError)
|
|
62
|
+
|
|
63
|
+
raise AuthError, "Vault JWT auth failed: #{e.message}"
|
|
52
64
|
end
|
|
53
65
|
|
|
54
66
|
# Authenticate and set the Vault client token for subsequent operations.
|
|
@@ -58,7 +70,7 @@ module Legion
|
|
|
58
70
|
def self.login!(jwt:, role: DEFAULT_ROLE, auth_path: DEFAULT_AUTH_PATH)
|
|
59
71
|
result = login(jwt: jwt, role: role, auth_path: auth_path)
|
|
60
72
|
::Vault.token = result[:token]
|
|
61
|
-
|
|
73
|
+
log.info "[crypt:vault_jwt] authenticated via JWT auth, policies=#{result[:policies].join(',')}"
|
|
62
74
|
result
|
|
63
75
|
end
|
|
64
76
|
|
|
@@ -70,6 +82,7 @@ module Legion
|
|
|
70
82
|
# @param role [String] Vault JWT auth role name
|
|
71
83
|
# @return [Hash] Same as login
|
|
72
84
|
def self.worker_login(worker_id:, owner_msid:, role: DEFAULT_ROLE)
|
|
85
|
+
log.info "[crypt:vault_jwt] worker login requested role=#{role} worker_id=#{worker_id}"
|
|
73
86
|
jwt = Legion::Crypt::JWT.issue(
|
|
74
87
|
{ worker_id: worker_id, sub: owner_msid, scope: 'vault', aud: 'legion' },
|
|
75
88
|
signing_key: Legion::Crypt.cluster_secret,
|
|
@@ -85,7 +98,7 @@ module Legion
|
|
|
85
98
|
defined?(Legion::Settings) &&
|
|
86
99
|
Legion::Settings[:crypt][:vault][:connected] == true
|
|
87
100
|
rescue StandardError => e
|
|
88
|
-
|
|
101
|
+
handle_exception(e, level: :debug, operation: 'crypt.vault_jwt_auth.vault_connected?')
|
|
89
102
|
false
|
|
90
103
|
end
|
|
91
104
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'legion/logging/helper'
|
|
4
|
+
|
|
3
5
|
module Legion
|
|
4
6
|
module Crypt
|
|
5
7
|
module VaultKerberosAuth
|
|
@@ -7,9 +9,12 @@ module Legion
|
|
|
7
9
|
|
|
8
10
|
class AuthError < StandardError; end
|
|
9
11
|
|
|
12
|
+
extend Legion::Logging::Helper
|
|
13
|
+
|
|
10
14
|
def self.login(spnego_token:, auth_path: DEFAULT_AUTH_PATH)
|
|
11
15
|
raise AuthError, 'Vault is not connected' unless vault_connected?
|
|
12
16
|
|
|
17
|
+
log.info "[crypt:vault_kerberos] login requested auth_path=#{auth_path}"
|
|
13
18
|
response = ::Vault.logical.write(auth_path, authorization: "Negotiate #{spnego_token}")
|
|
14
19
|
raise AuthError, 'Vault Kerberos auth returned no auth data' unless response&.auth
|
|
15
20
|
|
|
@@ -21,12 +26,17 @@ module Legion
|
|
|
21
26
|
metadata: response.auth.metadata
|
|
22
27
|
}
|
|
23
28
|
rescue ::Vault::HTTPClientError => e
|
|
29
|
+
handle_exception(e, level: :warn, operation: 'crypt.vault_kerberos_auth.login', auth_path: auth_path)
|
|
24
30
|
raise AuthError, "Vault Kerberos auth failed: #{e.message}"
|
|
31
|
+
rescue StandardError => e
|
|
32
|
+
handle_exception(e, level: :error, operation: 'crypt.vault_kerberos_auth.login', auth_path: auth_path)
|
|
33
|
+
raise
|
|
25
34
|
end
|
|
26
35
|
|
|
27
36
|
def self.login!(spnego_token:, auth_path: DEFAULT_AUTH_PATH)
|
|
28
37
|
result = login(spnego_token: spnego_token, auth_path: auth_path)
|
|
29
38
|
::Vault.token = result[:token]
|
|
39
|
+
log.info "[crypt:vault_kerberos] authenticated via Kerberos auth, policies=#{result[:policies].join(',')}"
|
|
30
40
|
result
|
|
31
41
|
end
|
|
32
42
|
|
|
@@ -34,7 +44,7 @@ module Legion
|
|
|
34
44
|
defined?(::Vault) && defined?(Legion::Settings) &&
|
|
35
45
|
Legion::Settings[:crypt][:vault][:connected] == true
|
|
36
46
|
rescue StandardError => e
|
|
37
|
-
|
|
47
|
+
handle_exception(e, level: :debug, operation: 'crypt.vault_kerberos_auth.vault_connected')
|
|
38
48
|
false
|
|
39
49
|
end
|
|
40
50
|
|