02_ARCHITECTURE_VUE_ENSEMBLE.md 9.9 KB

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:

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:

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:

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:

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:

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:

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:

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

# 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:

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