Tags

arm64 bit blacklistd bluepill bluetooth cu dns dovecot elf envsubst esp8266 filter freebsd ipfw lets_encrypt opensmtpd perl python shell ssh ssl stm32 template tls unbound yubikey

Powered by

blOg
maRkdown
awK
shEll

10/06/2023

[ ssh ]

202306100800 ssh

ssh possède une option assez pratique pour qui veut apporter des modifications à sa configuration sans tout casser:

 -G      Causes ssh to print its configuration after evaluating Host and
         Match blocks and exit.

Pour avoir une idée de ce qu'il est possible de configurer:

$ ssh -F /dev/null -G localhost | wc -l
81

On va donc plutôt filtrer la sortie:

$ ssh -F /dev/null -G localhost | grep -e port -e localhost
host localhost
hostname localhost
port 22
gatewayports no
nohostauthenticationforlocalhost no

AddressFamily

Cette option permet de définir l'usage d'ipv4, d'ipv6 ou des deux. Comme chez moi, le ssh ne fonctionne qu'en ipv6, je peux ajouter dans mon ~/.ssh/config:

AddressFamily inet6

Sauf que:

Je commence par identifier le problème:

$ echo 'AddressFamily inet6' > /tmp/ssh_config
$ ssh -F /tmp/ssh_config github.com
ssh: Could not resolve hostname github.com: Address family for hostname not supported
$ ssh -F /tmp/ssh_config github.com 192.168.0.1
ssh: Could not resolve hostname 192.168.0.1: Name does not resolve

Je distingue ces citoyens de seconde zone avec une directive Match:

$ cat /tmp/ssh_config 
Match host github.com,10.*,192.168.*
AddressFamily inet

Match all
AddressFamily inet6

et je teste:

$ ssh -F /tmp/ssh_config -G github.com | grep address
addressfamily inet
$ ssh -F /tmp/ssh_config -G gitlab.com | grep address
addressfamily inet6
$ ssh -F /tmp/ssh_config -G 192.168.0.1 | grep address
addressfamily inet

En cas de liste, attention à ne pas utiliser d'espace, uniquement la virgule. Pour le réseau 172.16.0.0/12, c'est un peu plus long:

$ grep 172 /tmp/ssh_config
$ Match host github.com,10.*,192.168.*,172.16.*,172.17.*,172.18.*,172.19.*,172.2?.*,172.30.*,172.31.*

Pour mon usage d'ipv4, je ne souhaite pas polluer mon .ssh/known_hosts:

$ cat /tmp/ssh_config
Match host github.com,192.168.*,10.*,172.16.*,172.17.*,172.18.*,172.19.*,172.2?.*,172.30.*,172.31.*
AddressFamily inet

Match host 1*
UserKnownHostsFile none

Match all
AddressFamily inet6

IdentityFile

J'ai une clef pour chaque serveur publique sur lequel je me connecte et j'ai la bonne idée de la nommer en fonction du serveur:

$ cat /tmp/ssh_config
Match host github.com,10.*,192.168.*,172.16.*,172.17.*,172.18.*,172.19.*,172.2?.*,172.30.*,172.31.*
AddressFamily inet

Match host 1*
UserKnownHostsFile none

Match all
AddressFamily inet6

Match host github.com,gitlab.com
IdentityFile ~/.ssh/%h

Je teste:

$ ssh -F /tmp/ssh_config -G github.com | grep -e address -e identityfile
addressfamily inet
identityfile ~/.ssh/%h
$ ssh -F /tmp/ssh_config -G gitlab.com | grep -e address -e identityfile
addressfamily inet6
identityfile ~/.ssh/%h
$ ssh -F /tmp/ssh_config -G localhost | grep -e address -e identityfile
addressfamily inet6
identityfile ~/.ssh/id_rsa
identityfile ~/.ssh/id_ecdsa
identityfile ~/.ssh/id_ecdsa_sk
identityfile ~/.ssh/id_ed25519
identityfile ~/.ssh/id_ed25519_sk
identityfile ~/.ssh/id_xmss
identityfile ~/.ssh/id_dsa

Parce que l'ordre compte

J'utilise toujours une clef sauf pour le tld .ru:

