ssh config trick

Overcoming lack of %n token in IdentityFile

This was started as a ~/.ssh cleanup. Single config file for every host:

# another globals omited
IdentitiesOnly yes
IdentityFile id_%r
IdentityFile ~/.ssh/%h/id_%r

# basically bare minimum
Host github.com
User git

# just add another entry and that's it
Host peptide
HostName 192.168.0.201
Port 1234
User remote

And separate directory per host for identities:

$ tree ~/.ssh
config
github.com
   id_git
   id_git.pub
peptide
   id_remote
   id_remote.pub

After inventing such a great scheme that structure well enought SSH keys directory, it was a bit disappointing to find out there is no way to use Host as a name for directory with identities. man ssh_config says:

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

           %%    A literal `%'.
           %C    Shorthand for %l%h%p%r.
           %d    Local user's home directory.
           %h    The remote hostname.
           %i    The local user ID.
           %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.
           %u    The local username.

     Match exec accepts the tokens %%, %h, %L, %l, %n, %p, %r, and %u.

     CertificateFile accepts the tokens %%, %d, %h, %l, %r, and %u.

     ControlPath accepts the tokens %%, %C, %h, %i, %L, %l, %n, %p, %r, and %u.

     HostName accepts the tokens %% and %h.

     IdentityAgent and IdentityFile accept the tokens %%, %d, %h, %l, %r, and %u.

     LocalCommand accepts the tokens %%, %C, %d, %h, %l, %n, %p, %r, and %u.

     ProxyCommand accepts the tokens %%, %h, %p, and %r.

     RemoteCommand accepts the tokens %%, %C, %d, %h, %l, %n, %p, %r, and %u.

It means, this works well as intended but not as expected by the scheme:

$ ssh remote@peptide date
no such identity: id_remote: No such file or directory
no such identity: /home/paul/.ssh/192.168.0.201/id_remote: No such file or directory

Not good at all. Even so, workaround exists. Placing this line at the end of ~/.ssh/config does a dirty fix.

Match exec "[ %n != %h ] && [ -d %n ] && ln -fs ~/.ssh/%n ~/.ssh/%h"

Usually, Match narrows ongoing Host declarations, e.g pointing to another location of a id_rsa file when user@ came from command line. This time it works as a sort of autorun command. It compares "original" remote (nice mnemonic name for the host) with HostName from config file and force creation of a symlink to the directory with keys. Even though it look like misuse, it works nice in another context too. Match may help in transparent port knocking:

Host alp
HostName 127.0.0.1
Match exec "for port in 3000 4000 5000; do nc -zw3 %h $port; sleep 1; done"

Hacky, right?