···1# spindle secrets with openbao
23This document covers setting up Spindle to use OpenBao for secrets
4-management instead of the default SQLite backend.
00000000056## installation
78Install OpenBao from nixpkgs:
910```bash
11-nix-env -iA nixpkgs.openbao
12```
1314-## local development setup
00001516Start OpenBao in dev mode:
1718```bash
19-bao server -dev
20```
2122-This starts OpenBao on `http://localhost:8200` with a root token. Save
23-the root token from the output -- you'll need it.
2425Set up environment for bao CLI:
2627```bash
28export BAO_ADDR=http://localhost:8200
29-export BAO_TOKEN=hvs.your-root-token-here
30```
310000000000000000000032Create the spindle KV mount:
3334```bash
35bao secrets enable -path=spindle -version=2 kv
36```
3738-Set up AppRole authentication:
3940Create a policy file `spindle-policy.hcl`:
4142```hcl
043path "spindle/data/*" {
44- capabilities = ["create", "read", "update", "delete", "list"]
45}
46047path "spindle/metadata/*" {
48- capabilities = ["list", "read", "delete"]
49}
5051-path "spindle/*" {
052 capabilities = ["list"]
53}
0000054```
5556Apply the policy and create an AppRole:
···61bao write auth/approle/role/spindle \
62 token_policies="spindle-policy" \
63 token_ttl=1h \
64- token_max_ttl=4h
00065```
6667Get the credentials:
6869```bash
70-bao read auth/approle/role/spindle/role-id
71-bao write -f auth/approle/role/spindle/secret-id
000000000000000000000000000000000000000000000000000000000000000000072```
7374-Configure Spindle:
000000000007576Set these environment variables for Spindle:
7778```bash
79export 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
83export SPINDLE_SERVER_SECRETS_OPENBAO_MOUNT=spindle
84```
8586Start Spindle:
8788-Spindle will now use OpenBao for secrets storage with automatic token
89-renewal.
00000009091## verifying setup
9293-List all secrets:
9495```bash
96-bao kv list spindle/
000097```
9899-Add a test secret via Spindle API, then check it exists:
100101```bash
0000102bao kv list spindle/repos/
103-```
104105-Get a specific secret:
106-107-```bash
108bao kv get spindle/repos/your_repo_path/SECRET_NAME
109```
110111## how it works
112000113- 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
120121## troubleshooting
122123-**403 errors**: Check that your BAO_TOKEN is set and the spindle mount
124-exists
000125126**404 route errors**: The spindle KV mount probably doesn't exist - run
127-the mount creation step again
128129-**Token expired**: The AppRole system should handle this automatically,
130-but you can check token status with `bao token lookup`
000000000000000000000
···1# spindle secrets with openbao
23This document covers setting up Spindle to use OpenBao for secrets
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.
1415## installation
1617Install OpenBao from nixpkgs:
1819```bash
20+nix shell nixpkgs#openbao # for a local server
21```
2223+## setup
24+25+The setup process can is documented for both local development and production.
26+27+### local development
2829Start OpenBao in dev mode:
3031```bash
32+bao server -dev -dev-root-token-id="root" -dev-listen-address=127.0.0.1:8201
33```
3435+This starts OpenBao on `http://localhost:8201` with a root token.
03637Set up environment for bao CLI:
3839```bash
40export BAO_ADDR=http://localhost:8200
41+export BAO_TOKEN=root
42```
4344+### 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+64Create the spindle KV mount:
6566```bash
67bao secrets enable -path=spindle -version=2 kv
68```
6970+Set up AppRole authentication and policy:
7172Create a policy file `spindle-policy.hcl`:
7374```hcl
75+# Full access to spindle KV v2 data
76path "spindle/data/*" {
77+ capabilities = ["create", "read", "update", "delete"]
78}
7980+# Access to metadata for listing and management
81path "spindle/metadata/*" {
82+ capabilities = ["list", "read", "delete", "update"]
83}
8485+# Allow listing at root level
86+path "spindle/" {
87 capabilities = ["list"]
88}
89+90+# Required for connection testing and health checks
91+path "auth/token/lookup-self" {
92+ capabilities = ["read"]
93+}
94```
9596Apply the policy and create an AppRole:
···101bao write auth/approle/role/spindle \
102 token_policies="spindle-policy" \
103 token_ttl=1h \
104+ token_max_ttl=4h \
105+ bind_secret_id=true \
106+ secret_id_ttl=0 \
107+ secret_id_num_uses=0
108```
109110Get the credentials:
111112```bash
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"
182```
183184+### 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
196197Set these environment variables for Spindle:
198199```bash
200export SPINDLE_SERVER_SECRETS_PROVIDER=openbao
201+export SPINDLE_SERVER_SECRETS_OPENBAO_PROXY_ADDR=http://127.0.0.1:8201
00202export SPINDLE_SERVER_SECRETS_OPENBAO_MOUNT=spindle
203```
204205Start Spindle:
206207+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.
216217## verifying setup
218219+Test the proxy directly:
220221```bash
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
227```
228229+Test OpenBao operations through the server:
230231```bash
232+# List all secrets
233+bao kv list spindle/
234+235+# Add a test secret via Spindle API, then check it exists
236bao kv list spindle/repos/
0237238+# Get a specific secret
00239bao kv get spindle/repos/your_repo_path/SECRET_NAME
240```
241242## how it works
243244+- 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
247- Secrets are stored at `spindle/repos/{sanitized_repo_path}/{secret_key}`
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
000251252## troubleshooting
253254+**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.
259260**404 route errors**: The spindle KV mount probably doesn't exist - run
261+the mount creation step again.
262263+**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+```