---
categories: openbsd sysadmin
title: Howto OpenSSH
...

* Documentation : <https://www.openssh.com/manual.html>

[OpenSSH](https://www.openssh.com/) est l'implémentation la plus répandue du protocole SSH permettant de se connecter sur une machine à travers le réseau de manière sécurisée.
OpenSSH est développé par le projet [OpenBSD](HowtoOpenBSD) avec une grande attention sur la sécurité. Il offre de nombreuses fonctionnalités : SCP, SFTP, clés SSH, tunnels, VPN, etc.


## Installation

### Debian

On peut installer les parties client et serveur indépendamment :

~~~
# apt install openssh-client
# ssh -V
OpenSSH_7.4p1 Debian-10+deb9u1, OpenSSL 1.0.2l  25 May 2017

# apt install openssh-server
# nc localhost 22
SSH-2.0-OpenSSH_7.4p1 Debian-10+deb9u1
# systemctl status ssh
● ssh.service - OpenBSD Secure Shell server
   Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
 Main PID: 1715 (sshd)
    Tasks: 1 (limit: 4915)
   CGroup: /system.slice/ssh.service
           └─1715 /usr/sbin/sshd -D
~~~

### OpenBSD

Les parties client et serveur sont incluses dans la base OpenBSD.

~~~
$ ssh -V
OpenSSH_7.5, LibreSSL 2.5.2
~~~

La partie serveur est activée par défaut, sauf mention contraire à l'installation.

~~~
# grep -r sshd /etc/rc.conf*
/etc/rc.conf:sshd_flags=
/etc/rc.conf.local:sshd_flags=NO

# rcctl enable sshd
~~~


## Configuration

### Configuration sshd_config

<http://man.openbsd.org/sshd_config>

Fichiers de configuration :

~~~
/etc/ssh
├── moduli
├── ssh_config
├── sshd_config
├── ssh_host_ecdsa_key
├── ssh_host_ecdsa_key.pub
├── ssh_host_ed25519_key
├── ssh_host_ed25519_key.pub
├── ssh_host_rsa_key
└── ssh_host_rsa_key.pub
~~~

La configuration de base que nous utilisons en général (les options commentées sont les valeurs par défaut).

~~~
#   $OpenBSD: sshd_config,v 1.100 2016/08/15 12:32:04 naddy Exp $

# This is the sshd server system-wide configuration file.  See
# sshd_config(5) for more information.

# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin

# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented.  Uncommented options override the
# default value.

Port 22
Port 2200
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key

# Ciphers and keying
#RekeyLimit default none

# Logging
#SyslogFacility AUTH
LogLevel VERBOSE

# Authentication:

#LoginGraceTime 2m
PermitRootLogin no
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

#PubkeyAuthentication yes

# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2

#AuthorizedPrincipalsFile none

#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody

# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes

# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no

# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no

# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no

# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no

# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication.  Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes

#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#UsePrivilegeSeparation sandbox
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none

# no default banner path
#Banner none

# Allow client to pass locale environment variables
#AcceptEnv LANG LC_*

# override default of no subsystems
Subsystem   sftp    /usr/lib/openssh/sftp-server -l INFO

# Example of overriding settings on a per-user basis
#Match User anoncvs
#   X11Forwarding no
#   AllowTcpForwarding no
#   PermitTTY no
#   ForceCommand cvs server

AllowUsers jdoe alice bob

Match Address 192.0.2.42
    PasswordAuthentication yes
Match User alice bob
    PasswordAuthentication no
Match Group adm
    PasswordAuthentication no
~~~


#### Vérification / check de la configuration SSHD

Utile pour ne pas s'enfermer dehors :

~~~
$ sshd -t
~~~

Même chose, en affichant aussi la configuration sur la sortie standard :

~~~
$ sshd -T
~~~

### Configuration ssh_config

<http://man.openbsd.org/ssh_config>

On peut configurer la partie client via le fichier `~/.ssh/config`.

On peut ainsi passer certaines options générales :

~~~
UseRoaming no
User jdoe
IdentityFile ~/.ssh/id_ed25519
IdentityFile ~/.ssh/id_rsa
~~~

On peut aussi passer des options spécifiques à chaque serveur distant sur lequel on va se connecter.
On définit ainsi des *alias* (utilisables ensuite via `ssh`) et des options correspondantes :

~~~
Host foo ssh.example.com
    Hostname ssh.example.com
    Port 2222
    User john

Host sql.example.com
    IdentityFile ~/.ssh/id_bastion_ed25519
    ProxyCommand ssh bastion.example.com -W %h:%p
    StrictHostKeyChecking no
    UserKnownHostsFile /dev/null

Host nfs.example.com
    ProxyCommand ssh -W bastion.example.com:2222 john@192.0.2.111

Host switch42
    User admin
    HostName 192.0.2.150
    ProxyCommand sh -c "nc -w1 %h %p 2>/dev/null || ssh bastion.example.com -W %h:%p"
    KexAlgorithms diffie-hellman-group1-sha1
~~~

Pour les cas simples d'utilisation de `ProxyCommand`, il est possible d'utiliser `ProxyJump [user@]host[:port]` (équivalent à l'option `-J` en ligne de commande :

~~~
Host private.example.com
    ProxyJump bastion.example.com
~~~

## SCP

Le protocole SCP (Secure Copy) est basé sur SSH, il permet de transférer des fichiers entre deux machines distantes de façon sécurisée.

Utilisation simple :

~~~
$ scp /foo/FICHIER ssh.example.com:/bar/
~~~

Pour envoyer un répertoire, on utilisera l'option `-r` :

~~~
$ scp -r /foo/ ssh.example.com:/bar/
~~~

Options utiles pour `scp` :

* `-P 2222` : utilise le port 2222 pour le serveur distant (malheureusement différent de `ssh`…)
* `-q` : mode silencieux
* `-C` : active la compression
* `-i identity_file` : utilise une clé SSH spécifique


## SFTP

Le protocole SFTP correspond au **SSH File Transfer Protocol** : c'est une extension du protocole SSH qui permet non seulement de transférer des fichiers (comme [SCP](HowtoOpenSSH#scp)) mais aussi d'avoir des fonctionnalités plus avancées (listing de répertoire, suppression de fichiers, etc.) similaire au vieux protocole FTP :

~~~
$ sftp ssh.example.com
Connected to ssh.example.com.
sftp> ls
sftp> lls
sftp> pwd
sftp> get FICHIER
sftp> put FICHIER
sftp> bye
~~~

### chroot SFTP

On peut restreindre un accès SFTP dans un répertoire, les utilisateurs n'auront accès qu'à une vue limitée de l'arborescence du système.

Pour mettre en place un chroot SFTP, on crée un répertoire `/home/sftp` et un groupe `sftp` :

~~~
# mkdir /home/sftp
# chown root:sftp /home/sftp
# chmod 750 /home/sftp

# groupadd sftp
~~~

et on configure via `/etc/ssh/sshd_config` :

~~~
Subsystem sftp internal-sftp

Match group sftp
   ChrootDirectory /home/sftp
   X11Forwarding no
   AllowTcpForwarding no
   ForceCommand internal-sftp
~~~

On peut ensuite créer un utilisateur restreint :

~~~
# useradd -g sftp -d /jdoe jdoe
# mkdir /home/sftp/jdoe/
# chown jdoe:sftp /home/sftp/jdoe/
# chmod 700 /home/sftp/jdoe/
~~~

### SFTP Only

On peut restreindre un utilisateur au protocole SFTP.
Il faut s'assurer que `/usr/lib/sftp-server` soit un shell valide et lui définir comme shell par défaut :

~~~
# echo '/usr/lib/stfp-server' >> /etc/shells
# usermod -s /usr/lib/sftp-server userna
~~~


## Clé SSH

Il y a plusieurs types de clé, avec suivant les algorithmes, des tailles de clés variables ou non.
L'algorithme que nous conseillons est *ed25519* mais attention, ce n'est pas supporté sur des anciennes machines (Debian 7 par exemple) où il faut utiliser l'algorithme *RSA* (on conseille alors d'utiliser une taille de clé de 4096).

Attention, lors de la génération de votre paire de clés, si vous ne conservez pas le nom et l'emplacement par défaut ( qui est sous la forme `~/.ssh/id_{rsa,ed25519}`) alors la clé ne sera pas utilisée par le client SSH. Il faudra alors lui indiquer de l'utiliser de manière explicite avec avec l'argument *-i* pour spécifier la clé privée, ou le définir dans le [fichier de configuration de SSH](#configuration-ssh_config),

Pour générer une clé SSH *ed25519* :

~~~
$ ssh-keygen -t ed25519 -a 100
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/jdoe/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/jdoe/.ssh/id_ed25519.
Your public key has been saved in /home/jdoe/.ssh/id_ed25519.pub.
The key fingerprint is:
SHA256:7tdFlczm4VJkEl4yM08O4VOPkGQiU1YR8kKuLsm9v84 jdoe@example.com
The key's randomart image is:
+--[ED25519 256]--+
|        o.*oB&**.|
|         * =+.#Oo|
|          o .+*+o|
|         . . .oo |
|        S    ..  |
|     . =      .  |
|      + +  . .   |
|       o o. .    |
|        o+E.     |
+----[SHA256]-----+
~~~

> *Note* : l'option -a 100 spécifie le nombre d'itérations de l'algorithme de dérivation de clé qui protège la clé privée avec la passphrase utilisée. Cela protège la clé privée contre le brute-force de la passphrase.  Mais attention, plus ce nombre est grand, plus le déchiffrement de la clé est ralenti. Un bon compromis est *100* en nombre d'itérations.

Pour générer une clé SSH *RSA* :

~~~
$ ssh-keygen -o -t rsa -b 4096 -a 100
Generating public/private rsa key pair.
Enter file in which to save the key (/home/jdoe/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/jdoe/.ssh/id_rsa.
Your public key has been saved in /home/jdoe/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:9tGKNLEbiUyAbhShJ7rncBpn/ydCXZHtJkdIsUoW2TM jdoe@example.com
The key's randomart image is:
+---[RSA 4096]----+
|  o+. .+o=       |
| .o  ...E.o      |
|oo.   + o*       |
|.oo  = oo++.     |
|..   .+.S+. .    |
| .  . .o * o     |
|+ =.    o o      |
| X .. . .        |
|. . .o.o         |
+----[SHA256]-----+
~~~

> *Note* : dans le cas de *RSA*, on utilise  [l'argument `-o`](http://man.openbsd.org/ssh-keygen#o) afin que la clé privée utilise le nouveau format qui est à la fois [standard](https://tools.ietf.org/html/rfc4716) et plus résistant aux attaques par brute-force.

### authorized_keys

Pour autoriser une connexion avec une clé SSH, il faut la placer dans le fichier `~/.ssh/authorized_keys` et ajuster les droits :

~~~
$ ssh ssh.example.com mkdir -p ~/.ssh
$ ssh ssh.example.com chmod 700 ~/.ssh
$ scp ~/.ssh/id_ed25519.pub ssh.example.com:.ssh/authorized_keys
$ ssh ssh.example.com chmod 600 ~/.ssh/authorized_keys
~~~

Pour faire cela de façon plus simple, on peut utiliser le script `ssh-copy-id` :

~~~
$ ssh-copy-id ssh.example.com
~~~

> *Note* : pour préciser un port alternatif, on peut utiliser l'option `-p NN` depuis Debian 8. En Debian 7, il faut utiliser `ssh-copy-id "-pNN ssh.example.com"`

On peut mettre des restrictions d'accès via le fichier `.ssh/authorized_keys`, par exemple :

~~~
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa XXXXX commentaires
~~~

### Agent SSH

Il est important de protéger une clé SSH utilisée par un humain par une passphrase.
Pour éviter de saisir sa passphrase à chaque utilisation, on peut utiliser un *agent SSH* qui va retenir la clé SSH en mémoire.

En général, un agent SSH est lancé par son Window Manager.
Sinon, on peut le lancer automatiquement via son `~/.profile` :

~~~{.bash}
eval $(ssh-agent) 1> /dev/null
~~~

Une fois lancé, l'agent ouvre une socket Unix dans `$TMPDIR/ssh-XXXXXXXXXX/agent.PPID` et la rend disponible via les variables d'environnement suivantes :

~~~{.bash}
SSH_AUTH_SOCK=/tmp/ssh-IklIVmCGvWgT/agent.1151
SSH_AGENT_PID=1198
~~~

On peut alors lancer la commande `ssh-add` qui va nous demander notre passphrase pour transmettre la clé à l'agent SSH :

~~~
$ ssh-add -t 36000
Enter passphrase for /home/jdoe/.ssh/id_ed25519:
Identity added: /home/jdoe/.ssh/id_ed25519 (/home/jdoe/.ssh/id_ed25519)
~~~

> *Note* : l'option [-t](http://man.openbsd.org/ssh-agent#t) permet de limiter à 10h (36 000 secondes) le temps où l'agent va conserver la passphrase en mémoire. Si l'option n'est pas utilisée, ce temps sera infini, ce que l'on déconseille en général.

Sous Gnome, si vous utilisez `gnome-keyring-ssh` il se peut que vous ayez l'erreur `Could not add identity` pour votre clé id_ed25519. Il faut alors appliquer le correctif suivant :

~~~
mkdir -p ~/.config/autostart
cp /etc/xdg/autostart/gnome-keyring-ssh.desktop ~/.config/autostart/
echo "X-GNOME-Autostart-enabled=false" >> ~/.config/autostart/gnome-keyring-ssh.desktop
~~~

On peut également utiliser l'outil [keychain](https://www.funtoo.org/Keychain) qui facilite l'utilisation d'un agent SSH (et d'un agent GPG).
Il va notamment lancer les agents si ils ne sont pas encore lancés, et transmettre plusieurs clés SSH si besoin.

~~~
$ keychain id_ed25519 id_rsa --timeout 600

 * keychain 2.7.1 ~ http://www.funtoo.org
 * Starting ssh-agent...
 * Starting gpg-agent...
 * Adding 2 ssh key(s): /home/jdoe/.ssh/id_ed25519 /home/jdoe/.ssh/id_rsa
Enter passphrase for /home/jdoe/.ssh/id_ed25519:
 * ssh-add: Identities added: /home/jdoe/.ssh/id_ed25519 /home/jdoe/.ssh/id_rsa (life=600m)
~~~

> *Note* : on pourra bien sûr lancer *keychain* via son `~/.profile`

Enfin, il existe d'autres implémentations d'agent SSH, comme le  `gpg-agent` qui permet notamment l'utilisation de token USB pour sécuriser ses clés (Voir [HowtoGPG](HowtoGPG#agent-gpg)).


## Tunnel SSH

Un tunnel SSH permet d'accéder à une ressource distante via une connexion SSH.
Cela s'utilise classiquement pour accéder à un service distant non accessible directement.

### Tunnel SSH vers un service

Exemple simple : on veut accéder à un service MySQL accessible en local sur un serveur distant.
On lance la commande suivante :

~~~
$ ssh -L 3306:127.0.0.1:3306 ssh.example.com
~~~

Et l'on pourra accéder au service MySQL sur sa propre machine via 127.0.0.1 sur le port 3306.

Si le service MySQL est sur une 3ème machine (accessible depuis le serveur distant), il suffit de préciser son IP avec l'option `-L` :

~~~
$ ssh -L 3306:192.0.2.33:3306 ssh.example.com
~~~

On peut bien sûr utiliser un port différent pour sa propre machine, par exemple 8306 :

~~~
$ ssh -L 8306:192.0.2.33:3306 ssh.example.com
~~~

De même, si l'on veut se « binder » sur une autre IP que 127.0.0.1 sur sa propre machine, on peut le préciser avec l'option `-L` :

~~~
$ ssh -L 127.0.0.33:8306:192.0.2.33:3306 ssh.example.com
~~~

Enfin il faut noter que si l'on veut utiliser un port local inférieur à 1024, il faudra lancer la commande en "root" :

~~~
# ssh -L 443:127.0.0.1:443 ssh.example.com
~~~

### Tunnel SSH inverse

Si l'on est derrière une connexion NAT par exemple, on peut ouvrir un tunnel pour permettre une connexion distante depuis une machine accessible en SSH :

~~~
$ ssh -R 22000:127.0.0.1:22 ssh.example.com
~~~

Depuis *ssh.example.com* on peut ainsi accéder à la machine derrière le NAT via `ssh -p22000 127.0.0.1`.

### Proxy SOCKS via SSH

On peut lancer un proxy SOCKS passant par un serveur distant ainsi :

~~~
$ ssh -D 6789 ssh.example.com
~~~

Il reste ensuite à configurer le logiciel qui va utiliser ce proxy SOCKS (4a ou 5) avec l'adresse 127.0.0.1 et le port 6789.
C'est ainsi pratique avec un navigateur où l'ensemble du trafic vers le web passera ainsi par le serveur distant.


## Astuces

### Convertir une clé publique format PUTTY en format OpenSSH

~~~
ssh-keygen -i -f keyfile.pub > newkeyfile.pub
~~~

### Loguer/exécuter script avant chaque connexions SSH

Grâce au fichier placé dans ~~~/etc/ssh/sshrc~~~, juste avant toutes connexions ssh (rsync, sftp, ssh, ...), le contenu sera exécuté avant la session ssh ouverte.

### Séquences d'échappement SSH

<https://lonesysadmin.net/2011/11/08/ssh-escape-sequences-aka-kill-dead-ssh-sessions/>

On peut utiliser des combinaisons de touches spéciales via une connexion SSH pour intéragir avec la connexion en cours.

En tapant `Entrée + ~ + ?` on obtient la liste des séquences possibles :

~~~
Supported escape sequences:
 ~.   - terminate connection (and any multiplexed sessions)
 ~B   - send a BREAK to the remote system
 ~C   - open a command line
 ~R   - request rekey
 ~V/v - decrease/increase verbosity (LogLevel)
 ~^Z  - suspend ssh
 ~#   - list forwarded connections
 ~&   - background ssh (when waiting for connections to terminate)
 ~?   - this message
 ~~   - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)
~~~

Voici les séquences les plus utiles :

* `Entrée + ~ + .` : forcer à terminer la connexion SSH en cours (utile en cas de perte de connexion…)
* `Entrée + ~ + v` : diminue la verbosité, par exemple quand on s'est connecté avec `ssh -vvv`

Quelques exemples de manipulations possibles (en anglais) : <https://omecha.info/blog/ssh-escape-commands-for-fun-and-profit.html>

### Connexion SSH par rebond

Il se peut qu'on doive passer par une machine pour se connecter en SSH à une machine cible (c'est le principe d'un [bastion](https://fr.wikipedia.org/wiki/Bastion_(informatique))).

On peut ainsi se connecter avec `-o ProxyCommand` :

ssh -o ProxyCommand="ssh -W cible.example.com:22 bastion.example.com" cible.example.com

Dans les versions récentes d'OpenSSH (notamment sur Debian 9) il existe une méthode plus simple :

~~~
$ ssh -J bastion.example.com cible.example.com
~~~

> *Note* : il ne faut pas utiliser l'option `-A` pour rebondir car elle est dangereuse, à moins que vous ne vouliez vraiment faire du [Agent forwarding](HowtoOpenSSH#agent-forwarding)

### Agent forwarding

Si vous voulez utiliser une [clé SSH](HowtoOpenSSH#cle-SSH) locale depuis un serveur distant, vous pouvez utiliser l'option `-A` qui va rendre votre agent local accessible depuis le serveur distant :

~~~
$ ssh -A ssh.example.com
$ env | grep ^SSH_A
SSH_AUTH_SOCK=/tmp/ssh-sUSruIwyCa/agent.3265
~~~

> *Note* : attention, cette option doit être utilisée en connaissance de cause car l'utilisateur *root* sur la machine *ssh.example.com* aura accès à vos clés et donc aux machines distantes auxquelles vous avez accès avec vos clés.

On peut également ajouter les clés SSH présentes sur un serveur distant en faisant :

~~~
$ ssh ssh.example.com -t -A ssh-add
~~~

### VPN over SSH

On peut utiliser OpenSSH comme VPN !
Côté serveur, vous devez :

- Ajouter `PermitTunnel yes`
- Autoriser l'IP Forwarding : `sysctl -w net.ipv4.ip_forward=1`
- Si besoin, mettre une règle de NAT, par exemple sous Linux : `iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE`

Pour lancer la connexion VPN, on fera :

~~~
# ssh -w 42:42 ssh.example.com
~~~

On a ensuite un périphérique `tun42` utilisable, à configurer des 2 côtés.

- Côté serveur SSH : `ifconfig tun42 172.17.18.2/24`
- Côté client  SSH : `ifconfig tun42 172.17.18.1/24`

On peut alors enfin configurer le routage au niveau client, par exemple sous Linux :

~~~
# ip route add 8.8.8.8/32 via 172.17.18.2 dev tun42`
~~~

### UserKnownHostsFile

OpenSSH se sert du fichier `~/.ssh/known_hosts` pour retenir l'empreinte (_fingerprint_) de chaque connexion effectuée.
Cela lui permet de détecter un changement des clés du serveur, notamment une tentative d'usurpation d'un serveur :

~~~
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
~~~

On peut accepter automatiquement la clé à la première connexion ainsi :

~~~
$ ssh -o "StrictHostKeyChecking=accept-new" ssh.example.com
~~~

Si besoin, on peut supprimer la ligne concernée dans `~/.ssh/known_hosts` via une commande du type :

~~~
$ ssh-keygen -f "~/.ssh/known_hosts" -R ssh.example.com
$ ssh-keygen -f "~/.ssh/known_hosts" -R [ssh.example.com]:2222
~~~

On peut également désactiver cette vérification en utilisant un fichier alternatif :

~~~
$ ssh -o UserKnownHostsFile=/dev/null ssh.example.com
~~~

On peut également générer à l'avance les fingerpints dans un fichier `~/.ssh/known_hosts2` (utilisé par défaut).

Pour générer les fingerprints, on peut utiliser la commande `ssh-keyscan` :

~~~
$ ssh-keyscan ssh.example.com
ssh.example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2nP2WzQ8hkZDiEq5+QSGFhTB7SYfRa7/IG0gMOIoCDXH8b3sfsBUUEL8ZSFaWgNKskUnpgg/fqAhvnDLOPskr3OGXRfrCR68fCqn5H1zBrHB1kpdjPW9ezUe1xoY3hGp6LITANHWpZie1wBjYAzaBO70hNAo4JMCQvZXDsQdyws2DRSuYtiAoG/ZY0+t2VZh3MJLcofv1wNo43M+aHJR2xWmQSE7cWjMlcw/QOmsWJBv1+Kb/nK2Q7buX/byvY8ySu5ydATnyEinzbutZXc/t/FioOtWMeqh6NlD3aPGIpUTmf8ow+c1QwZWOC3T2GWyTD5KVmAZSm77lWkpYFcd1
ssh.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBsUneE642qr/kzKwJcKl9Cgog/kgCqRLZwZs4J7RRt8
~~~

Puis on crée un fichier contenant :

~~~
example-ssh,ssh.example.com,192.0.2.42 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2nP2WzQ8hkZDiEq5+QSGFhTB7SYfRa7/IG0gMOIoCDXH8b3sfsBUUEL8ZSFaWgNKskUnpgg/fqAhvnDLOPskr3OGXRfrCR68fCqn5H1zBrHB1kpdjPW9ezUe1xoY3hGp6LITANHWpZie1wBjYAzaBO70hNAo4JMCQvZXDsQdyws2DRSuYtiAoG/ZY0+t2VZh3MJLcofv1wNo43M+aHJR2xWmQSE7cWjMlcw/QOmsWJBv1+Kb/nK2Q7buX/byvY8ySu5ydATnyEinzbutZXc/t/FioOtWMeqh6NlD3aPGIpUTmf8ow+c1QwZWOC3T2GWyTD5KVmAZSm77lWkpYFcd1
example-ssh,ssh.example.com,192.0.2.42 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBsUneE642qr/kzKwJcKl9Cgog/kgCqRLZwZs4J7RRt8
~~~

Ce fichier contenant les fingerprints peut aussi être placé dans `/etc/ssh/ssh_known_hosts` ou `/etc/ssh/ssh_known_hosts2` et sera ainsi utilisé par défaut par tous les utilisateurs d'une machine.

Une autre technique pour vérifier un fingerprint est d'avoir des enregistrements DNS SSHFP.
On peut les générer à l'aide de la commande `ssh-keygen` :

~~~
$ ssh-keygen -r ssh.example.com
ssh.example.com IN SSHFP 1 1 b0db7dbfe0775199662453c9d6eace6f993b9fdc
ssh.example.com IN SSHFP 1 2 13e60f2c4d2848aea91c420b783273afe6c23efd23818ab220f167a53a0be886
ssh.example.com IN SSHFP 2 1 c2ea7d50f05af4cabc8e6add3491a08654127f83
ssh.example.com IN SSHFP 2 2 1222b6f7ad0d3447a31e3cba1af2eaf8aab7316570b63cc3eccdd4d865fee474
ssh.example.com IN SSHFP 3 1 d93dbd0af9c7fd456b3fa4e9094ede031791da84
ssh.example.com IN SSHFP 3 2 3b885c365ae3cebab6dea63b3eb697d2060d9da906e129011841d665a4ccfe4f
ssh.example.com IN SSHFP 4 1 39d521c3d4b6f672149c1cc053014c9ebdfd4727
ssh.example.com IN SSHFP 4 2 0f28d1764793b519c9c74bfb7c6d0dc9b980bdf22c68d1e324d19247d8cbe161
~~~

On peut ainsi vérifier à la connexion :

~~~
$ ssh -o "VerifyHostKeyDNS ask" ssh.example.com
The authenticity of host 'ssh.example.com (192.0.2.42)' can't be established.
ED25519 key fingerprint is SHA256:sln94vzrKSsTezPvT6pyO/Glavvl7/Ao8Wcd46BeRb0.
Matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)?
~~~

### ControlMaster

OpenSSH peut permettre de réutiliser une connexion en cours pour d'autres connexions via l'option `ControlMaster`.
Si l'on veut activer ce comportement, on pourra ajouter dans `~/.ssh/config` :

~~~
ControlMaster auto
ControlPath ~/.ssh/ssh_control_%h_%p_%r
~~~

### SSHFS

[SSHFS](https://github.com/libfuse/sshfs) permet de créer des montages via une connexion SSH.

Pour monter :

~~~
# apt install sshfs
$ sshfs user@ssh.example.com:/foo/bar /mnt
~~~

Pour démonter :

~~~
$ fusermount -u /mnt
~~~

Pour automatiser dans `/etc/fstab` :

~~~
user@ssh.example.com:/foo/bar /mnt fuse.sshfs noauto,user,_netdev,reconnect,x-systemd.automount,x-systemd.device-timeout=10,identityfile=<PRIVATE_KEY_PATH> 0 0
~~~


### X Forwarding

SSH peut créer automatiquement un tunnel et gérer la variable `$DISPLAY` pour afficher en local les applications graphiques distantes.
Côté serveur, il faut la présence du package `xauth` et l'option `X11Forwarding yes` dans la configuration SSH.
On peut alors lancer :

~~~
$ ssh -X ssh.example.com
$ xlogo
~~~

### mosh

<https://mosh.org/>

En cas de connexion réseau avec une latence réseau élevée ou instable (perte de paquets), on peut utiliser **mosh** qui vient se positionner après une connexion SSH en utilisant un port UDP dédiée à une session/utilisateur. Il gère aussi le roaming, c'est-à-dire que l'adresse IP source n'est pas importante pour garder la connexion (bascule ADSL vers LTE par exemple) et que la connexion peut être suspendue plusieurs heures sans problème (appareil en veille, coupure réseau…).

~~~
# apt install mosh
~~~

Pour se connecter basiquement (port SSH 22, utilisateur actuel). Il suffit grosso-modo de remplacer la commande ssh par mosh.

~~~
$ mosh server
~~~

Un exemple plus avancé.

~~~
$ mosh --ssh "ssh -p2222 -l user" server
~~~

Mosh va ouvrir une connexion ssh, puis la quitter pour basculer en UDP sur un port négocié (plage 60001:60999 par défaut). 
On peut tout à fait avoir la connexion SSH restreinte par un pare-feu (par exemple il faudra utiliser un VPN pour la connexion SSH), mais avoir la plage de ports UDP publiques.

### Restriction par IP en même temps que AllowGroups

Lorsqu'on utilise des autorisations à base de `AllowGroups` il n'est pas possible de spécifier des restriction par IP comme lorsqu'on utilise `AllowUsers` (exemple : `AllowUsers user1@IP user2@IP […] user3 user4`).

On peut contourner cette limitation en ajoutant un bloc `Match` avec le group et la ou les IP en conditions. Exemple avec root, restreint à 2 IP, avec clé uniquement :

~~~
Match User root Address 10.0.0.1,192.168.0.1
    AllowGroups root
    PubkeyAuthentication yes
    PasswordAuthentication no
    PermitRootLogin without-password
~~~

## FAQ

### Obtenir l'empreinte de la clé publique du serveur

~~~
$ ssh-keygen -lf /etc/ssh/clé.pub
~~~

### Regénérer les clés du serveur

#### Sous Debian :

~~~
# rm -i /etc/ssh/ssh_host_*
# dpkg-reconfigure openssh-server
Creating SSH2 RSA key; this may take some time ...
Creating SSH2 DSA key; this may take some time ...
Restarting OpenBSD Secure Shell server: sshd.
~~~

#### Sous OpenBSD :

~~~
# rm -i /etc/ssh/ssh_host_*
# ssh-keygen -A
ssh-keygen: generating new host keys: RSA DSA ECDSA ED25519
~~~

À noter que c'est fait à chaque boot (via */etc/rc*), si les clés
n'existent pas donc une autre solution est de supprimer les clés et de
rebooter.

### reload/restart le démon ssh sur Debian sans passer par le script d'init

Pour reload :

~~~
# start-stop-daemon --stop --signal 1 --quiet --oknodo --pidfile /var/run/sshd.pid --exec /usr/sbin/sshd
~~~

Pour redémarrer :

~~~
# start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile /var/run/sshd.pid
# start-stop-daemon --start --quiet --pidfile /var/run/sshd.pid --exec /usr/sbin/sshd
~~~

### Peut-on encore utiliser une clé SSH DSA ?

Les clés SSH avec l'algorithme DSA sont dépréciées depuis Stretch.

### Limitation du temps de connexion via SSH

On peut limiter le temps d'une connexion SSH inactive en utilisant la variable d'environnement *TMOUT*.
On peut provoquer une déconnexion automatique au bout d'1h d'activité en positionnant :

~~~{.bash}
export TMOUT=3600
~~~

À l'inverse, si l'on veut éviter une déconnexion automatique quand cette variable est positionnée, on peut la supprimer ou l'augmenter :

~~~
$ unset TMOUT
$ export TMOUT=999999
~~~

### Comment lister les clés SSH en mémoire d'un agent SSH ?

On peut utiliser la commande `ssh-add -l` :

~~~
$ ssh-add -l
256 71:fd:ba:ef:aa:94:27:14:05:d8:b6:db:28:e4:65:c2 /home/jdoe/.ssh/id_ed25519 (ED25519)
2048 2b:c8:ae:c0:d3:25:93:83:d4:41:4d:21:1e:80:2f:f4 rsa w/o comment (RSA)
~~~

À noter que l'on peut forcer un agent SSH à oublier les clés SSH à l'aide d'une des deux commandes suivantes :

~~~
$ ssh-add -D
All identities removed.

$ keychain --clear
 * ssh-agent: All identities removed.
 * gpg-agent: All identities removed.
~~~

On peut aussi verrouiller temporairement son agent SSH via :

~~~
$ ssh-add -x
Enter lock password:
Again:
Agent locked.

$ ssh-add -l
The agent has no identities.

$ ssh-add -X
Enter lock password:
Agent unlocked.
~~~

### Ouvrir un tunnel, en passant par un bastion

Voici un exemple pour exposer localement un service VNC sur le port 5901 qui est accessible uniquement localement sur le port 5906 d'un serveur VNC, qui lui même n'est accessible que par un bastion :

~~~
ssh -J bastion.example.com -L 5906:127.0.0.1:5901 vnc-server.example.com
~~~

### Comment protéger un serveur SSH des attaques ?

Voici plusieurs méthodes pour protéger son serveur SSH (qui peuvent se cumuler)

- ne pas ouvrir son port SSH à l'extérieur à l'exception de certaines adresses IP
- modifier le port d'écoute de son serveur SSH pour diminuer un peu les attaques automatiques (`Port 2200` dans *sshd_config*)
- utiliser du Port Knocking pour camoufler son port SSH
- ne pas autoriser les connexions SSH avec un mot de passe (`PasswordAuthentication no` dans *sshd_config*)
- configurer [Fail2Ban](HowtoFail2Ban) pour bannir les adresses IP qui se trompent de mot de passe

### Que ce passe t'il quand sshd_config contient à la fois AllowUsers et AllowGroups ?

C'est authorisé par sshd donc `sshd -t` ne sortira pas d'erreur ! Au niveau de la connexion, la page man de sshd_config(5) dit:

> The allow/deny directives are processed in the following order: DenyUsers, AllowUsers, DenyGroups, and finally AllowGroups.

Cela signifie en réalité que lors d'une tentative de connexion SSH, la logique suivante est suivi:

> Dans le cas où l'une de ces options n'est pas défini, on saute la ligne correspondante.

- si l'utilisateur tentant de ce connecté **est listé** dans `DenyUsers` alors il ne peut pas se connecter, sinon continuer,
- si l'utilisateur tentant de ce connecté **n'est pas listé** dans `AllowUsers` alors il ne peut pas se connecter, sinon continuer,
- si l'utilisateur **appartient à un groupe listé** dans `DenyGroups` alors il ne peut pas se connecter, sinon continuer,
- si l'utilisateur **n'appartient pas à un groupe listé** dans `AllowGroups` alors il ne peut pas se connecter, sinon continuer,
- l'utilisateur peut se connecté.

Donc pour résumé : Si `AllowUsers` et `AllowGroups` sont définis dans sshd_config alors il faut que l'utilisateur soit **à la fois** dans `AllowUsers` **et** `AllowGroups` pour pouvoir se connecter par SSH.


### SSH refuse d'ouvrir une session, ou nombre maximum de sessions SSH atteint

Côté client SSH, on peut rencontrer les erreurs suivantes :

~~~
Remote command execution failed: mux_client_request_session: session request failed: Session open refused by peer
~~~

Côté serveur, dans `/var/log/auth.log` :

~~~
sshd[14063]: error: no more sessions
~~~

Dans ce cas :

1. Augmenter la valeur de `MaxSessions` dans `/etc/ssh/sshd_config` (par défaut à 10).
2. Redémarrer le service `ssh` (faire un restart, pas un reload).
3. Vérifier que le service tourne bien.
4. S'il y a des sessions SSH persistantes (par exemple dans le cas d'un monitoring Nagios/Icinga), les tuer.

