:computer: make your ssh client smarter
A transparent wrapper that adds support for regex, aliases, gateways, dynamic hostnames, graphviz, json output, yaml configuration, and more to SSH.
lib-ssh wraps assh as a ProxyCommand; it means that it works seamlessly with:
lib-ssh or ssh (i.e., Tower, Atom.io, SSH Tunnel Manager)For specific examples, see 3rd Party Integration
gate -> gate.domain.tldnetcat and socat as default fallbacksassh can use the ProxyCommand with netcat feature of OpenSSH transparently and without the pain of using extended configuration.
Connect to hosta using hostb as a gateway.
flowchart
direction TB
y[you]
a[hosta]
b[hostb]
fw((firewall))
style fw fill:#f00,color:#fff
y ==x fw
fw .-> a
y --> b
b --> a
$ ssh hosta/hostb
user@hosta $
Equivalent to ssh -o ProxyCommand="ssh hostb nc %h %p" hosta
Connect to hosta using hostb as a gateway using hostc as a gateway.
flowchart
direction TB
y[you]
a[hosta]
b[hostb]
c[hostc]
fw((firewall))
style fw fill:#f00,color:#fff
y ==x fw
fw ..-> a
y --> c
c --> b
b --> a
$ ssh hosta/hostb/hostc
user@hosta $
Equivalent to ssh -o ProxyCommand="ssh -o ProxyCommand='ssh hostc nc %h %p' hostb nc %h %p" hosta
You can define an equivalent of the "ProxyCommand with netcat" feature of OpenSSH, with a simpler syntax, more advanced workflows, and a unique fallback feature.
Let's consider the following assh.yml file
hosts:
hosta:
Hostname: 1.2.3.4
hostb:
Hostname: 5.6.7.8
Gateways: hosta
hostc:
Hostname: 9.10.11.12
Gateways: hostb
hostd:
Hostname: 13.14.15.16
GatewayConnectTimeout: 2
Gateways:
- direct
- hosta
ssh hosta -> ssh 1.2.3.4ssh hostb -> ssh -o ProxyCommand="ssh hostb nc %h %p" hostassh hostc -> ssh -o ProxyCommand="ssh -o ProxyCommand='ssh hostc nc %h %p' hostb nc %h %p" hostassh hostd ->ssh 13.14.15.16ssh -o ProxyCommand="ssh hostd nc %h %p" hosta~/.ssh/config file when neededssh -vv, assh will automatically run in debug mode)ControlPath directories so you can use slashes in your ControlPath option, can be enabled with the ControlMasterMkdir: true configuration in host or globally.BeforeConnect is called just before assh tries to connect to the remote SSH port.
Note: BeforeConnect will be called for each SSH connection; if you use multiple gateways, it will be called for each gateways until one succeed to connect.
Example of Golang template variables:
// Host: https://pkg.go.dev/moul.io/assh/v2/pkg/config#Host
{{.Host.Name}} // localhost
{{.Host.HostName}} // 127.0.0.1
{{.Host.Port}} // 22
{{.Host.User}} // moul
{{.Host.Prototype}} // [email protected]:22
{{.Host}} // {"HostName":"localhost","Port":22","User":"moul","ControlPersist":"yes",...}
{{printf "%s:%s" .Host.HostName .Host.Port}} // localhost:22
OnConnect is called as soon as assh is connected to the remote SSH port.
Note: OnConnect is not aware of the authentication process and will always be raised.
Example of Golang template variables:
…
OnConnectError is called when assh fails to open a new TCP connection.
Example of Golang template variables:
…
OnDisconnect is called as the assh socket is closed.
warning: if you don't see a notification when closing an SSH connection, then you probably have ControlMaster configured; OnDisconnect is not linked to the ssh program but to its socket which may stay alive even after exiting the ssh program.
Example of Golang template variables:
…
BeforeConfigWrite is called just before assh rewrite the ~/.ssh/config file.
Example of Golang template variables:
{{.SSHConfigPath}} // ~/.ssh/config
Exec driver uses Golang's template system to execute a shell command
Usage: exec <binary> [args...]
defaults:
Hooks:
OnConnect: exec echo '{{.Host}}' | jq .
# executes: `echo '{"HostName":"localhost","Port":"22","User":"moul","ControlPersist":"yes",...}' | jq .
# which results in printing a pretty JSON of the host
# {
# "HostName": "localhost",
# "Port": "22",
# "User": "moul",
# "ControlPersist": "yes",
# ...
# }
defaults:
Hooks:
OnConnect: exec echo 'New SSH connection to {{.Host.Prototype}}.' | mail -s "SSH connection journal" [email protected]
# send an email with the connection prototype
defaults:
Hooks:
BeforeConfigWrite: exec cp {{.SSHConfigPath}} {{.SSHConfigPath}}.backup
# make a copy of ~/.ssh/config before being rewritten
defaults:
Hooks:
AfterConfigWrite: 'exec echo "# date: `date`" >> {{.SSHConfigPath}}'
# Append a comment with the compilation date to the generated ~/.ssh/config file
defaults:
Hooks:
AfterConfigWrite: 'exec cat /path/to/my/provider/generated/.ssh/config >> {{.SSHConfigPath}}'
# Append another .ssh/config file to the generated .ssh/config file
The exec commands are blocking, a new driver for background tasks is planned. For now, you can run a job in background like this:
defaults:
Hooks:
OnConnect:
- exec sleep 60 &
# execute the `sleep 60` command in background (non-blocking)
# if you quit your ssh connection, the process will continue in background.
Write driver uses Golang's template system to write out data to stdout
Usage: write <line:string...>
defaults:
Hooks:
OnConnect:
- write New SSH connection to {{.Host.Prototype}}.
# writes: "New SSH connection to [email protected]:22." on the terminal on connection
defaults:
Hooks:
OnDisconnect:
- "write SSH connection to {{.Host.Name}} closed, {{ .Stats.WrittenBytes }} bytes written in {{ .Stats.ConnectionDuration }} ({{ .Stats.AverageSpeed }})"
# writes: SSH connection to localhost closed, 40 bytes written.
Notify driver uses Golang's template system to open Desktop notifications.
Usage: notify <line:string...>
defaults:
Hooks:
OnConnect: notify New SSH connection to {{.Host.Prototype}}.
defaults:
Hooks:
OnDisconnect:
- "notify SSH connection to {{.Host.Name}} closed, {{ .Stats.WrittenBytes }} bytes written in {{ .Stats.ConnectionDuration }} ({{ .Stats.AverageSpeed }})"
assh now manages the ~/.ssh/config file, take care to keep a backup your ~/.ssh/config file.
~/.ssh/assh.yml is a YAML file containing:
hosts dictionary containing multiple HOST definitionsdefaults section containing global flagsincludes section containing path to other configuration files…
For further inspiration, these assh.yml files on public GitHub projects can educate you on how people are using assh
assh usage
…
assh config buildRewrites and replaces the existing ~/.ssh/config file.
This action is automatically done by assh when detecting configuration changes. Running this command is useful to set up assh or repair the configuration file.
$ assh config build > ~/.ssh/config
assh config listList hosts and options.
…
assh config graphvizGenerate a graphviz graph of the hosts
$ assh config graphviz | dot -Tpng > assh-hosts.png
assh config search <keyword>Search for <keyword> in hosts and host options.
$ assh config search bart
Listing results for bart:
bart -> [email protected]:22
bart-access -> moul@[hostname_not_specified]:22
assh infoDisplay system-wide information.
$ assh info
Debug mode (client): false
CLI Path: /path/to/assh
Go version: go1.6.2
OS/Arch: darwin/amd64
RC files:
- ~/.ssh/assh.yml
- ~/.ssh/assh.d/hosts.yml
- ~/.ssh/assh.d/moul.yml
- ~/.ssh/assh.d/test.yml
Statistics:
- 299 hosts
- 2 templates
- 4 included files
assh sockets listList active control sockets.
$ assh sockets list
4 active control sockets in "~/.ssh/cm/":
- bart/homer/lisa-22-root.sock (14 minutes)
- bart/homer-22-root.sock (14 minutes)
- bart-22-root.sock (14 minutes)
- marge-22-bart.sock (1 hour)
assh sockets flushClose active control sockets.
$ assh sockets flush
Closed 4 control sockets.
assh sockets masterCreate a master control sockets.
$ assh sockets master
assh pingSend packets to the SSH server and display stats.
$ assh ping -c 4 localhost
PING localhost (127.0.0.1) PORT 22 (ssh) PROTO tcp
Connected to 127.0.0.1: seq=0 time=321µs protocol=tcp port=22
Connected to 127.0.0.1: seq=1 time=501µs protocol=tcp port=22
Connected to 127.0.0.1: seq=2 time=550µs protocol=tcp port=22
Connected to 127.0.0.1: seq=3 time=641µs protocol=tcp port=22
--- localhost assh ping statistics ---
4 packets transmitted, 4 pa
No open issues yet, or sync has not completed.