Skip to content

Instantly share code, notes, and snippets.

@apla
Last active January 10, 2024 17:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save apla/f51b8c4bc27f574cec935189a4388661 to your computer and use it in GitHub Desktop.
Save apla/f51b8c4bc27f574cec935189a4388661 to your computer and use it in GitHub Desktop.
SSH ProxyCommand unusual use cases

SSH ProxyCommand unusual use cases

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.

Old hosts with RSA (or Azure)

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

Note about Azure

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:

Azure/AzureVM#26

Hosts with password authentication

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 sending id_* 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 or PubkeyAuthentication 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

TLS multiplexing HTTPS + SSH on port 443

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.

Closing notes on suffixes

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment