legion-crypt 1.4.4 → 1.4.5
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 +12 -0
- data/CLAUDE.md +1 -0
- data/README.md +45 -1
- data/lib/legion/crypt/settings.rb +11 -0
- data/lib/legion/crypt/tls.rb +60 -46
- data/lib/legion/crypt/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2e448a5dd1e2c70e43cff0b6512e1b2af1d41f9a2af7b9719495ba5b10c90ec7
|
|
4
|
+
data.tar.gz: 6c270665c5a185baa844e5b7e80af9f2ac8922a520748e387a9d10363294061e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bc43cab1939dee1cd1d6c28a07a2766953af52fc30230375d47e23e289f53beaf3a2be47d98c549bd9098c545d6dd540faa8a87143bb678429265a96b55d96cf
|
|
7
|
+
data.tar.gz: 1813d049d59f5bb81baeef8f10fb2e9f68d7540c8fb4858a75f2f40d881eb7b101a42ce4f89161a38ef14122da0e53e1cf0d2009716d7411ba16c0a77902504c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Legion::Crypt
|
|
2
2
|
|
|
3
|
+
## [1.4.5] - 2026-03-20
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- Refactored `Legion::Crypt::TLS` to standard `resolve` pattern: pure config normalizer with port auto-detect, vault URI resolution, legacy key migration, and three verification levels (none/peer/mutual)
|
|
7
|
+
- Removed consumer-specific `bunny_options` and `sequel_options` methods (moved to consuming gems)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- `TLS.resolve(tls_config, port:)` — standard TLS config resolver
|
|
11
|
+
- `TLS.migrate_legacy(config)` — backwards-compat mapping for transport's old TLS keys
|
|
12
|
+
- `TLS::TLS_PORTS` — known TLS port auto-detection map (5671, 6380, 11207)
|
|
13
|
+
- Default `tls:` settings block in `Legion::Crypt::Settings`
|
|
14
|
+
|
|
3
15
|
## [1.4.4] - 2026-03-18
|
|
4
16
|
|
|
5
17
|
### Added
|
data/CLAUDE.md
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
Handles encryption, decryption, secrets management, JWT token management, and HashiCorp Vault connectivity for the LegionIO framework. Provides AES-256-CBC message encryption, RSA key pair generation, cluster secret management, JWT issue/verify operations, and Vault token lifecycle management.
|
|
9
9
|
|
|
10
10
|
**GitHub**: https://github.com/LegionIO/legion-crypt
|
|
11
|
+
**Version**: 1.4.4
|
|
11
12
|
**License**: Apache-2.0
|
|
12
13
|
|
|
13
14
|
## Architecture
|
data/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# legion-crypt
|
|
2
2
|
|
|
3
|
-
Encryption, secrets management, JWT token management, and HashiCorp Vault integration for the [LegionIO](https://github.com/LegionIO/LegionIO) framework. Provides AES-256-CBC message encryption, RSA key pair generation, cluster secret management, JWT issue/verify operations,
|
|
3
|
+
Encryption, secrets management, JWT token management, and HashiCorp Vault integration for the [LegionIO](https://github.com/LegionIO/LegionIO) framework. Provides AES-256-CBC message encryption, RSA key pair generation, cluster secret management, JWT issue/verify operations, Vault token lifecycle management, and multi-cluster Vault connectivity.
|
|
4
|
+
|
|
5
|
+
**Version**: 1.4.4
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
@@ -146,6 +148,48 @@ Both `username` and `password` come from a single Vault read — one lease, one
|
|
|
146
148
|
|
|
147
149
|
Lease names are stable across environments. The actual Vault paths are deployment-specific config.
|
|
148
150
|
|
|
151
|
+
## Multi-Cluster Vault
|
|
152
|
+
|
|
153
|
+
`VaultCluster` supports connecting to multiple Vault clusters simultaneously. Each cluster has its own `::Vault::Client` instance.
|
|
154
|
+
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"crypt": {
|
|
158
|
+
"vault": {
|
|
159
|
+
"default": "primary",
|
|
160
|
+
"clusters": {
|
|
161
|
+
"primary": {
|
|
162
|
+
"protocol": "https",
|
|
163
|
+
"address": "vault.example.com",
|
|
164
|
+
"port": 8200,
|
|
165
|
+
"namespace": "my-namespace",
|
|
166
|
+
"auth_method": "ldap"
|
|
167
|
+
},
|
|
168
|
+
"secondary": {
|
|
169
|
+
"protocol": "https",
|
|
170
|
+
"address": "vault2.example.com",
|
|
171
|
+
"port": 8200,
|
|
172
|
+
"auth_method": "ldap"
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
```ruby
|
|
181
|
+
# Authenticate to all LDAP-configured clusters at once
|
|
182
|
+
Legion::Crypt.ldap_login_all(username: 'user', password: 'pass')
|
|
183
|
+
|
|
184
|
+
# Read from specific cluster
|
|
185
|
+
Legion::Crypt.read('secret/data/mykey', cluster: :secondary)
|
|
186
|
+
|
|
187
|
+
# Get a Vault client for a specific cluster
|
|
188
|
+
client = Legion::Crypt.vault_client(:primary)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
When `clusters` is empty, the legacy single-cluster path is used (backward compatible).
|
|
192
|
+
|
|
149
193
|
## Requirements
|
|
150
194
|
|
|
151
195
|
- Ruby >= 3.4
|
|
@@ -3,10 +3,21 @@
|
|
|
3
3
|
module Legion
|
|
4
4
|
module Crypt
|
|
5
5
|
module Settings
|
|
6
|
+
def self.tls
|
|
7
|
+
{
|
|
8
|
+
enabled: false,
|
|
9
|
+
verify: 'peer',
|
|
10
|
+
ca: nil,
|
|
11
|
+
cert: nil,
|
|
12
|
+
key: nil
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
|
|
6
16
|
def self.default
|
|
7
17
|
{
|
|
8
18
|
vault: vault,
|
|
9
19
|
jwt: jwt,
|
|
20
|
+
tls: tls,
|
|
10
21
|
cs_encrypt_ready: false,
|
|
11
22
|
dynamic_keys: true,
|
|
12
23
|
cluster_secret: nil,
|
data/lib/legion/crypt/tls.rb
CHANGED
|
@@ -1,78 +1,92 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'openssl'
|
|
4
|
-
|
|
5
3
|
module Legion
|
|
6
4
|
module Crypt
|
|
7
5
|
module TLS
|
|
8
|
-
|
|
6
|
+
TLS_PORTS = {
|
|
7
|
+
5671 => 'amqp',
|
|
8
|
+
6380 => 'redis',
|
|
9
|
+
11_207 => 'memcached'
|
|
10
|
+
}.freeze
|
|
9
11
|
|
|
10
12
|
class << self
|
|
11
|
-
def
|
|
12
|
-
|
|
13
|
-
end
|
|
13
|
+
def resolve(tls_config, port: nil)
|
|
14
|
+
config = symbolize_keys(migrate_legacy(tls_config || {}))
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
ctx.min_version = OpenSSL::SSL::TLS1_2_VERSION
|
|
18
|
-
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
16
|
+
enabled = config[:enabled]
|
|
17
|
+
auto_detected = false
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
if enabled.nil? && port && TLS_PORTS.key?(port.to_i)
|
|
20
|
+
enabled = true
|
|
21
|
+
auto_detected = true
|
|
22
|
+
log_warn("TLS auto-enabled for port #{port}")
|
|
23
|
+
end
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
end
|
|
25
|
+
enabled = false if enabled.nil?
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
verify = normalize_verify(config[:verify])
|
|
28
|
+
ca = resolve_uri(config[:ca])
|
|
29
|
+
cert = resolve_uri(config[:cert])
|
|
30
|
+
key = resolve_uri(config[:key])
|
|
31
|
+
|
|
32
|
+
if verify == :mutual && (cert.nil? || key.nil?)
|
|
33
|
+
log_warn('TLS mutual requested but cert or key missing, downgrading to peer')
|
|
34
|
+
verify = :peer
|
|
35
|
+
end
|
|
29
36
|
|
|
30
37
|
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
enabled: enabled,
|
|
39
|
+
verify: verify,
|
|
40
|
+
ca: ca,
|
|
41
|
+
cert: cert,
|
|
42
|
+
key: key,
|
|
43
|
+
auto_detected: auto_detected
|
|
36
44
|
}
|
|
37
45
|
end
|
|
38
46
|
|
|
39
|
-
def
|
|
40
|
-
|
|
47
|
+
def migrate_legacy(config)
|
|
48
|
+
config = symbolize_keys(config)
|
|
49
|
+
return config unless config.key?(:use_tls) && !config.key?(:enabled)
|
|
41
50
|
|
|
42
51
|
{
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
enabled: config[:use_tls],
|
|
53
|
+
verify: config[:verify_peer] ? 'peer' : 'none',
|
|
54
|
+
ca: config[:ca_certs],
|
|
55
|
+
cert: config[:tls_cert],
|
|
56
|
+
key: config[:tls_key]
|
|
47
57
|
}
|
|
48
58
|
end
|
|
49
59
|
|
|
50
|
-
|
|
51
|
-
settings_dig(:cert_path) || File.join(DEFAULT_CERT_DIR, 'legion.crt')
|
|
52
|
-
end
|
|
60
|
+
private
|
|
53
61
|
|
|
54
|
-
def
|
|
55
|
-
|
|
62
|
+
def symbolize_keys(hash)
|
|
63
|
+
hash.each_with_object({}) { |(k, v), h| h[k.to_sym] = v }
|
|
56
64
|
end
|
|
57
65
|
|
|
58
|
-
def
|
|
59
|
-
|
|
66
|
+
def normalize_verify(value)
|
|
67
|
+
case value.to_s
|
|
68
|
+
when 'none' then :none
|
|
69
|
+
when 'mutual' then :mutual
|
|
70
|
+
else :peer
|
|
71
|
+
end
|
|
60
72
|
end
|
|
61
73
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def settings_dig(*keys)
|
|
65
|
-
return nil unless defined?(Legion::Settings)
|
|
74
|
+
def resolve_uri(value)
|
|
75
|
+
return nil if value.nil?
|
|
66
76
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
77
|
+
if defined?(Legion::Settings::Resolver)
|
|
78
|
+
Legion::Settings::Resolver.resolve_value(value)
|
|
79
|
+
else
|
|
80
|
+
value
|
|
81
|
+
end
|
|
82
|
+
end
|
|
70
83
|
|
|
71
|
-
|
|
84
|
+
def log_warn(msg)
|
|
85
|
+
if defined?(Legion::Logging)
|
|
86
|
+
Legion::Logging.warn(msg)
|
|
87
|
+
else
|
|
88
|
+
warn msg
|
|
72
89
|
end
|
|
73
|
-
result
|
|
74
|
-
rescue StandardError
|
|
75
|
-
nil
|
|
76
90
|
end
|
|
77
91
|
end
|
|
78
92
|
end
|
data/lib/legion/crypt/version.rb
CHANGED