+193
-38
docs/spindle/openbao.md
+193
-38
docs/spindle/openbao.md
···
1
1
# spindle secrets with openbao
2
2
3
3
This document covers setting up Spindle to use OpenBao for secrets
4
-
management instead of the default SQLite backend.
4
+
management via OpenBao Proxy instead of the default SQLite backend.
5
+
6
+
## overview
7
+
8
+
Spindle now uses OpenBao Proxy for secrets management. The proxy handles
9
+
authentication automatically using AppRole credentials, while Spindle
10
+
connects to the local proxy instead of directly to the OpenBao server.
11
+
12
+
This approach provides better security, automatic token renewal, and
13
+
simplified application code.
5
14
6
15
## installation
7
16
8
17
Install OpenBao from nixpkgs:
9
18
10
19
```bash
11
-
nix-env -iA nixpkgs.openbao
20
+
nix shell nixpkgs#openbao # for a local server
12
21
```
13
22
14
-
## local development setup
23
+
## setup
24
+
25
+
The setup process can is documented for both local development and production.
26
+
27
+
### local development
15
28
16
29
Start OpenBao in dev mode:
17
30
18
31
```bash
19
-
bao server -dev
32
+
bao server -dev -dev-root-token-id="root" -dev-listen-address=127.0.0.1:8201
20
33
```
21
34
22
-
This starts OpenBao on `http://localhost:8200` with a root token. Save
23
-
the root token from the output -- you'll need it.
35
+
This starts OpenBao on `http://localhost:8201` with a root token.
24
36
25
37
Set up environment for bao CLI:
26
38
27
39
```bash
28
40
export BAO_ADDR=http://localhost:8200
29
-
export BAO_TOKEN=hvs.your-root-token-here
41
+
export BAO_TOKEN=root
30
42
```
31
43
44
+
### production
45
+
46
+
You would typically use a systemd service with a configuration file. Refer to
47
+
[@tangled.sh/infra](https://tangled.sh/@tangled.sh/infra) for how this can be
48
+
achieved using Nix.
49
+
50
+
Then, initialize the bao server:
51
+
```bash
52
+
bao operator init -key-shares=1 -key-threshold=1
53
+
```
54
+
55
+
This will print out an unseal key and a root key. Save them somewhere (like a password manager). Then unseal the vault to begin setting it up:
56
+
```bash
57
+
bao operator unseal <unseal_key>
58
+
```
59
+
60
+
All steps below remain the same across both dev and production setups.
61
+
62
+
### configure openbao server
63
+
32
64
Create the spindle KV mount:
33
65
34
66
```bash
35
67
bao secrets enable -path=spindle -version=2 kv
36
68
```
37
69
38
-
Set up AppRole authentication:
70
+
Set up AppRole authentication and policy:
39
71
40
72
Create a policy file `spindle-policy.hcl`:
41
73
42
74
```hcl
75
+
# Full access to spindle KV v2 data
43
76
path "spindle/data/*" {
44
-
capabilities = ["create", "read", "update", "delete", "list"]
77
+
capabilities = ["create", "read", "update", "delete"]
45
78
}
46
79
80
+
# Access to metadata for listing and management
47
81
path "spindle/metadata/*" {
48
-
capabilities = ["list", "read", "delete"]
82
+
capabilities = ["list", "read", "delete", "update"]
49
83
}
50
84
51
-
path "spindle/*" {
85
+
# Allow listing at root level
86
+
path "spindle/" {
52
87
capabilities = ["list"]
53
88
}
89
+
90
+
# Required for connection testing and health checks
91
+
path "auth/token/lookup-self" {
92
+
capabilities = ["read"]
93
+
}
54
94
```
55
95
56
96
Apply the policy and create an AppRole:
···
61
101
bao write auth/approle/role/spindle \
62
102
token_policies="spindle-policy" \
63
103
token_ttl=1h \
64
-
token_max_ttl=4h
104
+
token_max_ttl=4h \
105
+
bind_secret_id=true \
106
+
secret_id_ttl=0 \
107
+
secret_id_num_uses=0
65
108
```
66
109
67
110
Get the credentials:
68
111
69
112
```bash
70
-
bao read auth/approle/role/spindle/role-id
71
-
bao write -f auth/approle/role/spindle/secret-id
113
+
# Get role ID (static)
114
+
ROLE_ID=$(bao read -field=role_id auth/approle/role/spindle/role-id)
115
+
116
+
# Generate secret ID
117
+
SECRET_ID=$(bao write -field=secret_id auth/approle/role/spindle/secret-id)
118
+
119
+
echo "Role ID: $ROLE_ID"
120
+
echo "Secret ID: $SECRET_ID"
121
+
```
122
+
123
+
### create proxy configuration
124
+
125
+
Create the credential files:
126
+
127
+
```bash
128
+
# Create directory for OpenBao files
129
+
mkdir -p /tmp/openbao
130
+
131
+
# Save credentials
132
+
echo "$ROLE_ID" > /tmp/openbao/role-id
133
+
echo "$SECRET_ID" > /tmp/openbao/secret-id
134
+
chmod 600 /tmp/openbao/role-id /tmp/openbao/secret-id
135
+
```
136
+
137
+
Create a proxy configuration file `/tmp/openbao/proxy.hcl`:
138
+
139
+
```hcl
140
+
# OpenBao server connection
141
+
vault {
142
+
address = "http://localhost:8200"
143
+
}
144
+
145
+
# Auto-Auth using AppRole
146
+
auto_auth {
147
+
method "approle" {
148
+
mount_path = "auth/approle"
149
+
config = {
150
+
role_id_file_path = "/tmp/openbao/role-id"
151
+
secret_id_file_path = "/tmp/openbao/secret-id"
152
+
}
153
+
}
154
+
155
+
# Optional: write token to file for debugging
156
+
sink "file" {
157
+
config = {
158
+
path = "/tmp/openbao/token"
159
+
mode = 0640
160
+
}
161
+
}
162
+
}
163
+
164
+
# Proxy listener for Spindle
165
+
listener "tcp" {
166
+
address = "127.0.0.1:8201"
167
+
tls_disable = true
168
+
}
169
+
170
+
# Enable API proxy with auto-auth token
171
+
api_proxy {
172
+
use_auto_auth_token = true
173
+
}
174
+
175
+
# Enable response caching
176
+
cache {
177
+
use_auto_auth_token = true
178
+
}
179
+
180
+
# Logging
181
+
log_level = "info"
72
182
```
73
183
74
-
Configure Spindle:
184
+
### start the proxy
185
+
186
+
Start OpenBao Proxy:
187
+
188
+
```bash
189
+
bao proxy -config=/tmp/openbao/proxy.hcl
190
+
```
191
+
192
+
The proxy will authenticate with OpenBao and start listening on
193
+
`127.0.0.1:8201`.
194
+
195
+
### configure spindle
75
196
76
197
Set these environment variables for Spindle:
77
198
78
199
```bash
79
200
export SPINDLE_SERVER_SECRETS_PROVIDER=openbao
80
-
export SPINDLE_SERVER_SECRETS_OPENBAO_ADDR=http://localhost:8200
81
-
export SPINDLE_SERVER_SECRETS_OPENBAO_ROLE_ID=your-role-id-from-above
82
-
export SPINDLE_SERVER_SECRETS_OPENBAO_SECRET_ID=your-secret-id-from-above
201
+
export SPINDLE_SERVER_SECRETS_OPENBAO_PROXY_ADDR=http://127.0.0.1:8201
83
202
export SPINDLE_SERVER_SECRETS_OPENBAO_MOUNT=spindle
84
203
```
85
204
86
205
Start Spindle:
87
206
88
-
Spindle will now use OpenBao for secrets storage with automatic token
89
-
renewal.
207
+
Spindle will now connect to the local proxy, which handles all
208
+
authentication automatically.
209
+
210
+
## production setup for proxy
211
+
212
+
For production, you'll want to run the proxy as a service:
213
+
214
+
Place your production configuration in `/etc/openbao/proxy.hcl` with
215
+
proper TLS settings for the vault connection.
90
216
91
217
## verifying setup
92
218
93
-
List all secrets:
219
+
Test the proxy directly:
94
220
95
221
```bash
96
-
bao kv list spindle/
222
+
# Check proxy health
223
+
curl -H "X-Vault-Request: true" http://127.0.0.1:8201/v1/sys/health
224
+
225
+
# Test token lookup through proxy
226
+
curl -H "X-Vault-Request: true" http://127.0.0.1:8201/v1/auth/token/lookup-self
97
227
```
98
228
99
-
Add a test secret via Spindle API, then check it exists:
229
+
Test OpenBao operations through the server:
100
230
101
231
```bash
232
+
# List all secrets
233
+
bao kv list spindle/
234
+
235
+
# Add a test secret via Spindle API, then check it exists
102
236
bao kv list spindle/repos/
103
-
```
104
237
105
-
Get a specific secret:
106
-
107
-
```bash
238
+
# Get a specific secret
108
239
bao kv get spindle/repos/your_repo_path/SECRET_NAME
109
240
```
110
241
111
242
## how it works
112
243
244
+
- Spindle connects to OpenBao Proxy on localhost (typically port 8200 or 8201)
245
+
- The proxy authenticates with OpenBao using AppRole credentials
246
+
- All Spindle requests go through the proxy, which injects authentication tokens
113
247
- Secrets are stored at `spindle/repos/{sanitized_repo_path}/{secret_key}`
114
-
- Each repository gets its own namespace
115
-
- Repository paths like `at://did:plc:alice/myrepo` become
116
-
`at_did_plc_alice_myrepo`
117
-
- The system automatically handles token renewal using AppRole
118
-
authentication
119
-
- On shutdown, Spindle cleanly stops the token renewal process
248
+
- Repository paths like `did:plc:alice/myrepo` become `did_plc_alice_myrepo`
249
+
- The proxy handles all token renewal automatically
250
+
- Spindle no longer manages tokens or authentication directly
120
251
121
252
## troubleshooting
122
253
123
-
**403 errors**: Check that your BAO_TOKEN is set and the spindle mount
124
-
exists
254
+
**Connection refused**: Check that the OpenBao Proxy is running and
255
+
listening on the configured address.
256
+
257
+
**403 errors**: Verify the AppRole credentials are correct and the policy
258
+
has the necessary permissions.
125
259
126
260
**404 route errors**: The spindle KV mount probably doesn't exist - run
127
-
the mount creation step again
261
+
the mount creation step again.
128
262
129
-
**Token expired**: The AppRole system should handle this automatically,
130
-
but you can check token status with `bao token lookup`
263
+
**Proxy authentication failures**: Check the proxy logs and verify the
264
+
role-id and secret-id files are readable and contain valid credentials.
265
+
266
+
**Secret not found after writing**: This can indicate policy permission
267
+
issues. Verify the policy includes both `spindle/data/*` and
268
+
`spindle/metadata/*` paths with appropriate capabilities.
269
+
270
+
Check proxy logs:
271
+
272
+
```bash
273
+
# If running as systemd service
274
+
journalctl -u openbao-proxy -f
275
+
276
+
# If running directly, check the console output
277
+
```
278
+
279
+
Test AppRole authentication manually:
280
+
281
+
```bash
282
+
bao write auth/approle/login \
283
+
role_id="$(cat /tmp/openbao/role-id)" \
284
+
secret_id="$(cat /tmp/openbao/secret-id)"
285
+
```