
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}} // moul@127.0.0.1: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:
// 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}} // moul@127.0.0.1:22
{{.Host}} // {"HostName":"localhost","Port":22","User":"moul","ControlPersist":"yes",...}
{{printf "%s:%s" .Host.HostName .Host.Port}} // localhost:22
// Stats: https://pkg.go.dev/moul.io/assh/v2/pkg/commands#ConnectionStats
{{.Stats.ConnectedAt}} // 2016-07-20 11:19:23.467900594 +0200 CEST
OnConnectError is called when assh fails to open a new TCP connection.
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}} // moul@127.0.0.1:22
{{.Host}} // {"HostName":"localhost","Port":22","User":"moul","ControlPersist":"yes",...}
{{printf "%s:%s" .Host.HostName .Host.Port}} // localhost:22
// Error
{{.Error}} // dial tcp: lookup localhost: no such host
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:
// 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}} // moul@127.0.0.1:22
{{.Host}} // {"HostName":"localhost","Port":22","User":"moul","ControlPersist":"yes",...}
{{printf "%s:%s" .Host.HostName .Host.Port}} // localhost:22
// Stats: https://pkg.go.dev/moul.io/assh/v2/pkg/commands#ConnectionStats
{{.Stats.ConnectedAt}} // 2016-07-20 11:19:23.467900594 +0200 CEST
{{.Stats.WrittenBytes}} // 3613
{{.Stats.WrittenBytesHuman}} // 3.6kb
{{.Stats.DisconnectAt}} // 2016-07-20 11:19:29,520515792 +0200 CEST
{{.Stats.ConnectionDuration}} // 6.052615198s
{{.Stats.ConnectionDurationHuman}} // 6s
{{.Stats.AverageSpeed}} // 596.933bps
{{.Stats.AverageSpeedHuman}} // 3.4kb/s
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" m+assh@42.am
# 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 moul@127.0.0.1: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```yaml hosts:
homer: # ssh homer -> ssh 1.2.3.4 -p 2222 -u robert Hostname: 1.2.3.4 User: robert Port: 2222
bart: # ssh bart -> ssh 5.6.7.8 -u bart <- direct access # or ssh 5.6.7.8/homer -u bart <- using homer as a gateway Hostname: 5.6.7.8 User: bart Gateways: - direct # tries a direct access first - homer # fallback on homer gateway
maggie: # ssh maggie -> ssh 5.6.7.8 -u maggie <- direct access # or ssh 5.6.7.8/homer -u maggie <- using homer as a gateway User: maggie Inherits: bart # inherits rules from "bart"
bart-access: # ssh bart-access -> ssh home.simpson.springfield.us -u bart Inherits: - bart-template - simpson