spiffe-workload 0.2.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1661e0826c4de0e0f9e21788abbd78c41ad04c15b30c2f8e2b5a104949232e3e
4
+ data.tar.gz: 930a68a433e1e0d7a9b529713352bedd769177cc0e482d57e17c7ca998d54617
5
+ SHA512:
6
+ metadata.gz: 2c5160736a3274699160105a2e772af9c8259e91292189f69dc5f1de8612b0ef4435ccf7e0d8dd32888780d0ec976dd3c985db2c022d23c94af00034f9a7ddd6
7
+ data.tar.gz: cc9a091b5373da018de85ec9a5c7b3b0d77a649c5ffde8a13f9da936303632ecab1ecadbb12b10f4335046b4a68cdca1b10d20d2fe0da542b664d3e710d5edc9
data/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0] - 2026-02-04
4
+
5
+ ### Added
6
+ - Full SPIFFE Workload API implementation
7
+ - X.509 SVID fetching with automatic rotation
8
+ - JWT SVID generation
9
+ - Trust bundle management
10
+ - OpenSSL integration for TLS contexts
11
+ - Thread-safe credential caching
12
+ - Puppet integration support
13
+ - Basic Workload API client
14
+ - Manual protobuf definitions
15
+
16
+ ### Fixed
17
+ - Security header: `workload.spiffe.io: 'true'`
18
+ - gRPC service name: `SpiffeWorkloadAPI`
19
+ - Method names use proper snake_case
20
+ - Proper protobuf code generation
data/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 SPIFFE Ruby Contributors
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,342 @@
1
+ # SPIFFE Workload API - Ruby Client
2
+
3
+ [![CI](https://github.com/halradaideh/spiffe-rubygem/actions/workflows/ci.yml/badge.svg)](https://github.com/halradaideh/spiffe-rubygem/actions/workflows/ci.yml)
4
+ [![Gem Version](https://badge.fury.io/rb/spiffe-workload.svg)](https://badge.fury.io/rb/spiffe-workload)
5
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
6
+
7
+ A Ruby client library for the [SPIFFE Workload API](https://github.com/spiffe/spiffe/blob/main/standards/SPIFFE_Workload_API.md), enabling Ruby applications to obtain and use SPIFFE identities from a SPIRE agent.
8
+
9
+ This project aims to be part of the [SPIFFE](https://spiffe.io/) ecosystem. See the [SPIFFE GitHub](https://github.com/spiffe/spiffe) for more information about the SPIFFE project.
10
+
11
+ ## What is this?
12
+
13
+ This gem allows Ruby applications (including Puppet) to:
14
+ - Fetch X.509 SVIDs (certificates) from SPIRE for mTLS
15
+ - Generate JWT SVIDs for API authentication
16
+ - Access trust bundles for verification
17
+ - Handle automatic credential rotation
18
+
19
+ It communicates directly with the SPIRE agent over Unix domain sockets, enabling proper process-based attestation (unlike subprocess-based CLI tools).
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ gem install spiffe-workload
25
+ ```
26
+
27
+ For Puppet:
28
+ ```bash
29
+ /opt/puppetlabs/puppet/bin/gem install spiffe-workload
30
+ ```
31
+
32
+ ## Prerequisites
33
+
34
+ 1. **SPIRE Agent** running with workload API socket accessible
35
+ 2. **Workload entry** registered for your application
36
+
37
+ ```bash
38
+ # Verify SPIRE agent is running
39
+ ls -la /run/spire/sockets/agent.sock
40
+
41
+ # Register your application
42
+ spire-server entry create \
43
+ -parentID spiffe://example.org/agent/myhost \
44
+ -spiffeID spiffe://example.org/myapp \
45
+ -selector unix:uid:$(id -u) \
46
+ -selector unix:path:/path/to/your/app
47
+ ```
48
+
49
+ ## Quick Start
50
+
51
+ ### Fetch X.509 Certificate
52
+
53
+ ```ruby
54
+ require 'spiffe'
55
+
56
+ client = Spiffe.workload_api_client
57
+ svid = client.x509_svid
58
+
59
+ puts "My identity: #{svid.spiffe_id}"
60
+ puts "Expires: #{svid.leaf_certificate.not_after}"
61
+
62
+ client.shutdown
63
+ ```
64
+
65
+ ### Fetch JWT Token
66
+
67
+ ```ruby
68
+ require 'spiffe'
69
+
70
+ client = Spiffe.workload_api_client
71
+ jwt = client.jwt_svid(audience: 'my-service')
72
+
73
+ puts "Token: #{jwt.token}"
74
+ puts "Expires: #{jwt.expiration}"
75
+
76
+ client.shutdown
77
+ ```
78
+
79
+ ### mTLS HTTP Request
80
+
81
+ ```ruby
82
+ require 'spiffe'
83
+ require 'net/http'
84
+
85
+ client = Spiffe.workload_api_client
86
+ uri = URI('https://api.example.com/data')
87
+
88
+ http = Net::HTTP.new(uri.host, uri.port)
89
+ http.use_ssl = true
90
+ http.ssl_context = client.tls_context
91
+
92
+ response = http.get(uri.path)
93
+ puts response.body
94
+
95
+ client.shutdown
96
+ ```
97
+
98
+ ## Configuration
99
+
100
+ ### Socket Path
101
+
102
+ Auto-detected from:
103
+ 1. `socket_path` parameter
104
+ 2. `SPIFFE_ENDPOINT_SOCKET` environment variable
105
+ 3. Default: `/run/spire/sockets/agent.sock`
106
+
107
+ ```ruby
108
+ client = Spiffe.workload_api_client(
109
+ socket_path: '/var/run/spire/agent.sock'
110
+ )
111
+ ```
112
+
113
+ ### Timeout
114
+
115
+ ```ruby
116
+ client = Spiffe.workload_api_client(timeout: 10)
117
+ ```
118
+
119
+ ## Puppet Integration
120
+
121
+ ### Custom Function Example
122
+
123
+ ```ruby
124
+ # modules/spiffe/lib/puppet/functions/spiffe_jwt.rb
125
+ Puppet::Functions.create_function(:spiffe_jwt) do
126
+ def spiffe_jwt(audience)
127
+ require 'spiffe'
128
+ client = Spiffe.workload_api_client
129
+ jwt = client.jwt_svid(audience: audience)
130
+ jwt.token
131
+ ensure
132
+ client&.shutdown
133
+ end
134
+ end
135
+ ```
136
+
137
+ Use in Puppet manifest:
138
+
139
+ ```puppet
140
+ $token = Deferred('spiffe_jwt', ['vault.example.com'])
141
+
142
+ file { '/etc/app/token':
143
+ content => $token,
144
+ mode => '0600',
145
+ }
146
+ ```
147
+
148
+ ### SPIRE Configuration for Puppet
149
+
150
+ ```yaml
151
+ # Puppet agent workload entry
152
+ selectors:
153
+ - "unix:uid:0" # Root user
154
+ - "unix:path:/opt/puppetlabs/puppet/bin/ruby" # Puppet Ruby binary
155
+ ```
156
+
157
+ ## API Reference
158
+
159
+ ### `Spiffe.workload_api_client`
160
+
161
+ Creates a new Workload API client.
162
+
163
+ **Parameters:**
164
+ - `socket_path` (String, optional): Path to SPIRE agent socket
165
+ - `timeout` (Integer, optional): Request timeout in seconds
166
+
167
+ **Returns:** `Spiffe::Workload::Client`
168
+
169
+ ### `Client#x509_svid`
170
+
171
+ Fetches X.509 SVID.
172
+
173
+ **Returns:** `Spiffe::Workload::X509SVIDWrapper`
174
+
175
+ Properties:
176
+ - `spiffe_id` - SPIFFE ID string
177
+ - `leaf_certificate` - OpenSSL::X509::Certificate
178
+ - `certificate_chain` - Array of certificates
179
+ - `private_key` - OpenSSL::PKey::RSA
180
+ - `ttl` - Time to live in seconds
181
+
182
+ ### `Client#jwt_svid(audience:, spiffe_id: nil)`
183
+
184
+ Fetches JWT SVID.
185
+
186
+ **Parameters:**
187
+ - `audience` (String|Array): Target audience(s)
188
+ - `spiffe_id` (String, optional): Specific SPIFFE ID
189
+
190
+ **Returns:** `Spiffe::Workload::JWTSVIDWrapper`
191
+
192
+ Properties:
193
+ - `spiffe_id` - SPIFFE ID string
194
+ - `token` - JWT token string
195
+ - `expiration` - Expiration time
196
+ - `claims` - Decoded JWT claims
197
+
198
+ ### `Client#tls_context`
199
+
200
+ Creates OpenSSL context with current SVID.
201
+
202
+ **Returns:** `OpenSSL::SSL::SSLContext`
203
+
204
+ ### `Client#on_x509_svid_update { |svid| ... }`
205
+
206
+ Registers callback for SVID rotation.
207
+
208
+ ### `Client#shutdown`
209
+
210
+ Cleanly shuts down the client.
211
+
212
+ ## Troubleshooting
213
+
214
+ ### "Socket does not exist"
215
+
216
+ ```bash
217
+ # Check SPIRE agent status
218
+ systemctl status spire-agent
219
+
220
+ # Verify socket location
221
+ sudo find /run /var/run -name "agent.sock" 2>/dev/null
222
+ ```
223
+
224
+ ### "No identity issued"
225
+
226
+ ```bash
227
+ # Check workload registration
228
+ spire-server entry show
229
+
230
+ # Verify selectors match your process
231
+ ps aux | grep your-app
232
+ ```
233
+
234
+ ### "Permission denied"
235
+
236
+ ```bash
237
+ # Check socket permissions
238
+ ls -la /run/spire/sockets/agent.sock
239
+
240
+ # Add user to spire group
241
+ sudo usermod -a -G spire $USER
242
+ ```
243
+
244
+ ## Architecture
245
+
246
+ This gem implements a **client-side library** for the SPIFFE Workload API:
247
+
248
+ ```
249
+ ┌────────────────┐
250
+ │ Ruby App │
251
+ │ (this gem) │
252
+ └───────┬────────┘
253
+ │ gRPC over Unix socket
254
+
255
+ ┌────────────────┐
256
+ │ SPIRE Agent │
257
+ │ (attests app) │
258
+ └───────┬────────┘
259
+ │ mTLS
260
+
261
+ ┌────────────────┐
262
+ │ SPIRE Server │
263
+ └────────────────┘
264
+ ```
265
+
266
+ **Key points:**
267
+ - No subprocess attestation issues (unlike CLI tools)
268
+ - Direct process attestation by SPIRE
269
+ - Thread-safe credential caching
270
+ - Automatic rotation support
271
+
272
+ ## Contributing
273
+
274
+ We welcome contributions! This project follows the [SPIFFE contribution guidelines](https://github.com/spiffe/spiffe/blob/main/CONTRIBUTING.md).
275
+
276
+ ### Getting Started
277
+
278
+ 1. Fork the repository
279
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
280
+ 3. Make your changes
281
+ 4. Ensure tests pass (`bundle exec rspec`)
282
+ 5. Ensure code style passes (`bundle exec rubocop`)
283
+ 6. Commit with DCO sign-off (`git commit -s -m 'Add amazing feature'`)
284
+ 7. Push to your fork (`git push origin feature/amazing-feature`)
285
+ 8. Open a Pull Request
286
+
287
+ ### DCO Sign-off
288
+
289
+ All commits must include a `Signed-off-by` line to certify the [Developer Certificate of Origin (DCO)](DCO):
290
+
291
+ ```bash
292
+ git commit -s -m "Your commit message"
293
+ ```
294
+
295
+ ### Similar SPIFFE Projects
296
+
297
+ - [go-spiffe](https://github.com/spiffe/go-spiffe) - Go implementation
298
+ - [java-spiffe](https://github.com/spiffe/java-spiffe) - Java implementation
299
+ - [py-spiffe](https://github.com/spiffe/py-spiffe) - Python implementation
300
+
301
+ See [SPIFFE CONTRIBUTING.md](https://github.com/spiffe/spiffe/blob/main/CONTRIBUTING.md) for more details on contributing to SPIFFE projects.
302
+
303
+ ## Development
304
+
305
+ ### Build from Source
306
+
307
+ ```bash
308
+ git clone https://github.com/halradaideh/spiffe-rubygem.git
309
+ cd spiffe-rubygem
310
+ bundle install
311
+ gem build spiffe-workload.gemspec
312
+ gem install spiffe-workload-*.gem
313
+ ```
314
+
315
+ ### Run Tests
316
+
317
+ ```bash
318
+ bundle exec rspec
319
+ ```
320
+
321
+ ### Generate Protobuf
322
+
323
+ ```bash
324
+ gem install grpc-tools
325
+ rake generate_protos
326
+ ```
327
+
328
+ ## License
329
+
330
+ Apache License 2.0 - see [LICENSE](LICENSE) file
331
+
332
+ ## Support
333
+
334
+ - **Issues:** GitHub Issues
335
+ - **SPIFFE Slack:** [slack.spiffe.io](https://slack.spiffe.io)
336
+ - **SPIFFE Docs:** [spiffe.io/docs](https://spiffe.io/docs)
337
+
338
+ ## Version
339
+
340
+ Current version: 0.2.0
341
+
342
+ See [CHANGELOG.md](CHANGELOG.md) for version history.
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spiffe
4
+ VERSION = '0.2.0'
5
+ end