sshbox

command module
v0.0.0-...-153ad23 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2025 License: MIT Imports: 26 Imported by: 0

README

sshbox

Build Status

A small, programmable SSH server that can:

  • act as a regular SSH server and run a command (or shell) per session
  • act as a flexible “SSH proxy/jump” that executes a command template to another SSH endpoint
  • sandbox sessions by running a containerized environment (e.g. uLinux box or Docker)

It focuses on composable authentication methods and a powerful command templating model so you can control exactly what runs for an incoming SSH connection.

Based on the excellent examples from gliderlabs/ssh

Features

  • Public key authentication via multiple pluggable methods (OR semantics; first match wins):
    • none: accept any key (for testing only)
    • file:: parse authorized keys from a local file
    • github[:user1,user2,...]: fetch keys from https://github.com/.keys (optional allow-list)
    • url:[|user1,user2,...]: fetch keys from an arbitrary URL format (e.g. your Gitea), with optional allow-list
    • lookup:<users.yml>[|user1,user2,...]: in-repo YAML user DB with keys and attributes
  • Agent forwarding passthrough for child processes you run (enable ForwardAgent in the client if you intend to hop to an upstream SSH server)
  • Command templating with session/user variables and helper functions
  • Optional pre-hook and post-hook commands per session (with templating)
  • MOTD display (toggle)
  • Host key management: generates a host key if not present
  • Graceful shutdown on signals
  • Cron-like hook runner for periodic tasks
  • Sandbox helpers using Docker or uLinux box (scripts included)

Install

With a Go toolchain:

  • Go 1.20+ recommended

Install latest:

go install git.mills.io/prologic/sshbox@latest

Build from source:

git clone https://git.mills.io/prologic/sshbox.git
cd sshbox
make

Prebuilt binaries are published on the Releases page.

Quick start

Run an SSH server on :2222, authenticating against an authorized_keys file, and starting a shell:

sshbox -a file:$HOME/.ssh/authorized_keys /bin/sh

Authorize via GitHub for an explicit allow-list of users and start a shell:

sshbox -a github:alice,bob /bin/sh

Authorize via an arbitrary URL format (e.g. your Gitea or other service). The format must include a single %s placeholder for the SSH username:

# Example: url:<format>|<allow-list>
sshbox -a 'url:https://git.mills.io/%s.keys|alice,bob' /bin/sh

YAML lookup (bundled DB with attributes):

sshbox -a lookup:./users.yml|alice,bob /bin/sh

Using sshbox as an SSH proxy/jump

sshbox does not embed an SSH client to upstream, but it executes the command you provide for each session. You can therefore run the system ssh client in a controlled way and pass through the original command and environment. Agent forwarding is supported when the connecting client requests it.

Important points:

  • The command you pass to sshbox is tokenized and executed. The user’s requested command (if any) is appended to the args.
  • You can template variables into your command to route by username, set environment, or enforce policy.
  • If you want the upstream SSH to authenticate using the caller’s keys, ensure the caller enables agent forwarding to sshbox (ForwardAgent yes), so child ssh processes see SSH_AUTH_SOCK.

Example: forward all sessions to an upstream Gitea instance as the git user, passing the original command:

sshbox \
  -a github:alice,bob \
  -a 'url:https://git.mills.io/%s.keys|alice,bob' \
  'ssh -o BatchMode=yes -o StrictHostKeyChecking=no [email protected] ${Args}'

Notes:

  • ${Args} expands to the client’s requested command (e.g. git-receive-pack 'repo.git').
  • If the connecting client forwarded their agent, the spawned ssh process will be able to use it to authenticate to the upstream.
  • If you want to force a specific upstream port or user, set it in the template. The template is evaluated before arg splitting.

Sandboxing sessions

You can use the included scripts to start/attach to a Docker-based sandbox per user. The YAML user DB can provide resource attributes that become environment variables.

Example using the provided scripts:

# Prepare the per-user home volume if needed
sshbox \
  -a lookup:./users.yml \
  -p './setup-home.sh ${User}' \
  './sandbox.sh ${User}'
  • setup-home.sh ensures a Docker volume and data container exist for ${User} and sets ownership
  • sandbox.sh starts or reuses a per-user container with constraints sourced from user_attrs_* env

