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 +7 -0
- data/CHANGELOG.md +20 -0
- data/LICENSE +17 -0
- data/README.md +342 -0
- data/lib/spiffe/version.rb +5 -0
- data/lib/spiffe/workload/client.rb +348 -0
- data/lib/spiffe/workload/grpc_stub.rb +122 -0
- data/lib/spiffe/workload/http_client.rb +67 -0
- data/lib/spiffe/workload/jwt_svid.rb +75 -0
- data/lib/spiffe/workload/messages.rb +102 -0
- data/lib/spiffe/workload/proto_helper.rb +46 -0
- data/lib/spiffe/workload/service.rb +36 -0
- data/lib/spiffe/workload/tls_config.rb +43 -0
- data/lib/spiffe/workload/x509_svid.rb +93 -0
- data/lib/spiffe/workload_pb.rb +30 -0
- data/lib/spiffe/workload_services_pb.rb +51 -0
- data/lib/spiffe.rb +22 -0
- data/proto/spiffe/workload.proto +168 -0
- metadata +166 -0
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
|
+
[](https://github.com/halradaideh/spiffe-rubygem/actions/workflows/ci.yml)
|
|
4
|
+
[](https://badge.fury.io/rb/spiffe-workload)
|
|
5
|
+
[](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.
|