LNX Outil · Linux

OpenSSH

Clés, config et tunnels SSH : local, distant, dynamique, ProxyJump et persistance.

Intermédiaire / 2 min de lecture / maj 11 nov 2026 / 5 tags
raw domaine signaler
Index des sheets

#Connexion et clés

bash
ssh user@10.10.10.10
ssh -p 2222 user@host
ssh -i ~/.ssh/id_ed25519 user@host
ssh -J jump user@internal

# Clé ed25519 avec passphrase
ssh-keygen -t ed25519 -a 100 -C "operator@laptop"

# Déployer la clé publique
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host
ssh-add -t 8h ~/.ssh/id_ed25519
ssh-add -l
bash
# Permissions attendues
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519 ~/.ssh/config
chmod 644 ~/.ssh/id_ed25519.pub ~/.ssh/authorized_keys
ini
# ~/.ssh/config
Host jump
  HostName 10.10.10.10
  User operator
  Port 2222
  IdentityFile ~/.ssh/id_ed25519
  ServerAliveInterval 30
  ServerAliveCountMax 3
  ExitOnForwardFailure yes
  ControlMaster auto
  ControlPath ~/.ssh/cm-%r@%h:%p
  ControlPersist 10m

Host internal
  HostName 10.10.20.10
  User operator
  ProxyJump jump
bash
ssh -G jump | grep -iE "hostname|user|port|forward|proxy"
ssh-keyscan -H 10.10.10.10 >> ~/.ssh/known_hosts
ssh-keygen -R 10.10.10.10

#Comprendre les tunnels

Option Sens Bind sur
-L Local → distant Machine cliente (toi)
-R Distant → local Serveur SSH (bastion)
-D Proxy SOCKS dynamique Machine cliente
-J Rebond SSH Chaîne de bastions
-W Forward stdio Utilisé avec ProxyCommand
text
# -L : le service distant devient accessible localement
[toi:8080] ──SSH──▶ [jump] ──TCP──▶ internal.corp:80
ssh -N -L 8080:internal.corp:80 user@jump

#Tunnels locaux -L

bash
# Accéder à un service interne via un bastion
ssh -N -L 8080:internal.corp:80 user@jump

# Plusieurs tunnels dans la même session
ssh -N -L 8080:internal.corp:80 -L 5432:db.internal:5432 user@jump

# Arrière-plan, sans shell, échec si le port local est occupé
ssh -fNT -o ExitOnForwardFailure=yes -L 8080:internal:80 user@jump

# Rendre le port accessible aux autres machines de ton réseau
ssh -g -N -L 8080:internal:80 user@jump

# Forward d'un socket Unix (Docker, par exemple)
ssh -N -L /tmp/docker.sock:/var/run/docker.sock user@jump
bash
# Vérifier que le port écoute
ss -tlnp | grep 8080
curl -s http://127.0.0.1:8080/

#Tunnels distants -R

bash
# Exposer un service local sur le loopback du bastion
ssh -N -R 9001:127.0.0.1:9001 user@jump

# Exposer sur toutes les interfaces du bastion (GatewayPorts requis)
ssh -N -R 0.0.0.0:9001:127.0.0.1:9001 user@jump

# Laisser le serveur choisir le port (affiché en verbose)
ssh -v -N -R 0:127.0.0.1:9001 user@jump

# Callback pour un reverse shell (voir aussi /sheets/reverse-shells/)
ssh -N -R 4444:127.0.0.1:4444 user@jump
bash
# Sur le serveur SSH, pour autoriser un bind non-loopback
# /etc/ssh/sshd_config.d/forwarding.conf
GatewayPorts clientspecified

#Proxy SOCKS -D

bash
# SOCKS5 local sur 127.0.0.1:1080
ssh -N -D 1080 user@jump

# Exposer le SOCKS aux autres interfaces
ssh -N -D 0.0.0.0:1080 user@jump

# Tester avec curl (DNS résolu côté proxy)
curl --socks5-hostname 127.0.0.1:1080 http://internal.corp/

# Scanner le réseau interne via proxychains
proxychains4 nmap -sT -Pn -p 22,80,443,445 10.10.20.0/24
ini
# /etc/proxychains4.conf
[ProxyList]
socks5 127.0.0.1 1080

#Rebonds et ProxyJump

bash
# Un ou plusieurs bastions
ssh -J user@jump user@10.10.20.10
ssh -J user@jump1,user@jump2 user@target

# Équivalent explicite
ssh -o ProxyJump=user@jump user@target

# ProxyCommand : SSH dans SSH
ssh -o ProxyCommand='ssh -W %h:%p user@jump' user@target

# Passer par un proxy HTTP CONNECT
ssh -o ProxyCommand='ncat --proxy proxy.corp:3128 --proxy-type http %h %p' user@target
ssh -o ProxyCommand='socat - PROXY:proxy.corp:%h:%p,proxyport=3128' user@target
bash
# Tunnel à travers la cible finale
# Ici, c'est la cible qui doit joindre internal:80
ssh -J jump -L 8080:internal:80 user@target

