Home / Docs / Secrets & Integrations

Secrets & Integrations

Solo & Teams

Bring your own vault. Servonaut never stores your SSH keys or secret values — they live in your Bitwarden Password Manager (or Secrets Manager) and the CLI resolves them locally at the moment you need them.

Trust model in one sentence

Servonaut backend stores where a credential lives (which vault, which item id). The value never leaves your machine.

How it works

Each server in your inventory can carry a credential reference: a tiny pointer (provider, item id, optional collection id) that tells the CLI which Bitwarden record to fetch when you SSH in. The pointer is the only thing stored on servonaut.dev. The actual SSH private key, BWS access token, and secret values are pulled by the CLI directly from your vault — over your Bitwarden session, with your unlock password — and dropped into a 0600-permissioned tmpfile that's cleaned up on process exit.

Stored on servonaut.devStored in your Bitwarden vaultStored on disk during use
provider: bitwarden_pm
item_id: uuid
collection_id (optional)
vault URL (if self-hosted)
SSH private key
BWS access token
Secret values (DB passwords, API keys…)
Temp keyfile (0600, atexit cleanup, 24h stale sweeper)

Supported providers

  • Bitwarden Password Manager (bw) — the consumer vault. Free tier of Bitwarden is enough to store an SSH key. Self-hosted Bitwarden servers are supported via a custom Vault URL.
  • Bitwarden Secrets Manager (bws) — Bitwarden's developer secrets product. Useful when you want machine-readable secrets distinct from your personal password vault. Same wire shape as PM.
  • Local fallback — if no credential ref is configured for a server, the CLI falls back to ~/.ssh/ key discovery exactly like before.
Why Bitwarden first?

It's open-source, has a free tier suitable for individuals, supports both consumer (Password Manager) and developer (Secrets Manager) workflows, and ships first-class CLIs (bw + bws) that we can shell out to without a custom integration. 1Password and HashiCorp Vault adapters are on the roadmap.

Personal vs. team scope

Every integration is scoped to either you (your personal vault, your servers) or your team (the team's shared vault, the team's shared servers). Two scopes, same wire shape — different storage tables on the backend, different audit trails.

ScopeUse it whenRequired plan
Personal Solo developer with their own AWS/OVH/Hetzner instances Solo or Teams
Team-shared Multiple team members need to SSH the same boxes with a rotated key Teams (paid seat)

The /account/integrations wizard

Everything is configured through a single wizard at /account/integrations. No JSON files, no env vars to remember. The wizard has four cards depending on your plan:

  1. Personal SSH Key Config — point the CLI at your personal Bitwarden vault for SSH keys.
  2. Personal Secrets Config — same, for non-SSH secrets (DB passwords, API keys) you want resolved by name.
  3. Team SSH Key Config — visible only to team owners/admins. Sets the vault used when team members SSH a shared server.
  4. Per-server credential refs — for each personal or team server, paste the Bitwarden item id of the key. The CLI uses this exact key for that exact instance.
The BWS access token is yours, forever

The wizard never asks for your BWS_ACCESS_TOKEN or Bitwarden unlock password — it stores only the name of the env var to read (default: BWS_ACCESS_TOKEN). The token itself sits in your shell environment or your password manager.

Setup in five minutes

  1. Install the Bitwarden CLI on your machine. Servonaut uses it to talk to your vault.
    macOS / Linux
    $ npm install -g @bitwarden/cli # or: brew install bitwarden-cli / snap install bw $ bw login # your Bitwarden email + master password $ export BW_SESSION=$(bw unlock --raw)

    See the Bitwarden CLI install guide for other platforms.

  2. Store your SSH key in Bitwarden as a native SSH Key item. In the Bitwarden vault UI (Web or Desktop), pick Vault → New item → SSH Key and paste your OpenSSH private key body into the Private Key field. Save the item and copy the resulting item id — you'll paste it into Servonaut's "Manage SSH Ref" form in the next step.
    Requires Bitwarden 2023.10 or newer

    Servonaut reads the private key from .sshKey.privateKey on the BW item. Legacy Secure Notes with the key pasted in the notes field are not supported in v2.12.0 — the CLI will return a BwItemShapeError. If you need notes-blob support, file an issue.

  3. Open the integrations wizard at /account/integrations. Pick "Bitwarden Password Manager", leave the Vault URL blank for the SaaS version (or paste your self-hosted URL), and hit Save SSH config.
  4. Attach a credential ref to a server. Open one of your instances in the "Servers" section of the wizard, paste the Bitwarden item id, and save.
  5. SSH using the ref. From your terminal:
    CLI
    $ servonaut ssh i-0a1b2c3d4e5f6g7h8 # resolves ref → fetches key from Bitwarden → writes tmpfile → exec ssh

