Last years, with modern IaC tools, ssh
command and protocol feel less important. More tasks are done by crafting disposable software stacks in docker images, and by setting centralised observability solutions. And ssh acts as a «last resort» manual tool.
But software is still running on the servers, and we need access to those servers sometimes. Additionally, physical resource configuration still needs to be managed, and ssh
is a standard way to do this.
Using ssh
is easy. Public key authentication imposes some additional learning. After you'll get used to it, ssh
becomes some transparent routine.
ssh
allows you to customise configuration with a set of Host
and Match
rules in the config file. When the host alias matches one of those rules, the following configuration options apply to the connection. Some ssh configuration options can be used with percent interpolated variables, such as %h
for user-requested host alias.
For DevOps, it's important to provide a uniform way to connect to lookalike services and I have struggled to find that way for some time. Host
and Match
rules help, but at scale, even for 5 hosts, you'll need a little more flexibility. You can add something to the host alias for connecting FQDN HostName
, but you cannot modify anything within the host alias. And for this ProxyCommand
can be used to call arbitrary shell script and further modify connection options whatever you like.
Little more than one year ago Apple shipped macOS Ventura which doesn't allow SSH connections to hosts with RSA keys. In fact, RSA keys are fine (for now) as long as they are rsa-sha2-256
or rsa-sha2-512
type and at least 2048 bits long. To be on the safe side and not to be mistaken by RSA abbreviation, it is better to use any elliptic curve algorithm (ED25519
better than ECDSA
). Pretty funny that almost a decade ago in OpenSSH 7.0 DSA keys were considered unsafe and RSA is recommended, but now RSA is unsafe and EC DSA (which is Elliptic Curve DSA) is a possible replacement.
I don't want to configure every such host with legacy sshd. Some results from Google searches even recommend turning on RSA for all hosts which is probably not secure anymore.
What do we need to do? Just to add some options for specific hosts and make it visible that connections have reduced security.
How I'm doing this? Snippet from my ~/.ssh/config
:
Host *+legacy *+legacy+* *+rsa *+rsa+*
KexAlgorithms +diffie-hellman-group1-sha1
HostkeyAlgorithms +ssh-rsa
PubkeyAcceptedKeyTypes +ssh-rsa
ProxyCommand nc $(HN="%h"; echo "${HN%%%%+*}") %p
ssh config snipped above allows me to connect any host with reduced security when I explicitly ask for this like this with a specific host suffix — +rsa
:
$ ssh router-chaos-calmer+rsa
Shell expansion in ProxyCommand removes +rsa
tail from the host alias and applies options to enable RSA for this particular connection.
https://stackoverflow.com/questions/33444349/ssh-config-substitutions
Azure VMs don't have support for ecdsa or ed25519 key types, Microsoft recommends…
To work around this issue, use other SSH keys for the VM, such as RSA
…which are deprecated from OpenSSH 8.8. Shame! Workaround:
I'm using ssh for many hosts. It is a known problem when you're trying to connect to the new host, but you can't — even with a proper password. One of the reasons can be that the preferred authentication method is the public key, host allows you 5 tries to authenticate, your ssh client tries ~/.ssh/id_{rsa,ecdsa,ed25519}
, and a few keys from your ssh-agent. And you have no more authentication tries, you cannot enter the password because the host has already closed your SSH connection.
Usually solutions include one of three ssh options:
IdentitiesOnly yes
— stops sendingid_*
keys along with disabling of ssh-agent's usage; only keys explicitly defined in config or provided via-i
switch will be used.IdentityAgent none
— only disables ssh-agent.PreferredAuthentications password
orPubkeyAuthentication no
— use only passwords and do not use public key authentication at all.
Third option with additional suffix:
Host *+password *+password+*
PubkeyAuthentication no
PreferredAuthentications password
ProxyCommand nc $(HN="%h"; echo "${HN%%%%+*}") %p
Usage example:
$ ssh 192.168.1.42+password
This suffix trick also works for combined suffixes:
$ ssh 192.168.1.42+rsa+password
Sometimes your hotel blocks everything, except web browsing. Worse, if your home provider blocks port 22 and doesn't like incoming VPN connections.
In such, situations I'm using some preconfigured TLS server with HTTPS and SSH service multiplexing. I'll describe a server configuration in the next article, stay tuned!
Host *+tls *+tls+*
ProxyCommand openssl s_client -verify_quiet -quiet -alpn 'ssh2' -servername $(HN="%h"; echo "${HN%%%%+*}") -connect $(HN="%h"; echo "${HN%%%%+*}"):443
Now with +tls
suffix, it's possible to connect to my home network from a hotel room using overly restricted hotel WiFi.
When combining all the snippets above into ~/.ssh/config
please note:
ssh_config(5):
# For each parameter, the first obtained value will be used
+rsa
and +password
suffixes above using ProxyCommand
to cut suffix from the host alias and make reachable HostName
. If you ever need to use +tls
suffix with another suffix, +tls
suffix section in the config file should be above +rsa
or +password
. It is because ProxyCommand for +tls
not only replaces host alias suffix but also creates a TLS channel to your host.
For some hosts, you'll need to provide additional configuration, such as a key to connect. Usually, it looks like an additional Host
or Match
section with the host alias or template. Modify the Host
declaration to allow the use of suffixes:
# Before
Host server
IdentityFile ~/.ssh/server
…
# After
Host server server+*
IdentityFile ~/.ssh/server
…
Host aliases in Host
section match either of space-separated values. So, for example above, it's server
or server+<something>
. The Match
section is a little trickier because every rule in that section should be truthful.