Class: Legion::Crypt::Spiffe::WorkloadApiClient
- Inherits:
-
Object
- Object
- Legion::Crypt::Spiffe::WorkloadApiClient
- Includes:
- Logging::Helper
- Defined in:
- lib/legion/crypt/spiffe/workload_api_client.rb
Overview
Minimal SPIFFE Workload API client.
The SPIFFE Workload API is served over a Unix domain socket by a local SPIRE agent. The wire protocol is gRPC/HTTP2, but we avoid pulling in a full gRPC stack by implementing just enough of the HTTP/2 framing to send a single unary RPC call and parse a single response.
For environments that cannot make a real SPIRE call (CI, lite mode, no socket present) the client returns a self-signed fallback SVID so that callers never have to special-case the nil case.
Constant Summary collapse
- GRPC_CONTENT_TYPE =
gRPC content-type and method path for the Workload API FetchX509SVID RPC.
'application/grpc'- FETCH_X509_METHOD =
'/spiffe.workload.SpiffeWorkloadAPI/FetchX509SVID'- FETCH_JWT_METHOD =
'/spiffe.workload.SpiffeWorkloadAPI/FetchJWTSVID'- HTTP2_PREFACE =
Handshake + settings frames required to open an HTTP/2 connection.
"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"- HTTP2_SETTINGS_FRAME =
"\x00\x00\x00\x04\x00\x00\x00\x00\x00".b
- CONNECT_TIMEOUT =
5- READ_TIMEOUT =
10
Constants included from Logging::Helper
Instance Method Summary collapse
-
#available? ⇒ Boolean
Returns true when the SPIRE agent socket exists and is reachable.
-
#fetch_jwt_svid(audience:) ⇒ Object
Fetch a JWT SVID from the SPIRE Workload API for the given audience.
-
#fetch_x509_svid ⇒ Object
Fetch an X.509 SVID from the SPIRE Workload API.
-
#initialize(socket_path: nil, trust_domain: nil, allow_x509_fallback: nil) ⇒ WorkloadApiClient
constructor
A new instance of WorkloadApiClient.
Methods included from Logging::Helper
Constructor Details
#initialize(socket_path: nil, trust_domain: nil, allow_x509_fallback: nil) ⇒ WorkloadApiClient
Returns a new instance of WorkloadApiClient.
35 36 37 38 39 |
# File 'lib/legion/crypt/spiffe/workload_api_client.rb', line 35 def initialize(socket_path: nil, trust_domain: nil, allow_x509_fallback: nil) @socket_path = socket_path || Legion::Crypt::Spiffe.socket_path @trust_domain = trust_domain || Legion::Crypt::Spiffe.trust_domain @allow_x509_fallback = allow_x509_fallback.nil? ? Legion::Crypt::Spiffe.allow_x509_fallback? : allow_x509_fallback end |
Instance Method Details
#available? ⇒ Boolean
Returns true when the SPIRE agent socket exists and is reachable.
84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/legion/crypt/spiffe/workload_api_client.rb', line 84 def available? return false unless ::File.exist?(@socket_path) sock = UNIXSocket.new(@socket_path) sock.close true rescue StandardError => e handle_exception(e, level: :debug, operation: 'crypt.spiffe.workload_api_client.available', socket_path: @socket_path) false end |
#fetch_jwt_svid(audience:) ⇒ Object
Fetch a JWT SVID from the SPIRE Workload API for the given audience.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/legion/crypt/spiffe/workload_api_client.rb', line 66 def fetch_jwt_svid(audience:) log.info("[SPIFFE] Fetching JWT SVID from Workload API audience=#{audience}") payload = encode_jwt_request(audience) raw = call_workload_api(FETCH_JWT_METHOD, payload) parse_jwt_svid_response(raw, audience) rescue WorkloadApiError, IOError, Errno::ENOENT, Errno::ECONNREFUSED, Errno::EPIPE => e handle_exception(e, level: :warn, operation: 'crypt.spiffe.workload_api_client.fetch_jwt_svid', socket_path: @socket_path, audience: audience) log.warn("[SPIFFE] JWT SVID fetch failed (#{e.})") raise SvidError, "Failed to fetch JWT SVID for audience '#{audience}': #{e.}" rescue StandardError => e handle_exception(e, level: :error, operation: 'crypt.spiffe.workload_api_client.fetch_jwt_svid', socket_path: @socket_path, audience: audience) log.error("[SPIFFE] JWT SVID fetch failed: #{e.}") raise SvidError, "Failed to fetch JWT SVID for audience '#{audience}': #{e.}" end |
#fetch_x509_svid ⇒ Object
Fetch an X.509 SVID from the SPIRE Workload API. Returns a populated X509Svid struct. Falls back to a self-signed certificate when the Workload API is unavailable.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/legion/crypt/spiffe/workload_api_client.rb', line 44 def fetch_x509_svid log.info("[SPIFFE] Fetching X.509 SVID from Workload API socket=#{@socket_path}") raw = call_workload_api(FETCH_X509_METHOD, '') parse_x509_svid_response(raw) rescue WorkloadApiError, IOError, Errno::ENOENT, Errno::ECONNREFUSED, Errno::EPIPE => e handle_exception(e, level: :warn, operation: 'crypt.spiffe.workload_api_client.fetch_x509_svid', socket_path: @socket_path, fallback: @allow_x509_fallback) unless @allow_x509_fallback log.error("[SPIFFE] Workload API unavailable (#{e.}); X.509 fallback disabled") raise SvidError, "Failed to fetch X.509 SVID: #{e.}" end log.warn("[SPIFFE] Workload API unavailable (#{e.}); using self-signed fallback") self_signed_fallback rescue StandardError => e handle_exception(e, level: :error, operation: 'crypt.spiffe.workload_api_client.fetch_x509_svid', socket_path: @socket_path) log.error("[SPIFFE] X.509 SVID fetch failed: #{e.}") raise end |