Match host github.com,10.*,192.168.*,172.16.*,172.17.*,172.18.*,172.19.*,172.2?.*,172.30.*,172.31.*
AddressFamily inet

Match host 1*
UserKnownHostsFile none

Match all
AddressFamily inet6
PreferredAuthentications publickey

Match host github.com,gitlab.com
IdentityFile ~/.ssh/%h

Match host *.ru
PreferredAuthentications password

Pas marche:

$ ssh -F /tmp/ssh_config -G fail.ru | grep -e preferredauthentications
preferredauthentications publickey

On ne peut pas redéfinir une directive, comme indiqué en début de page de manuel:

 Unless noted otherwise, for each parameter, the first obtained value will
 be used.  

Pour mon cas d'usage je peux:

Include et alias

La directive suivante définit un raccourci vers github.com

Host gh
Hostname github.com

que l'on peut placer dans un fichier dédié. Une directive Include :

$ cat /tmp/ssh_config_alias
Host gh
Hostname github.com

$ cat /tmp/ssh_config
Include /tmp/ssh_config_alias # Chemin complet car le fichier de config n'est pas un de ceux par défaut

Match host github.com,10.*,192.168.*,172.16.*,172.17.*,172.18.*,172.19.*,172.2?.*,172.30.*,172.31.*
AddressFamily inet

Match host 1*
UserKnownHostsFile none

Match all
AddressFamily inet6

Match host github.com,gitlab.com
IdentityFile ~/.ssh/%h

Match host *.ru
PreferredAuthentications password

Match all
PreferredAuthentications publickey

et le tour est joué:

$ ssh -F /tmp/ssh_config -G gh | grep -e address -e identityfile
addressfamily inet
identityfile ~/.ssh/%h

J'ai quelques machines virtuelles qui sont dans un sous-domaine dédié:

Host nbsd2?,al3?,fbsd4?
Hostname %n.xen

Mais ce n'est pas la bonne solution: le token %n n'est pas disponible dans une directive Hostname. Je vais utiliser les directives Canonicalize :

Match host nbsd2? al3? fbsd4?
CanonicalizeHostname yes
CanonicalDomains xen.bsdsx.fr # oui, le domaine complet

Si la configuration DNS est correcte alors:

$ ssh -F /tmp/ssh_config -G al30 | grep -e hostname
hostname al30.ni3.bsdsx.fr
canonicalizehostname true

Control

Quand on doit avoir plusieurs connections vers une machine, on comprend vite l'utilité des directives Control et ça ne coûte pas plus cher de l'activer par défaut:

$ cat /tmp/ssh_config_alias
ControlMaster auto
ControlPath ~/.ssh/.%r@%h:%p
...

Match vs Host

J'ai toujours utilisé la directive Host, c'est pour ce billet que je suis passé à Match. Ces deux directives ne diffèrent que par leur syntaxe:

Host *.ru *.ch
Match host *.ru,*.ch

mais seul Match permet ce genre de chose:

Match host *.prod.mon.domaine user backup localuser !production exec "id -Gn %u | grep -q admin"
PreferredAuthentications publickey
IdentitiesOnly yes
IdentityFile ~/.ssh/id_rsa_backup_with_force_command

Si:

alors on utilise une clef spécifique. Oui cet exemple est plutôt capillotracté (mais aucun drosophile n'a été ... lors de la rédaction de ce billet).

Un dernier pour la route

C'est plus par principe qu'autre chose mais si il y a bien un truc que je ne supporte pas c'est tout ce qui ne sert à rien (oui, je ne supporte pas grand chose :) . Quand je vois tous les fichiers testés par

$ ssh -v ...

je me dis que ces quelques lignes ne peuvent pas faire de mal:

GlobalKnownHostsFile /dev/null # je n'ai jamais créé les fichiers de cette directive
UserKnownHostsFile ~/.ssh/known_hosts # known_hosts2 n'existe pas
# Pour ne pas tester des clefs qui n'existent pas
IdentityFile ~/.ssh/id_rsa
IdentityFile ~/.ssh/id_ecdsa_sk
AddKeysToAgent yes # ajouter les clefs à l'agent lors de leur première utilisation

Enjoy !

Commentaires: https://github.com/bsdsx/blog_posts/issues/18


Lien vers ce billet