Elegant OpenSSH configuration
This is one part in a series on OpenSSH client configuration. Also read Secure OpenSSH defaults and The SSH agent.
The OpenSSH client is very robust, verify flexible, and very configurable. Many times I see people struggling to remember server-specific ssh flags or arcane, manual multi-hop procedures. I even see entire scripts written to automate the process.
But the vast majority of what you might want ssh to do can be abstracted
away with some configuration in your
All (or, at least, most) of these configuration directives are fully documented in the ssh_config manpage.
If you prefer, follow along with an example of a complete ~/.ssh/config file.
One of the first annoyances people have–and one of the first things
people try to fix–when using a command-line ssh client is having to type
in long hostnames. For example, the Research Computing login service is
$ ssh login.rc.colorado.edu
This particular name isn’t too bad; but coupled with usernames and
especially when used as part of an
scp, these fully-qualified domain
names can become cumbersome.
$ scp -r /path/to/src/ firstname.lastname@example.org:dest/
OpenSSH supports host aliases through pattern-matching in
Host login*.rc HostName %h.colorado.edu Host *.rc HostName %h.int.colorado.edu
In this example,
%h is substituted with the name specified on the
command-line. With a configuration like this in place, connections to
login.rc are directed to the full name
$ scp -r /path/to/src/ email@example.com:dest/
Failing that, other references to hosts with a
.rc suffix are
directed to the internal Research Computing domain. (We’ll use these
.rc domain segment could be moved from the
Host pattern to
HostName value; but leaving it in the alias helps to distinguish
the Research Computing login nodes from other login nodes that you may
have access to. You can use arbitrary aliases in the
too; but then the
%h substitution isn’t useful: you have to
enumerate each targeted host.)
Unless you happen to use the same username on your local workstation as
you have on the remove server, you likely specify a username using
@ syntax or
-l argument to the
$ ssh firstname.lastname@example.org
As with specifying a fully-qualified domain name, tracking and
specifying a different username for each remote host can become
burdensome, especially during an
scp operation. Record the correct
username in your
~/.ssh/config file in stead.
Match host=*.rc.colorado.edu,*.rc.int.colorado.edu User user1234
Now all connections to Research Computing hosts use the specified username by default, without it having to be specified on the command-line.
$ scp -r /path/to/src/ login.rc:dest/
Note that we’re using a
Match directive here, rather than a
host= argument to
Match matches against the
derived hostname, so it reflects the real hostname as determined using
Host directives. (Make sure the correct
established earlier in the configuration, though.)
Even if the actual command is simple to type, authenticating to the host
may be require manual intervention. The Research Computing login nodes,
for example, require two-factor authentication using a password or pin
coupled with a one-time VASCO password or Duo credential. If you want to
open multiple connections–or, again, copy files using
authenticate with multiple factors quickly becomes tedious. (Even having
to type in a password at all may be unnecessary; but we’ll assume, as is
the case with the Research Computing login example, that you can’t use
OpenSSH supports sharing a single network connection for multiple ssh sessions.
Match host=login.rc.colorado.edu ControlMaster auto ControlPath ~/.ssh/.socket_%h_%p_%r ControlPersist 4h
ControlPath defined, the first ssh
connection authenticates and establishes a session normally; but future
connections join the active connection, bypassing the need to
re-authenticate. The optional
ControlPersist option causes this
connection to remain active for a period of time even after the last
session has been closed.
$ ssh login.rc email@example.com's password: [user1234@login01 ~]$ logout $ ssh login.rc [user1234@login01 ~]$
(Note that many arguments to the
ssh command are effectively ignored
after the initial connection is established. Notably, if X11 was not
-Y during the first session, you cannot use
the shared connection to forward X11 in a later session. In this case,
-S none argument to
ssh to ignore the existing
connection and explicitly establish a new connection.)
But what if you want to get to a host that isn’t directly available
from your local workstation? The hosts in the
domain referenced above may be accessible from a local network
connection; but if you are connecting from elsewhere on the Internet,
you won’t be able to access them directly.
Except that OpenSSH provides the
ProxyCommand option which, when
coupled with the OpenSSH client presumed to be available on the
intermediate server, supports arbitrary proxy connections through to
Match host=*.rc.int.colorado.edu ProxyCommand ssh -W %h:%p login.rc.colorado.edu
Even though you can’t connect directly to Janus compute nodes from the
Internet, for example, you can connect to them from a Research
Computing login node; so this
ProxyCommand configuration allows
transparent access to hosts in the internal Research Computing domain.
$ ssh janus-compile1.rc [user1234@janus-compile1 ~]$
And it even works with
$ echo 'Hello, world!' >/tmp/hello.txt $ scp /tmp/hello.txt janus-compile1.rc:/tmp hello.txt 100% 14 0.0KB/s 00:00 $ ssh janus-compile1.rc cat /tmp/hello.txt Hello, world!
If you tried the example above, chances are that you were met with an unexpected password prompt that didn’t accept any password that you used. That’s because most internal Research Computing hosts don’t actually support interactive authentication, two-factor or otherwise. Connections from a CURC login node are authorized by the login node; but a proxied connection must authenticate from your local client.
The best way to authenticate your local workstation to an internal CURC host is using public-key authentication.
If you don’t already have an SSH key, generate one now.
$ ssh-keygen -t rsa -b 4096 # if you don't already have a key
Now we have to copy the (new?) public key to the remote CURC
~/.ssh/authorized_keys file. RC provides a global home directory, so
copying to any login node will do. Targeting a specific login node is
useful, though: the
ControlMaster configuration for
login.rc.colorado.edu tends to confuse
$ ssh-copy-id login01.rc
ssh-copy-id command doesn’t come with OS X, but theres a
third-party port available on
usually available on a Linux system, too. Alternatively, you can just