Files
ssh-netbox-wrapper/README.md
T
Sebastian Unterschütz 8fc7896b35
Release / release (push) Successful in 46s
docs: update README for wizard, token versions, completion install
2026-05-23 13:31:08 +02:00

7.2 KiB

netssh

A transparent SSH wrapper that resolves hostnames via NetBox before connecting.

Instead of looking up an IP manually, you just type the hostname as it appears in NetBox:

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)

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, verifies the SHA-256 checksum, and installs to /usr/local/bin/netssh (using sudo only if necessary).

To install to a custom directory:

INSTALL_DIR=~/.local/bin curl -fsSL https://git.zb-server.de/Sebi/ssh-netbox-wrapper/raw/branch/main/install.sh | bash

Build from source

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:

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:

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:

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:

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:

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:

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

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)

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):

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):

fpath=(~/.zfunc $fpath)
autoload -Uz compinit && compinit

Completions are served from the local cache — no network request on every <Tab>.

Development

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.