# netssh A transparent SSH wrapper that resolves hostnames via [NetBox](https://netbox.dev/) before connecting. Instead of looking up an IP manually, you just type the hostname as it appears in NetBox: ```sh netssh my-router-01 netssh -p 2222 admin@app-server-03 uptime ``` `netssh` looks up the host in NetBox, resolves the right IP using a configurable strategy chain, and replaces the process with the native `ssh` binary — so all your existing SSH configs, keys, and agent forwarding work without any changes. ## Features - **Transparent proxy** — replaces itself with `ssh` via `syscall.Exec`, preserving all SSH flags and options - **Flexible IP resolution** — configurable chain of strategies: management subnet, primary IP, or named interface - **Interactive TUI** — fuzzy search with live NetBox queries and 300 ms debouncing (start with `netssh`, no arguments) - **Persistent cache** — successful lookups are cached to `~/.cache/netssh/hosts.json` for instant shell completion - **Setup wizard** — interactive first-run onboarding; re-run anytime with `netssh configure` - **Shell completion** — install without sudo via `netssh completion install` - **Default SSH user** — set a fallback username once in config instead of typing it every time ## Installation ### One-liner (Linux & macOS) ```sh curl -fsSL https://git.zb-server.de/Sebi/ssh-netbox-wrapper/raw/branch/main/install.sh | bash ``` The script detects your OS and architecture, downloads the matching binary from the [latest release](https://git.zb-server.de/Sebi/ssh-netbox-wrapper/releases/latest), verifies the SHA-256 checksum, and installs to `/usr/local/bin/netssh` (using `sudo` only if necessary). To install to a custom directory: ```sh INSTALL_DIR=~/.local/bin curl -fsSL https://git.zb-server.de/Sebi/ssh-netbox-wrapper/raw/branch/main/install.sh | bash ``` ### Build from source ```sh git clone ssh://git@git.zb-server.de:30022/Sebi/ssh-netbox-wrapper.git cd ssh-netbox-wrapper go build -o netssh ./cmd/netssh ``` ## Configuration ### Interactive wizard On first run (when no config exists), `netssh` automatically starts an interactive setup wizard. Re-run it at any time to change settings without editing the file manually: ```sh netssh configure ``` The wizard walks through NetBox connection, SSH defaults, resolver strategies, and cache TTL, then saves to `~/.config/netssh.yaml`. ### Manual config `~/.config/netssh.yaml`: ```yaml netbox: url: https://netbox.example.com token: nbt_your-api-token-here # v2 token (nbt_ prefix) recommended token_version: 2 # auto-detected from token; 1 = legacy, 2 = nbt_ resolver: # Strategies are tried in order; the first to return an IP wins. strategies: - management_subnet - primary_ip # Used by the management_subnet strategy. management_subnets: - 10.0.0.0/8 - 172.16.0.0/12 # Used by the interface_name strategy. interface_name: mgmt0 cache: ttl: 3600 # seconds; 0 = always query NetBox on connect (cache still used for completion) # path: ~/.cache/netssh/hosts.json # default ssh: default_user: admin # used when no user is specified on the command line ``` Any value can be overridden with environment variables (`NETSSH_NETBOX_URL`, `NETSSH_NETBOX_TOKEN`, etc.). ### API tokens NetBox supports two token formats: | Format | Example | Notes | |--------|---------|-------| | v2 (recommended) | `nbt_abc123…` | Create in NetBox → Admin → API Tokens | | v1 (legacy) | `abc123def456…` | Older format; still works, but v2 is preferred | `netssh` auto-detects the version from the token prefix and stores it as `token_version` in the config. A hint is shown during `netssh configure` if a legacy v1 token is entered. ## Usage ### SSH wrapper mode Pass any SSH flags and a NetBox hostname: ```sh netssh my-router-01 netssh -p 2222 admin@app-server-03 uptime netssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no db-primary ``` The process is replaced by `ssh` with the resolved IP — your `~/.ssh/config`, agent, and keys all work as normal. ### Default username Set `ssh.default_user` in the config to avoid typing a username every time: ```sh netssh my-router # → ssh -l admin 10.0.0.1 ``` The default is only applied when no user is specified on the command line. An explicit user always takes precedence: ```sh netssh root@my-router # user@ prefix wins → ssh root@10.0.0.1 netssh -l ops my-router # -l flag wins → ssh -l ops 10.0.0.1 ``` ### Interactive TUI Run without arguments to open the interactive search: ```sh netssh ``` | Key | Action | |-----|--------| | type | filter hosts (300 ms debounce → NetBox query) | | `Tab` | autocomplete top result into the search field | | `↑` / `↓` | navigate results | | `Enter` | connect to selected host | | `Esc` / `Ctrl+C` | quit | ### Cache management ```sh netssh cache list # show all cached entries netssh cache refresh # re-fetch all hosts from NetBox netssh cache clear # wipe the cache ``` ### Search (for scripting) ```sh netssh search app- # prints matching hostnames, one per line ``` ## IP Resolution Strategies Strategies are tried in the configured order; the first to succeed wins. | Name | Description | |------|-------------| | `primary_ip` | Returns the `primary_ip4` (or `primary_ip6`) set in NetBox. No extra API call. | | `management_subnet` | Fetches all IPs for the host and returns the first one matching a configured CIDR. | | `interface_name` | Fetches IPs attached to a specific named interface (e.g. `mgmt0`). | ## Shell Completion Install completion for the current user (no sudo required): ```sh netssh completion install # auto-detects $SHELL netssh completion install --shell bash netssh completion install --shell zsh netssh completion install --shell fish ``` | Shell | Install path | |-------|-------------| | bash | `~/.local/share/bash-completion/completions/netssh` | | zsh | `~/.zfunc/_netssh` | | fish | `~/.config/fish/completions/netssh.fish` | For zsh, make sure `~/.zfunc` is in your `fpath` (add to `~/.zshrc`): ```zsh fpath=(~/.zfunc $fpath) autoload -Uz compinit && compinit ``` Completions are served from the local cache — no network request on every ``. ## Development ```sh go test ./... # run all tests go build ./... # build all packages ``` The test suite covers the cache, NetBox client (via `httptest`), IP resolver chain, SSH argument parser, config loading, and the setup wizard. ## How it works 1. `netssh` checks whether the first argument is a known subcommand (`configure`, `search`, `cache`, `completion`). If not, it enters SSH wrapper mode. 2. On first run or when `netbox.url` is empty, the interactive setup wizard starts automatically. 3. It parses the SSH arguments to extract the destination hostname, handling all flags that consume an extra argument (`-p`, `-i`, `-J`, …). 4. It checks the local cache. If the entry exists and is within the TTL, it connects immediately. 5. Otherwise it queries NetBox (`/api/dcim/devices/` and `/api/virtualization/virtual-machines/` in parallel), runs the result through the resolver chain, and caches the IP. 6. It calls `syscall.Exec` to replace itself with `ssh`, substituting the hostname with the resolved IP.