See users.yml for an example of per-user attributes (e.g. mem, cpus, pids, image). These appear as env vars named user_attrs_ and can be used in hooks/templates.

CLI options

  • -b, --bind string (default ":2222"): interface:port to bind
  • -v, --version: print version
  • -d, --debug: enable debug logging
  • -k, --host-key string (default "ssh_host_key"): path to host private key; auto-generated if missing
  • -a, --auth method [...]: one or more auth methods (first to pass wins)
  • --disable-motd: suppress /etc/motd output on PTY sessions
  • -p, --pre-hook string: command to run before starting the session
  • -P, --post-hook string: command to run after the session ends
  • -e, --every-hook 'spec:cmd': run cmd on a cron-like schedule (spec is robfig/cron v3 format)

Auth method syntax:

  • none
  • file:
  • github[:user1,user2,...]
  • url:[|user1,user2,...]
  • lookup:<users.yml>[|user1,user2,...]

When an allow-list is provided (comma separated), only those SSH usernames may authenticate with that method.

Templating and environment

The command, pre-hook and post-hook strings are processed with a template engine prior to execution. Available variables:

  • User: SSH username (ctx.User)
  • Host: remote address
  • Time: Unix seconds at session start
  • Args: client’s requested command joined as a single string
  • Env: full environment passed by the client
  • user_name, user_email: from lookup: users.yml
  • user_attrs_: for each attribute in users.yml under attrs

Helper functions available in templates:

  • getEnv "VAR": read a server-side environment variable
  • getUserID "username": resolve a local system username to UID
  • getGroupID "group": resolve a local system group to GID

Example:

sshbox \
  -a lookup:./users.yml \
  -p 'logger pre user=${User} host=${Host} ts=${Time}' \
  -P 'logger post user=${User} ts=${Time}' \
  'box run ${user_attrs_image:-alpine} /bin/sh'

Security considerations

  • Auth methods are OR’d with “first match wins.” Order matters. Place stricter/fast methods first if desired.
  • github and url methods fetch keys over HTTPS for the SSH username. If you do not supply an allow-list, you effectively trust “any valid user at the provider” for the username presented. Use allow-lists wherever possible.
  • If you run sshbox as a proxy, ensure you always pass a fixed command that does only what you intend (e.g., spawn a specific ssh command). If you omit the command, sshbox will default to /bin/sh, which is almost certainly not what you want for a proxy.
  • Agent forwarding: the upstream hop will only work with the caller’s keys if they enable agent forwarding to sshbox. Document this requirement for your users.
  • Hooks and templates: avoid interpolating untrusted values directly into shell commands without quoting. The template engine substitutes literal strings into your command; use cautious shell practices if you expand variables.
  • Host key: sshbox auto-generates a host key if missing. Back up or manage this key if you require host key pinning for clients.

Example: Gitea proxy layout

Goal: accept SSH connections to sshbox and forward to [email protected], while authenticating callers using a combination of your Gitea keys API and GitHub keys.

  1. Require an allow-list of users for both methods to avoid authorizing unexpected accounts.
  2. Require clients to enable agent forwarding for sshbox so the child ssh can authenticate to git.mills.io using their own keys.
  3. Force the forwarding command.
sshbox \
  -b :2222 \
  -d \
  -k /etc/ssh/sshbox_host_key \
  -a 'url:https://git.mills.io/%s.keys|alice,bob' \
  -a 'github:alice,bob' \
  'ssh -o BatchMode=yes -o StrictHostKeyChecking=no [email protected] ${Args}'

Client-side (example):

# ~/.ssh/config
Host sshbox
    HostName sshbox.example.org
    Port 2222
    User alice
    ForwardAgent yes

Users then run:

git clone ssh://sshbox/repo.git
# or
ssh sshbox info

The upstream [email protected] will still enforce repository-level writes based on keys it trusts. If a user is not present at Gitea (or the repo denies them), the write will fail even if sshbox authentication succeeded.

License

MIT

Documentation

Overview

Package main implements the sshbox command-line tool

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL