Networking¶
SSH connection gateways¶
Background¶
When connecting to well-secured networks whose internal hosts are not directly reachable from the Internet, a common pattern is “bouncing”, “gatewaying” or “proxying” SSH connections via an intermediate host (often called a “bastion”, “gateway” or “jump box”).
Gatewaying requires making an initial/outer SSH connection to the gateway system, then using that connection as a transport for the “real” connection to the final/internal host.
At a basic level, one could ssh gatewayhost
, then ssh internalhost
from
the resulting shell. This works for individual long-running sessions, but
becomes a burden when it must be done frequently.
There are two gateway solutions available in Fabric, mirroring the
functionality of OpenSSH’s client: ProxyJump
style (easier, less overhead,
can be nested) or ProxyCommand
style (more overhead, can’t be nested,
sometimes more flexible). Both support the usual range of configuration
sources: Fabric’s own config framework, SSH config files, or runtime
parameters.
ProxyJump
¶
This style of gateway uses the SSH protocol’s direct-tcpip
channel type - a
lightweight method of requesting that the gateway’s sshd
open a connection
on our behalf to another system. (This has been possible in OpenSSH server for
a long time; support in OpenSSH’s client is new as of 7.3.)
Channel objects (instances of paramiko.channel.Channel
) implement Python’s
socket API and are thus usable in place of real operating system sockets for
nearly any Python code.
ProxyJump
style gatewaying is simple to use: create a new Connection
object parameterized for the gateway, and supply it as the gateway
parameter when creating your inner/real Connection
:
from fabric import Connection
c = Connection('internalhost', gateway=Connection('gatewayhost'))
As with any other Connection
, the gateway connection may be configured with
its own username, port number, and so forth. (This includes gateway
itself
- they can be chained indefinitely!)
ProxyCommand
¶
The traditional OpenSSH command-line client has long offered a ProxyCommand
directive (see man ssh_config), which
pipes the inner connection’s input and output through an arbitrary local
subprocess.
Compared to ProxyJump
style gateways, this adds overhead (the extra
subprocess) and can’t easily be nested. In trade, it allows for advanced tricks
like use of SOCKS proxies, or custom filtering/gatekeeping applications.
ProxyCommand
subprocesses are typically another ssh
command, such as
ssh -W %h:%p gatewayhost
; or (on SSH versions lacking -W
) the widely
available netcat
, via ssh gatewayhost nc %h %p
.
Fabric supports ProxyCommand
by accepting command string objects in the
gateway
kwarg of Connection
; this is used to populate a
paramiko.proxy.ProxyCommand
object at connection time.
Additional concerns¶
If you’re unsure which of the two approaches to use: use ProxyJump
style.
It performs better, uses fewer resources on your local system, and has an
easier-to-use API.
Warning
Requesting both types of gateways simultaneously to the same host (i.e.
supplying a Connection
as the gateway
via kwarg or config, and
loading a config file containing ProxyCommand
) is considered an error
and will result in an exception.