···11# spindle secrets with openbao2233This document covers setting up Spindle to use OpenBao for secrets44-management instead of the default SQLite backend.44+management via OpenBao Proxy instead of the default SQLite backend.55+66+## overview77+88+Spindle now uses OpenBao Proxy for secrets management. The proxy handles99+authentication automatically using AppRole credentials, while Spindle1010+connects to the local proxy instead of directly to the OpenBao server.1111+1212+This approach provides better security, automatic token renewal, and1313+simplified application code.514615## installation716817Install OpenBao from nixpkgs:9181019```bash1111-nix-env -iA nixpkgs.openbao2020+nix shell nixpkgs#openbao # for a local server1221```13221414-## local development setup2323+## setup2424+2525+The setup process can is documented for both local development and production.2626+2727+### local development15281629Start OpenBao in dev mode:17301831```bash1919-bao server -dev3232+bao server -dev -dev-root-token-id="root" -dev-listen-address=127.0.0.1:82012033```21342222-This starts OpenBao on `http://localhost:8200` with a root token. Save2323-the root token from the output -- you'll need it.3535+This starts OpenBao on `http://localhost:8201` with a root token.24362537Set up environment for bao CLI:26382739```bash2840export BAO_ADDR=http://localhost:82002929-export BAO_TOKEN=hvs.your-root-token-here4141+export BAO_TOKEN=root3042```4343+4444+### production4545+4646+You would typically use a systemd service with a configuration file. Refer to4747+[@tangled.sh/infra](https://tangled.sh/@tangled.sh/infra) for how this can be4848+achieved using Nix.4949+5050+Then, initialize the bao server:5151+```bash5252+bao operator init -key-shares=1 -key-threshold=15353+```5454+5555+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:5656+```bash5757+bao operator unseal <unseal_key>5858+```5959+6060+All steps below remain the same across both dev and production setups.6161+6262+### configure openbao server31633264Create the spindle KV mount:3365···6735bao secrets enable -path=spindle -version=2 kv6836```69377070-Set up AppRole authentication:3838+Set up AppRole authentication and policy:71397240Create a policy file `spindle-policy.hcl`:73417442```hcl4343+# Full access to spindle KV v2 data7544path "spindle/data/*" {7676- capabilities = ["create", "read", "update", "delete", "list"]4545+ capabilities = ["create", "read", "update", "delete"]7746}78474848+# Access to metadata for listing and management7949path "spindle/metadata/*" {8080- capabilities = ["list", "read", "delete"]5050+ capabilities = ["list", "read", "delete", "update"]8151}82528383-path "spindle/*" {5353+# Allow listing at root level5454+path "spindle/" {8455 capabilities = ["list"]5656+}5757+5858+# Required for connection testing and health checks5959+path "auth/token/lookup-self" {6060+ capabilities = ["read"]8561}8662```8763···10161bao write auth/approle/role/spindle \10262 token_policies="spindle-policy" \10363 token_ttl=1h \104104- token_max_ttl=4h6464+ token_max_ttl=4h \6565+ bind_secret_id=true \6666+ secret_id_ttl=0 \6767+ secret_id_num_uses=010568```1066910770Get the credentials:1087110972```bash110110-bao read auth/approle/role/spindle/role-id111111-bao write -f auth/approle/role/spindle/secret-id7373+# Get role ID (static)7474+ROLE_ID=$(bao read -field=role_id auth/approle/role/spindle/role-id)7575+7676+# Generate secret ID7777+SECRET_ID=$(bao write -field=secret_id auth/approle/role/spindle/secret-id)7878+7979+echo "Role ID: $ROLE_ID"8080+echo "Secret ID: $SECRET_ID"11281```11382114114-Configure Spindle:8383+### create proxy configuration8484+8585+Create the credential files:8686+8787+```bash8888+# Create directory for OpenBao files8989+mkdir -p /tmp/openbao9090+9191+# Save credentials9292+echo "$ROLE_ID" > /tmp/openbao/role-id9393+echo "$SECRET_ID" > /tmp/openbao/secret-id9494+chmod 600 /tmp/openbao/role-id /tmp/openbao/secret-id9595+```9696+9797+Create a proxy configuration file `/tmp/openbao/proxy.hcl`:9898+9999+```hcl100100+# OpenBao server connection101101+vault {102102+ address = "http://localhost:8200"103103+}104104+105105+# Auto-Auth using AppRole106106+auto_auth {107107+ method "approle" {108108+ mount_path = "auth/approle"109109+ config = {110110+ role_id_file_path = "/tmp/openbao/role-id"111111+ secret_id_file_path = "/tmp/openbao/secret-id"112112+ }113113+ }114114+115115+ # Optional: write token to file for debugging116116+ sink "file" {117117+ config = {118118+ path = "/tmp/openbao/token"119119+ mode = 0640120120+ }121121+ }122122+}123123+124124+# Proxy listener for Spindle125125+listener "tcp" {126126+ address = "127.0.0.1:8201"127127+ tls_disable = true128128+}129129+130130+# Enable API proxy with auto-auth token131131+api_proxy {132132+ use_auto_auth_token = true133133+}134134+135135+# Enable response caching136136+cache {137137+ use_auto_auth_token = true138138+}139139+140140+# Logging141141+log_level = "info"142142+```143143+144144+### start the proxy145145+146146+Start OpenBao Proxy:147147+148148+```bash149149+bao proxy -config=/tmp/openbao/proxy.hcl150150+```151151+152152+The proxy will authenticate with OpenBao and start listening on153153+`127.0.0.1:8201`.154154+155155+### configure spindle115156116157Set these environment variables for Spindle:117158118159```bash119160export SPINDLE_SERVER_SECRETS_PROVIDER=openbao120120-export SPINDLE_SERVER_SECRETS_OPENBAO_ADDR=http://localhost:8200121121-export SPINDLE_SERVER_SECRETS_OPENBAO_ROLE_ID=your-role-id-from-above122122-export SPINDLE_SERVER_SECRETS_OPENBAO_SECRET_ID=your-secret-id-from-above161161+export SPINDLE_SERVER_SECRETS_OPENBAO_PROXY_ADDR=http://127.0.0.1:8201123162export SPINDLE_SERVER_SECRETS_OPENBAO_MOUNT=spindle124163```125164126165Start Spindle:127166128128-Spindle will now use OpenBao for secrets storage with automatic token129129-renewal.167167+Spindle will now connect to the local proxy, which handles all168168+authentication automatically.169169+170170+## production setup for proxy171171+172172+For production, you'll want to run the proxy as a service:173173+174174+Place your production configuration in `/etc/openbao/proxy.hcl` with175175+proper TLS settings for the vault connection.130176131177## verifying setup132178133133-List all secrets:179179+Test the proxy directly:134180135181```bash182182+# Check proxy health183183+curl -H "X-Vault-Request: true" http://127.0.0.1:8201/v1/sys/health184184+185185+# Test token lookup through proxy186186+curl -H "X-Vault-Request: true" http://127.0.0.1:8201/v1/auth/token/lookup-self187187+```188188+189189+Test OpenBao operations through the server:190190+191191+```bash192192+# List all secrets136193bao kv list spindle/137137-```138194139139-Add a test secret via Spindle API, then check it exists:140140-141141-```bash195195+# Add a test secret via Spindle API, then check it exists142196bao kv list spindle/repos/143143-```144197145145-Get a specific secret:146146-147147-```bash198198+# Get a specific secret148199bao kv get spindle/repos/your_repo_path/SECRET_NAME149200```150201151202## how it works152203204204+- Spindle connects to OpenBao Proxy on localhost (typically port 8200 or 8201)205205+- The proxy authenticates with OpenBao using AppRole credentials206206+- All Spindle requests go through the proxy, which injects authentication tokens153207- Secrets are stored at `spindle/repos/{sanitized_repo_path}/{secret_key}`154154-- Each repository gets its own namespace155155-- Repository paths like `at://did:plc:alice/myrepo` become156156- `at_did_plc_alice_myrepo`157157-- The system automatically handles token renewal using AppRole158158- authentication159159-- On shutdown, Spindle cleanly stops the token renewal process208208+- Repository paths like `did:plc:alice/myrepo` become `did_plc_alice_myrepo`209209+- The proxy handles all token renewal automatically210210+- Spindle no longer manages tokens or authentication directly160211161212## troubleshooting162213163163-**403 errors**: Check that your BAO_TOKEN is set and the spindle mount164164-exists214214+**Connection refused**: Check that the OpenBao Proxy is running and215215+listening on the configured address.216216+217217+**403 errors**: Verify the AppRole credentials are correct and the policy218218+has the necessary permissions.165219166220**404 route errors**: The spindle KV mount probably doesn't exist - run167167-the mount creation step again221221+the mount creation step again.168222169169-**Token expired**: The AppRole system should handle this automatically,170170-but you can check token status with `bao token lookup`223223+**Proxy authentication failures**: Check the proxy logs and verify the224224+role-id and secret-id files are readable and contain valid credentials.225225+226226+**Secret not found after writing**: This can indicate policy permission227227+issues. Verify the policy includes both `spindle/data/*` and228228+`spindle/metadata/*` paths with appropriate capabilities.229229+230230+Check proxy logs:231231+232232+```bash233233+# If running as systemd service234234+journalctl -u openbao-proxy -f235235+236236+# If running directly, check the console output237237+```238238+239239+Test AppRole authentication manually:240240+241241+```bash242242+bao write auth/approle/login \243243+ role_id="$(cat /tmp/openbao/role-id)" \244244+ secret_id="$(cat /tmp/openbao/secret-id)"245245+```