#Transferts de fichiers

bash
# scp / sftp (port en majuscule)
scp -P 2222 fichier user@host:/tmp/
scp -r dossier user@host:/tmp/
sftp -P 2222 user@host

# rsync à travers SSH
rsync -avz -e 'ssh -p 2222' dossier/ user@host:/tmp/dossier/

# Sans scp : tar dans un pipe
tar czf - dossier | ssh user@host 'tar xzf - -C /tmp'

# Lire un fichier distant
ssh user@host 'cat /etc/passwd' > passwd.local

# Monter un répertoire distant
sshfs user@host:/remote /mnt/remote -o reconnect

#Multiplexage et persistance

bash
# Une seule connexion TCP réutilisée pour plusieurs sessions
ssh -M -S ~/.ssh/cm-jump -fN -L 8080:internal:80 user@jump

ssh -S ~/.ssh/cm-jump -O check user@jump
ssh -S ~/.ssh/cm-jump -O forward -L 9090:internal:90 user@jump
ssh -S ~/.ssh/cm-jump -O cancel -L 9090:internal:90 user@jump
ssh -S ~/.ssh/cm-jump -O exit user@jump
bash
# Reconnexion automatique d'un tunnel
autossh -M 0 -fNT \
  -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \
  -o ExitOnForwardFailure=yes \
  -L 8080:internal:80 user@jump
ini
# ~/.config/systemd/user/tunnel-8080.service
[Unit]
Description=SSH tunnel 8080 -> internal:80
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/bin/ssh -NT -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 -L 8080:internal:80 user@jump
Restart=always
RestartSec=5

[Install]
WantedBy=default.target
bash
systemctl --user daemon-reload
systemctl --user enable --now tunnel-8080.service
loginctl enable-linger "$USER"

#Agent et restrictions de clé

bash
eval "$(ssh-agent -s)"
ssh-add -t 8h ~/.ssh/id_ed25519
ssh-add -l

# Forward de l'agent : pratique, mais risqué sur un hôte non fiable
ssh -A user@jump
text
# ~/.ssh/authorized_keys
# Clé de backup : uniquement cette commande, depuis ce réseau
restrict,command="/usr/local/bin/backup",from="10.10.10.0/24" ssh-ed25519 AAAA...

# Clé de tunnel : pas de shell, uniquement le forwarding
restrict,pty,port-forwarding ssh-ed25519 AAAA...
Option sshd Effet
AllowTcpForwarding yes Autorise -L et -R
AllowTcpForwarding local Autorise seulement -L
AllowTcpForwarding remote Autorise seulement -R
PermitOpen host:port Restreint les destinations
PermitListen Restreint les ports d'écoute distants
GatewayPorts no -R limité au loopback
AllowAgentForwarding no Coupe -A
PermitTunnel no Coupe ssh -w (TUN/TAP)

#Durcissement serveur

bash
# /etc/ssh/sshd_config.d/hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding local
PermitOpen git.internal:22 db.internal:5432
ClientAliveInterval 60
ClientAliveCountMax 3
bash
sshd -t
systemctl reload ssh       # Debian / Ubuntu
systemctl reload sshd      # RHEL / Fedora
sshd -T | grep -iE "forward|gateway|permitopen"

#Dépannage

bash
ssh -vvv user@host
ssh -G host | grep -iE "forward|proxy|user|port"
ss -tlnp
ss -tnp
journalctl -u ssh -f        # ou -u sshd
Erreur Piste
Permission denied (publickey) Clé absente, permissions, ssh-add -l, SELinux (restorecon -R ~/.ssh)
Host key verification failed ssh-keygen -R host après vérification
channel open failed: administratively prohibited AllowTcpForwarding / PermitOpen côté serveur
remote port forwarding failed Port déjà pris sur le serveur, ou GatewayPorts
bind: Address already in use Port local déjà utilisé
Connexion qui tombe ServerAliveInterval, ClientAliveInterval, MTU/réseau
bash
# Scripts non interactifs
ssh -o BatchMode=yes -o ConnectTimeout=10 user@host 'uptime'

# Accepter une nouvelle clé d'hôte sans la vérifier (lab uniquement)
ssh -o StrictHostKeyChecking=accept-new user@host

# Vérifier les algorithmes négociés
ssh -Q cipher
ssh -Q kex
INDEX // 42 FICHES // 12 DOMAINES LOCAL SEARCH
↑↓ naviguer ↵ ouvrir esc fermer sheet.sec / find
Raccourcis clavier
Recherche globale /ou⌘K
Naviguer dans les résultats ↑↓
Ouvrir le résultat actif ↵
Fermer une fenêtre esc
Accueil gh
Tous les sheets gs
Fiche aléatoire gr
Cette fenêtre ?