CLI commands

servonaut ssh <instance-id>

SSH into an instance using its credential ref. Resolution is three-tier:

  1. Personal credential ref attached to the instance (your config)
  2. Team credential ref attached to the instance (shared with the team)
  3. Local ~/.ssh/ key discovery (the legacy path)

Whichever resolves first wins. The fetched key is written to a temp file with 0600 permissions, used to open the SSH session, and deleted when the process exits. A 24-hour stale sweeper cleans up any tmpfile orphaned by a hard crash.

servonaut servers verify <id>

Sanity-checks the credential resolution and connectivity for one instance, without dropping you into a shell. Runs bw get item locally to confirm the key fetches, then ssh -o BatchMode=yes -o ConnectTimeout=N to confirm the key actually authenticates against the box. Posts the result back to servonaut.dev so your dashboard can show the green checkmark.

Exit codeMeaningVerify report POSTed?
0Verified — key resolves and SSH connects.Yes (status=verified)
1Verified-failure — probe ran end-to-end but reported not_found (the BW item is missing) or auth_failed (SSH refused the key — firewall, wrong user, key not in authorized_keys).Yes (status=not_found or auth_failed)
2Fatal config — couldn't run the probe at all: no credential ref stored, Bitwarden CLI not installed, vault locked, or user not signed into Servonaut.No

TUI surfaces

The same flows are available inside the Servonaut TUI for users who prefer to stay in the interactive UI:

WhereKeyAction
Instance listkManage SSH ref for the selected instance (add / edit / delete)
Instance listvVerify SSH against the selected instance (opens probe modal)
Instance rowSSH-verify column shows green / red / dash based on the most recent verify
Settings"Bitwarden SSH Vault" section — same config the web wizard writes, reachable offline
Why both web and TUI?

The web wizard is the canonical surface for first-time setup and team-admin actions. The TUI surfaces the same operations for users who live in the terminal and don't want to alt-tab to a browser to rotate a key.

Audit & change tracking

Every change made through the integrations wizard is recorded in your audit log: who changed it, what changed (full diff — minus secret values, which never reach us), and when. Workspace owners can review the trail from the admin area.

The CLI also compares its cached secrets_fetched_at against the server's updated_at on each session, so you'll see "team secrets config changed since last fetch — refreshing" in the TUI when an admin rotates something.

Troubleshooting

"Error: bw command not found"

Install the Bitwarden CLI: npm install -g @bitwarden/cli on most systems, brew install bitwarden-cli on macOS, or snap install bw on Linux. See the Bitwarden CLI install guide for other platforms. Install the Bitwarden CLI separately — Servonaut does not bundle it.

"BwItemShapeError: BW item ... has no SSH key field"

The credential ref points at a Bitwarden item that isn't a native SSH Key item. Servonaut v2.12.0 requires Bitwarden 2023.10 or newer and reads the private key from .sshKey.privateKey. Open the item in Bitwarden, delete it, and re-create it as Vault → New item → SSH Key with the private key in the Private Key field.

"Bitwarden vault is locked"

Run bw unlock (or bw login if you've never authenticated on this machine) and export the resulting session token to BW_SESSION. The CLI reads it from your environment.

"Verify exits 1 — connection refused"

The credential ref resolves fine, but the SSH daemon refused the key. Check: the right username (ubuntu vs root vs cloud-specific default), security-group/firewall rules allowing your IP, and the public key actually being present in the server's ~/.ssh/authorized_keys.

"Personal Bitwarden integration requires a Solo or Teams subscription"

Secrets integrations are a paid feature — the Free tier is intentionally excluded because the integration costs real ops time to support. See Pricing for the per-plan breakdown.

Documentation