sshkeeper/README.md

313 lines
9.8 KiB
Markdown

# sshkeeper
`sshkeeper` is a Linux console manager for SSH profiles, secrets, and quick
OpenSSH launches. It does not replace OpenSSH; it keeps connection metadata in a
local SQLite database, keeps passwords/passphrases in an encrypted vault, and
starts the system `ssh` client with the right options.
## sshkeeper is not Ansible
sshkeeper does not configure servers, push files, or manage infrastructure.
It is an SSH connection manager: it remembers how to reach your servers
(bastions, jump chains, port forwards) and launches the system `ssh` client.
Think of it as a smart `~/.ssh/config` with a TUI, encrypted secrets, and
port forwarding management.
## Features
- Bubble Tea TUI for daily interactive use.
- CLI commands for scripting and quick edits.
- Encrypted vault for SSH passwords and key passphrases.
- Password and key-passphrase auth through a PTY prompt handler, without putting
secrets in command-line arguments.
- Key, SSH-agent, password, and key+passphrase auth modes.
- **Routes / ProxyJump** — manage bastion hosts and jump chains with human-readable display.
- **Port forwarding** — named local/remote/SOCKS forwards with type selector, validation, and OpenSSH preview.
- **Tunnel management** — start/stop/list background tunnels, PID tracking, runtime state.
- **Tunnel vs Forward** — clear separation: forward = saved rule, tunnel = running SSH process.
- Groups, tags, command templates, search by metadata/routes/forward ports, and OpenSSH config generation.
- Import from `~/.ssh/config` and simple tab-separated export.
## Install
### Build from source
```bash
git clone git@git.mirv.top:mirivlad/sshkeeper.git
cd sshkeeper
go build -o ~/.local/bin/sshkeeper .
```
Or use the build scripts:
```bash
./build.sh # Build binary to bin/
./release.sh # Build release tarballs to dist/
```
Requirements: Go 1.25+, Linux x86_64, system OpenSSH.
**Source repositories:**
- Main public: [github.com/mirivlad/sshkeeper](https://github.com/mirivlad/sshkeeper)
- Mirror/dev: `git@git.mirv.top:mirivlad/sshkeeper`
### Install from release (after v0.2.0 publication)
```bash
tar -xzf sshkeeper_v0.2.0_linux_amd64.tar.gz
chmod +x sshkeeper-linux-amd64
sudo install -m 0755 sshkeeper-linux-amd64 /usr/local/bin/sshkeeper
sshkeeper
```
## First Run
Run the TUI or any command. On the first run, `sshkeeper` creates its config,
database, and vault, then asks for a master password.
```bash
sshkeeper
```
You can also initialize explicitly:
```bash
sshkeeper init
```
## TUI
Running `sshkeeper` without arguments opens the TUI.
### Main Window
```
sshkeeper 0 servers
Vault unlocked | 0 OK | 0 FAIL
NAME ALIAS ROUTE AUTH GROUP STATUS
No servers yet. Press Ctrl+A to add one.
Enter: connect | Ctrl+X: actions | Ctrl+A: add | Ctrl+E: edit
Ctrl+F: search | Ins: select | ?: hotkeys | F1: help | Ctrl+Q: quit
```
### Quick Help (?)
Press `?` on any screen for a compact hotkey reference.
### Full Help (F1)
Press `F1` on any screen for full documentation including routes, port
forwarding, tunnels, and vault.
### Screenshots
| Main list | Actions | Route edit |
|-----------|---------|------------|
| ![Main list](docs/screenshots/screen_1.png) | ![Actions](docs/screenshots/screen_2.png) | ![Route edit](docs/screenshots/screen_3.png) |
| Port forwards | Tunnel manager |
|---------------|----------------|
| ![Port forwards](docs/screenshots/screen_4.png) | ![Tunnel manager](docs/screenshots/screen_5.png) |
### Key Reference
| Key | Action |
|-----|--------|
| Enter | Connect to selected server |
| Ctrl+A | Add server |
| Ctrl+E | Edit server |
| Ctrl+F | Search |
| Ctrl+W | Manage port forwards for selected server |
| Ctrl+X | Action menu (connect, tunnels, forwards, route, test, edit, delete, import/export, vault actions) |
| Ins | Select / deselect a server |
| ? | Quick help (hotkeys) |
| F1 | Full documentation |
| Ctrl+Q / Ctrl+C | Quit |
Templates are global entities and can run on any server. Foreground template
runs leave the TUI, show the SSH session in the terminal, and then return to the
TUI. Background runs execute the command and show per-server output in a result
screen.
In add/edit forms:
| Key | Action |
|-----|--------|
| Tab / Down | Next field |
| Shift+Tab / Up | Previous field |
| `/` on Auth Method or Group | Pick from list |
| Enter | Move to action / activate |
| Esc | Back |
## Routes, Tunnels, and Port Forwards
### Jump host (single bastion)
```bash
sshkeeper route set web --jumps bastion
sshkeeper route show web
# Route: bastion → web@10.0.0.10:22
# Mode: via
# ProxyJump: bastion
```
### Jump chain (multiple hops)
```bash
sshkeeper route set prod --jumps bastion,dmz-gw
sshkeeper route show prod
# Route: bastion → dmz-gw → prod@10.0.0.20:22
# Mode: chain
# ProxyJump: bastion,dmz-gw
```
### Port forwards
A **port forward** is a saved rule that describes how to tunnel traffic through SSH.
It does not start any process — it is just configuration.
```bash
# Local forward: access a remote service from your machine
sshkeeper forward add web --name "Local PostgreSQL" --type local --local-port 15432 --remote-addr 127.0.0.1 --remote-port 5432
# SOCKS proxy: route browser traffic through SSH server
sshkeeper forward add bastion --name "SOCKS Proxy" --type dynamic --local-port 1080
# Disable a saved forward
sshkeeper forward edit 1 --enabled=false
# List forwards for a server
sshkeeper forward list web
# [1] Local PostgreSQL Local 127.0.0.1:15432 127.0.0.1:5432 yes
# [2] SOCKS Proxy SOCKS 127.0.0.1:1080 SOCKS yes
```
Forward types:
| Type | Description |
|------|-------------|
| **Local** | Port on your machine → service reachable from SSH server |
| **Remote** | Port on SSH server → service on your machine |
| **SOCKS** | Local dynamic SOCKS proxy through SSH |
Default listen address is `127.0.0.1` (localhost only). Use `0.0.0.0` with caution — the port will be accessible from the network.
### Tunnels
A **tunnel** is a running SSH process that activates one or more port forwards.
```bash
# Connect with all enabled forwards active (interactive session)
sshkeeper tunnel web
# Start tunnels only (foreground, no shell)
sshkeeper tunnel web --forward-only
# Start tunnels in background (detached process)
sshkeeper tunnel web --background
# List running tunnels
sshkeeper tunnel list
# Stop a tunnel
sshkeeper tunnel stop <id>
# Stop every tracked tunnel
sshkeeper tunnel stop-all
```
Background tunnels run detached with `ssh -N`, require at least one enabled
forward, and currently support key or SSH-agent authentication only. Use
foreground `sshkeeper tunnel <alias>` or `--forward-only` for password and
key-passphrase authentication so the PTY prompt handler can provide the secret.
### Connect vs Tunnel
| Action | Command | TUI | Description |
|--------|---------|-----|-------------|
| Connect | `sshkeeper connect <alias>` | `Enter` | Standard SSH session, no port forwards |
| Connect with tunnels | `sshkeeper tunnel <alias>` | Action menu → Connect with tunnels | SSH session with all enabled forwards active |
| Start tunnels only | `sshkeeper tunnel <alias> --forward-only` | Action menu → Start tunnels only | Foreground tunnel, no shell |
| Start tunnels in background | `sshkeeper tunnel <alias> --background` | Action menu → Start tunnels in background | Detached tunnel process with PID tracking |
| Manage port forwards | `sshkeeper forward` | Action menu → Manage port forwards | Add/edit/delete forward rules |
| Manage tunnels | `sshkeeper tunnel list/stop/stop-all` | Action menu → Manage tunnels | View running tunnels and stop them |
## Vault
The vault stores SSH passwords and key passphrases encrypted on disk.
- Cipher: XChaCha20-Poly1305.
- KDF: Argon2id, currently 64 MiB memory, 3 iterations.
- Existing legacy vault files remain readable.
- Unlock state is process-local. `sshkeeper vault unlock` verifies the master
password, but it does not keep future shell commands unlocked.
Useful commands:
```bash
sshkeeper vault status
sshkeeper vault unlock
sshkeeper vault list
sshkeeper vault delete <alias> [ssh_password|key_passphrase]
sshkeeper vault change-password
```
`vault list`, `vault delete`, and `vault change-password` ask for the master
password themselves because they need to decrypt the vault in the current
process.
## Security
`sshkeeper` stores SSH passwords and key passphrases in an encrypted local vault
and avoids passing secrets through command-line arguments. The project has not
had an independent security audit; review the implementation and threat model
before using it for high-risk environments.
## Data Locations
`sshkeeper` uses XDG-style app directories:
| Data | Default path |
|------|-------------|
| Config | `~/.config/sshkeeper/config.toml` |
| Database | `~/.local/share/sshkeeper/sshkeeper.db` |
| Vault | `~/.local/share/sshkeeper/vault.bin` |
| Generated OpenSSH config | `~/.ssh/config.d/sshkeeper.conf` |
If `XDG_CONFIG_HOME` or `XDG_DATA_HOME` are set, sshkeeper stores data under
`$XDG_CONFIG_HOME/sshkeeper` and `$XDG_DATA_HOME/sshkeeper`.
## Build And Test
```bash
go test ./...
go build -o bin/sshkeeper .
```
`bin/` is ignored by git.
## Project Layout
```text
sshkeeper/
├── cmd/ # Cobra CLI commands and TUI launcher
├── internal/config/ # XDG paths and config loading
├── internal/db/ # SQLite migrations and CRUD
├── internal/model/ # Domain models
├── internal/ssh/ # OpenSSH command building, PTY prompt handling
├── internal/tui/ # Bubble Tea UI
├── internal/vault/ # Encrypted vault
├── internal/tunnel/ # Tunnel state management
├── docs/guide.md # User guide
├── build.sh # Build binary to bin/
├── release.sh # Build release tarballs to dist/
└── main.go
```
## License
MIT. See [LICENSE](LICENSE).