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:
- ssh
- scp
- rsync
- git
- Desktop applications depending on
lib-ssh
orssh
(i.e., Tower, Atom.io, SSH Tunnel Manager)
For specific examples, see 3rd Party Integration
- regex support
- aliases
gate
->gate.domain.tld
- gateways -> transparent ssh connection chaining
- includes: split configuration in multiple files, note that OpenSSH as of v7.3 has native support for this
- local command execution: finally the reverse of RemoteCommand
- templates: equivalent to host but you can't connect directly to a template, perfect for inheritance
- inheritance: make hosts inherits from host hosts or templates
- variable expansion: resolve variables from the environment
- smart proxycommand: RAW tcp connection when possible with
netcat
andsocat
as default fallbacks - rate limit: configure a per-host or global rate-limiting
- JSON output
- Graphviz: graphviz reprensentation of the hosts
assh 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.4
ssh hostb
->ssh -o ProxyCommand="ssh hostb nc %h %p" hosta
ssh hostc
->ssh -o ProxyCommand="ssh -o ProxyCommand='ssh hostc nc %h %p' hostb nc %h %p" hosta
ssh hostd
->- assh will try to
ssh 13.14.15.16
- then, fallback on
ssh -o ProxyCommand="ssh hostd nc %h %p" hosta
- this method allows you to have the best performances when it is possible, but ensure your commands will work if you are outside of your company for instance
- assh will try to
- Automatically regenerates
~/.ssh/config
file when needed - Inspect parent process to determine log level (if you use
ssh -vv
, assh will automatically run in debug mode) - Automatically creates
ControlPath
directories so you can use slashes in yourControlPath
option, can be enabled with theControlMasterMkdir: 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: http://godoc.org/moul.io/assh/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: http://godoc.org/moul.io/assh/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: http://godoc.org/moul.io/assh/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: http://godoc.org/moul.io/assh/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 Gol 2E87 ang template variables:
// Host: http://godoc.org/moul.io/assh/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: http://godoc.org/moul.io/assh/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.