Match It Before You SSH It

The widely used command line tools including Vim, Emacs are too versatile that you could not be able to master it in your life time. SSH is definitely one in this category one uses on a daily basis but there are all kinds of configs that one may never heard of but are surprisingly useful, and best of all, they are built-in features.

In this post, I will explain my journey to config my ssh setup such that it is able to help you connect to your ssh server seamlessly while using your mobile computing devices specifically laptops at different locations where your Mac and your server may or may not be in the same Local Area Network. To make it simpler, I will mainly focusing on Mac based operating system. I will explain the chain of thoughts on how my ssh server config file evolves to make it simpler, more elegant without losing its functionality. Please go to the end of this post to obtain the optimized version of the server config setup.

Let me explain further on what I want to achieve: I may want to connect to a computer through local area network or through internet connection depending on where I am, suppose the server I want to connect to is in my office. If I’m at the office, I want to connect to the machine via local area network, otherwise I may need to connect it through the internet. I don’t want always to connect to the server over the internet, especially when I’m in the office. The reason is fair and simple, I want to reduce the latency. The easiest way to handle it is to setup multiple configs for the same machine with different Host Aliases to identify they are separated setups, thus you have a setup for office network connection and another one for out of office. The problem is that this is not smart as it introduces more chaos to your workflow as in your code, you need to specify which specific ssh config you want to use when connecting to a server. I want a setup that is smart enough to help me connect to the right machine with the correct config, best of all with the same host alias, thus other scripts would not need to determine how to connect to the machine by themselves, such tasks are offloaded to ssh config. Noted that all the info I presented here are based on macOS as I mentioned before, please check your OS’s own manual to make sure the configs are properly set up.

Actually it is not too difficult to handle, as I saw many posts that could handle the issue by using the match condition in the ssh config setup. It turns out I need to rely on ssh’s Match function. It allows me to check a condition before applying a specific setup for a ssh connection.

The following snippets is used to connect to ssh server located in office through internet or through local area network. The key is to setup the Match condition correctly. In this example I use ping hostname

Match originalhost demo exec "ping -c 1 -W 1 ssh_server.lan >/dev/null 2>&1; [ $? -ne 0 ]"
  HostName ssh_sererver.company.com
  Port 8022
  User demo
  IdentityFile /Users/demo/.ssh/ssh_server
  IdentitiesOnly yes
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  LogLevel ERROR

Host demo
  HostName ssh_sererver.lan
  Port 22
  User demo
  IdentityFile /Users/demo/.ssh/ssh_server
  IdentitiesOnly yes
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  LogLevel ERROR
C

This looks like duplicate setups for 2 servers, but actually they do share the same alias which is demo. The key issue I need to mention especially on Mac is that you need to put the Match directive above the originalhost directive in your config which differs from what have been shown in 1 and 2, otherwise, the Match directive would not work. In this context, directive means a text block for setting up a ssh server, including HostName, Port, etc.

Match is versatile such that you could setup various criterias for your ssh servers to be connected. One step further would be how to setup those criterias based on the available parameters a session has, what kind of command line tools can be incorporated such that the you have a more general and effective setup on the decision making process.

To further utilize the match keyword, one needs to read through the manual on that specific part, this would be time consuming, I could only list a few things out here regarding how to use the match keyword and how to use tokens.

Match conditions: criteria keywords, all criteria, require args, negation,

exec TOKEN,

canonical
final
exec
TOKENS
     Arguments to some keywords can make use of tokens, which are expanded at runtime:

           %%    A literal ‘%’.
           %C    Hash of %l%h%p%r.
           %d    Local user's home directory.
           %f    The fingerprint of the server's host key.
           %H    The known_hosts hostname or address that is being searched for.
           %h    The remote hostname.
           %I    A string describing the reason for a KnownHostsCommand execution: either ADDRESS      when looking up a host by address (only when CheckHostIP is enabled), HOSTNAME when searching by  hostname, or ORDER when preparing the host key algorithm preference list to use for the destination host.
           %i    The local user ID.
           %K    The base64 encoded host key.
           %k    The host key alias if specified, otherwise the original remote hostname given on the
                 command line.
           %L    The local hostname.
           %l    The local hostname, including the domain name.
           %n    The original remote hostname, as given on the command line.
           %p    The remote port.
           %r    The remote username.
           %T    The local tun(4) or tap(4) network interface assigned if tunnel forwarding was requested, or "NONE" otherwise.
           %t    The type of the server host key, e.g.  ssh-ed25519
           %u    The local username.
Markdown

I will provide another example based on the knowledge shown above and a new scenario, where the server is accessible on your company’s local network with a domain name, the firewall does not allow users outside of the company’s network to access. You could still login through a proxy server which is inside the company’s network.

Host proxyserver
  HostName proxyserver.comany.com
   port 22
   User demo
   IdentityFile /Users/demo/ssh/proxy_ssh_server
   IdentitiesOnly yes

Host demo
  HostName ssh_server.company.com
  Port 22
  User demo
  IdentityFile /Users/demo/.ssh/ssh_server
  IdentitiesOnly yes
  StrictHostKeyChecking no
  UserKnownHostsFile /dev/null
  LogLevel ERROR
  Match originalhost proxyserver demo exec "nc -G 1 %h %p > /dev/null 2>&1; [ $? -ne 0]"
C

This time, the command nc is used to see certain port of a remote server is accessible or not, if it is accessible, we could connect it directly, otherwise, a proxy jump is needed. %h and %p represent the remote hostname and the remote port, which should be ssh_server.company.com and 22, the Match directive is located a bit differently than the first example, but they both work in the same fashion.

That perhaps is all I want to share regarding how to use match keyword on you ssh config file when your setup and you specific needs get more complex and you still want to minimize any distraction when working on your machines.

  1. Using ssh_config Match to connect to a host using multiple IP or Hostnames[]
  2. Tunneling an SSH connection only when necessary using Match[]

Posted

in

,

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *