# SYNTHÈSE COMPLÈTE — De Debian vierge à proxy SSH transparent ## 🎯 Objectif final Transformer une Debian minimale en **proxy SSH transparent** qui: - Accepte vos connexions SSH depuis Windows - Les redirige automatiquement vers une machine de destination (dest1 ou dest2) - Vous fait atterrir dans un shell sur la destination - Tout cela sans que vous ne voyiez le passage par la gateway --- ## 📦 Ce que vous avez créé ### 3 conteneurs Docker 1. **Gateway** (172.30.0.10): Proxy SSH qui intercepte et redirige 2. **Dest1** (172.30.0.11): Machine de destination 1 3. **Dest2** (172.30.0.12): Machine de destination 2 ### 2 niveaux d'authentification 1. **Windows → Gateway**: Clé `lab_rsa` 2. **Gateway → Destinations**: Clé `gateway_rsa` ### 1 réseau privé - Réseau bridge Docker: `172.30.0.0/24` - Isolé de l'extérieur --- ## 🔧 Les 9 fichiers essentiels ### 1️⃣ `docker-compose.yaml` **C'est quoi**: Fichier d'orchestration Docker **Fait quoi**: ```yaml Crée 3 services: - gateway (Dockerfile: gateway/Dockerfile) - dest1 (Dockerfile: dest/Dockerfile) - dest2 (Dockerfile: dest/Dockerfile) Les relie par un réseau privé: 172.30.0.0/24 Expose port 2222 (gateway SSH) ``` **Pourquoi c'est important**: Sans ce fichier, les conteneurs ne peuvent pas communiquer --- ### 2️⃣ `gateway/Dockerfile` **C'est quoi**: Fichier de construction de l'image gateway **Fait quoi**: ```dockerfile Stage 1 (Builder): FROM golang:1.24 Clone sshproxy v2.1.0 depuis GitHub Compile les binaires sshproxy en Go Stage 2 (Final): FROM debian:bookworm-slim Copie binaires compilés Installe sshd Crée compte testuser Copie clé gateway_rsa CRUCIAL: chown testuser /etc/sshproxy/gateway_rsa ← Sinon: Permission denied! Copie authorized_keys (lab_rsa.pub) Copie sshd_config Copie sshproxy.yaml Copie sshproxy-wrapper.sh ``` **Pourquoi c'est important**: - Multi-stage = image finale petite (pas d'env Go) - Permissions testuser = évite "Permission denied" exit 255 - C'est l'image qui lance le proxy --- ### 3️⃣ `gateway/sshd_config` **C'est quoi**: Configuration du daemon SSH gateway **Fait quoi**: ``` PasswordAuthentication no ← Clé uniquement PubkeyAuthentication yes PermitRootLogin no ← Pas de root AllowTcpForwarding no ← Pas de tunneling X11Forwarding no ForceCommand /usr/sbin/sshproxy-wrapper ← ⭐⭐⭐ LIGNE MAGIQUE ⭐⭐⭐ Toute connexion SSH lancera d'abord: /usr/sbin/sshproxy-wrapper ``` **Pourquoi c'est important**: `ForceCommand` est ce qui rend le proxy TRANSPARENT Chaque SSH est interceptée et proxifiée --- ### 4️⃣ `gateway/sshproxy.yaml` **C'est quoi**: Configuration du proxy sshproxy **Fait quoi**: ```yaml Destinations: - 172.30.0.11:22 (dest1) - 172.30.0.12:22 (dest2) Sélection: random ← Chaque connexion choisit aléatoirement Commande SSH pour rebond: ssh -v -tt -i /etc/sshproxy/gateway_rsa \ -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null \ testuser@DESTINATION -tt ← ⭐⭐⭐ CRUCIAL POUR SHELL INTERACTIF ⭐⭐⭐ ``` **Pourquoi c'est important**: - Définit les destinations du proxy - `-tt` alloue un pseudo-terminal → shell interactif possible - Sans `-tt`: commandes OK, mais shell freeze --- ### 5️⃣ `gateway/sshproxy-wrapper.sh` **C'est quoi**: Script shell wrapper **Fait quoi**: ```bash if [ -z "$SSH_ORIGINAL_COMMAND" ]; then # Pas de commande (shell interactif) exec /usr/sbin/sshproxy else # Commande fournie exec /usr/sbin/sshproxy fi ``` **Pourquoi c'est important**: - Exécuté en premier par `ForceCommand` du sshd - Permet du preprocessing futur (audit, ACL, etc.) - Actuellement les 2 branches font pareil (sshproxy gère) --- ### 6️⃣ `dest/Dockerfile` **C'est quoi**: Fichier de construction des images dest1 et dest2 **Fait quoi**: ```dockerfile FROM debian:bookworm-slim RUN apt-get install openssh-server ← Juste sshd Crée testuser Copie gateway_rsa.pub dans authorized_keys Copie dest/sshd_config Lance sshd ``` **Pourquoi c'est important**: - Simple: just SSH normal - Accepte la clé gateway_rsa.pub - Pas besoin de sshproxy (pas de proxy sur destinations) --- ### 7️⃣ `dest/sshd_config` **C'est quoi**: Configuration SSH des destinations **Fait quoi**: ``` Même config que gateway SAUF: PAS DE ForceCommand ← Clé différence! SSH fonctionne normalement ``` **Pourquoi c'est important**: Les destinations sont des vraies machines SSH Pas d'interception (pas de proxy) --- ### 8️⃣ `keys/lab_rsa` + `keys/lab_rsa.pub` **C'est quoi**: Paire de clés SSH Windows → Gateway **Fait quoi**: ``` lab_rsa (privée): Fichier: C:\Users\user\.ssh\lab_rsa Usage: ssh -i lab_rsa -p 2222 localhost lab_rsa.pub (publique): Copié dans: gateway:/home/testuser/.ssh/authorized_keys Signature: c'est une connexion autorisée ``` **Génération**: ```bash ssh-keygen -t ed25519 -f keys/lab_rsa -N "" ``` **Pourquoi c'est important**: - Première couche d'authentification - Windows doit avoir la privée - Gateway doit avoir la publique --- ### 9️⃣ `keys/gateway_rsa` + `keys/gateway_rsa.pub` **C'est quoi**: Paire de clés SSH Gateway → Destinations **Fait quoi**: ``` gateway_rsa (privée): Compilée dans: /etc/sshproxy/gateway_rsa Usage: sshproxy l'utilise pour rebond auto gateway_rsa.pub (publique): Copié dans: dest1/dest2:/home/testuser/.ssh/authorized_keys Signature: c'est la gateway qui demande d'entrer ``` **Génération**: ```bash ssh-keygen -t ed25519 -f keys/gateway_rsa -N "" ``` **Pourquoi c'est important**: - Deuxième couche d'authentification - Gateway doit avoir la privée (compilée dans image) - Destinations doivent avoir la publique --- ## 🔄 Flux détaillé d'une connexion ``` Step 1: Vous lancez ssh -p 2222 -i keys/lab_rsa testuser@localhost Step 2: Docker reçoit sur port 2222 Remap vers 172.30.0.10:22 (gateway sshd) Step 3: Gateway sshd accepte Lit: /home/testuser/.ssh/authorized_keys Cherche: lab_rsa.pub ✓ Trouve et valide Step 4: sshd lance ForceCommand Exécute: /usr/sbin/sshproxy-wrapper Step 5: Wrapper détecte SSH_ORIGINAL_COMMAND = "hostname" (si vous aviez tapé) Lance: /usr/sbin/sshproxy Step 6: sshproxy lit config Lit: /etc/sshproxy/sshproxy.yaml Voit: destinations = [172.30.0.11, 172.30.0.12] Choisit: random → 172.30.0.12 (dest2) Step 7: sshproxy exécute rebond ssh -tt -i /etc/sshproxy/gateway_rsa testuser@172.30.0.12 Step 8: dest2 sshd accepte Lit: /home/testuser/.ssh/authorized_keys Cherche: gateway_rsa.pub ✓ Trouve et valide Step 9: dest2 exécute shell/commande Résultat retourné via gateway vers vous Step 10: Vous voyez testuser@dest2:~$ (ou résultat de la commande) ``` --- ## ✨ Les 3 "magies" clés ### Magie 1: ForceCommand ``` Fichier: gateway/sshd_config Ligne: ForceCommand /usr/sbin/sshproxy-wrapper Effet: TOUTE connexion SSH est interceptée et proxifiée ``` ### Magie 2: -tt flag ``` Fichier: gateway/sshproxy.yaml Args: "-tt" Effet: Alloue PTY sur destination → shell interactif possible Sans ça: exit 255 ou freeze ``` ### Magie 3: 2 couches de clés ``` Layer 1: lab_rsa (client→gateway) Layer 2: gateway_rsa (gateway→dest) Effet: Authentification multi-niveaux ``` --- ## 🚀 Comment lancer ```bash # 1. Générer clés (si pas fait) ssh-keygen -t ed25519 -f keys/lab_rsa -N "" ssh-keygen -t ed25519 -f keys/gateway_rsa -N "" # 2. Lancer infra docker compose up -d # 3. Tester ssh -p 2222 -i keys/lab_rsa testuser@localhost 'hostname' # Devrait afficher: dest1 ou dest2 # 4. Tester shell interactif echo "hostname" | ssh -p 2222 -i keys/lab_rsa testuser@localhost # Devrait afficher: testuser@dest1:~$ hostname ↵ dest1 # 5. Vérifier round-robin for i in {1..5}; do \ ssh -p 2222 -i keys/lab_rsa testuser@localhost hostname; \ done # Mélange de dest1 et dest2 ``` --- ## 🎓 Points clés à retenir | Concept | Explication | |---------|------------| | **ForceCommand** | Intercepte chaque SSH sur la gateway | | **-tt flag** | Permet l'interactivité sur destination | | **2 clés SSH** | 2 authentifications (client→gateway, gateway→dest) | | **IPs statiques** | sshproxy doit savoir où proxifier | | **Random route_select** | Répartition charge automatique | | **Wrapper.sh** | Future extensibilité (audit, ACL) | | **Multi-stage Docker** | Image finale petite et efficace | --- ## ❌ Pièges évités | Piège | Cause | Solution | |-------|-------|----------| | Permission denied | gateway_rsa propriété root | `chown testuser /etc/sshproxy/gateway_rsa` | | Exit status 255 | PTY non alloué | `-tt` dans sshproxy.yaml | | Shell freeze | Pas de wrapper | sshproxy-wrapper.sh | | IPs qui changent | Network recréé | Subnet fixe + ipv4_address | --- ## 📚 Documentation disponible 1. **DOCUMENTATION_COMPLETE.md** (17 KB) - Explication ligne par ligne de chaque fichier 2. **QUICK_REFERENCE.md** (10 KB) - Diagrammes visuels + checklist 3. **ELI5_EXPLICATION.md** (6 KB) - Version ultra-simplifiée 4. **RESOLUTION_RAPPORT.md** (4 KB) - Comment on a résolu le bug exit 255 5. **INDEX_FICHIERS.md** (9 KB) - Index complet avec responsabilités --- ## 🎯 Résultat final ✅ Vous pouvez faire: ```bash ssh -p 2222 testuser@localhost # Shell interactif ssh -p 2222 testuser@localhost 'hostname' # Commandes ssh -p 2222 testuser@localhost 'ls -la' # Tout ce que SSH permet ``` ✅ Transparence: ``` Vous atterrissez directement sur dest1 ou dest2 Sans voir le saut par la gateway Authentification multi-niveaux cachée ``` ✅ Round-robin: ``` Chaque connexion choisit aléatoirement dest1 ou dest2 Répartition charge automatique ``` --- ## 🚪 Prochaines étapes (optionnel) - **etcd**: Ajouter persistence de session - **OpenLDAP**: Remplacer comptes locaux - **Audit logging**: Enregistrer chaque commande - **ACL**: Contrôler accès par utilisateur/destination - **Health checks**: Tester disponibilité destinations