sshproxy-lab/
├── docker-compose.yaml [CRÉÉ]
├── keys/
│ ├── lab_rsa [CRÉÉ] Clé privée Windows
│ ├── lab_rsa.pub [CRÉÉ] Clé publique Windows
│ ├── gateway_rsa [CRÉÉ] Clé privée Gateway
│ └── gateway_rsa.pub [CRÉÉ] Clé publique Gateway
├── gateway/
│ ├── Dockerfile [CRÉÉ] Build multi-stage sshproxy
│ ├── sshd_config [CRÉÉ] Config SSH daemon + ForceCommand
│ ├── sshproxy.yaml [CRÉÉ] Config sshproxy v2.1.0
│ └── sshproxy-wrapper.sh [CRÉÉ] Wrapper shell pour proxy
└── dest/
├── Dockerfile [CRÉÉ] Build destination simple
└── sshd_config [CRÉÉ] Config SSH normal
Documentation:
├── DOCUMENTATION_COMPLETE.md [GÉNÉRÉ] Explication détaillée (17KB)
├── QUICK_REFERENCE.md [GÉNÉRÉ] Architecture visuelle + checklist
├── ELI5_EXPLICATION.md [GÉNÉRÉ] Explication simplifié
├── RESOLUTION_RAPPORT.md [GÉNÉRÉ] Résolution du bug exit 255
└── INDEX_FICHIERS.md [CE FICHIER]
docker-compose.yaml ← Point de départRôle: Orchestrer 3 conteneurs Docker en réseau privé
Contenu:
gateway: Gateway sshproxy (port 2222)dest1: Destination 1 (172.30.0.11)dest2: Destination 2 (172.30.0.12)172.30.0.0/24Pourquoi c'est important:
Modifié: Jamais (c'est le fichier principal)
gateway/Dockerfile ← 2e fichier critiqueRôle: Builder l'image du proxy
Étapes (multi-stage):
Stage builder (golang:1.24-bookworm)
Stage final (debian:bookworm-slim)
testuserPourquoi c'est important:
Clés à retenir:
# 3 lignes critiques:
COPY keys/gateway_rsa /etc/sshproxy/gateway_rsa
RUN chown testuser:testuser /etc/sshproxy/gateway_rsa ← Clé!
COPY gateway/sshproxy-wrapper.sh /usr/sbin/sshproxy-wrapper
gateway/sshd_config ← 3e fichier critiqueRôle: Configuration du daemon SSH côté gateway
Parametres clés:
ForceCommand /usr/sbin/sshproxy-wrapper
↑↑↑ CRUCIAL! C'est la ligne qui rend tout transparent ↑↑↑
PasswordAuthentication no # Clé uniquement
PubkeyAuthentication yes # Accepte clés publiques
AuthorizedKeysFile .ssh/authorized_keys
PermitRootLogin no # Pas de root
AllowTcpForwarding no # Pas de -L/-R
X11Forwarding no # Pas de graphique
Différence vs dest:
ForceCommand → intercepteForceCommand → SSH normalgateway/sshproxy.yaml ← 4e fichier critiqueRôle: Configuration du proxy (destinations, stratégie, commandes SSH)
Sections:
log: "/tmp/sshproxy-{user}.log" # Fichier log par utilisateur
log_level: "debug" # Verbosité
ssh: # Commande SSH pour rebond
exe: "/usr/bin/ssh"
args:
- "-v" # Verbose
- "-tt" ← CRUCIAL! # Force PTY (pour shell interactif)
- "-i" "/etc/sshproxy/gateway_rsa" # Clé privée
- "-o" "StrictHostKeyChecking=no" # Accepte nouvelles clés
- "-o" "UserKnownHostsFile=/dev/null" # Pas de known_hosts
etcd: # Clustering (vide = mode stateless)
endpoints: []
mandatory: false
dest: # Destinations à proxifier
- "172.30.0.11:22" # dest1
- "172.30.0.12:22" # dest2
route_select: "random" # Sélection aléatoire
mode: "balanced" # Mode équilibré
Le -tt c'est quoi?
-t = alloue un pseudo-terminal (shell interactif possible)
-tt = force allocation même si no TTY en input
Sans ça: commandes OK mais shell freeze
gateway/sshproxy-wrapper.sh ← Wrapper simpleRôle: Détecte si c'est shell interactif ou commande, exécute sshproxy
Contenu:
#!/bin/bash
if [ -z "$SSH_ORIGINAL_COMMAND" ]; then
# Shell interactif (pas de commande)
exec /usr/sbin/sshproxy
else
# Commande fournie
exec /usr/sbin/sshproxy
fi
Observations:
dest/Dockerfile ← Build simpleRôle: Image pour dest1 et dest2
Contenu:
FROM debian:bookworm-slim # Même base que gateway
RUN apt-get install openssh-server # Juste sshd
# Crée testuser
# Copie gateway_rsa.pub dans authorized_keys
# Copie dest/sshd_config
Différence vs gateway/Dockerfile:
dest/sshd_config ← Configuration destinationRôle: SSH normal (pas d'interception)
Différence clé:
Gateway: ForceCommand /usr/sbin/sshproxy-wrapper (intercepte)
Dest: (pas de ForceCommand) (SSH normal)
keys/lab_rsa & keys/lab_rsa.pubRôle: Client Windows → Gateway
Lab_rsa (privée):
Windows garde dans C:\Users\user\.ssh\lab_rsa
Utilisée pour: ssh -i lab_rsa -p 2222 localhost
lab_rsa.pub (publique):
Copié dans gateway:/home/testuser/.ssh/authorized_keys
Signature: autorise ce client
Génération:
ssh-keygen -t ed25519 -f keys/lab_rsa -N ""
keys/gateway_rsa & keys/gateway_rsa.pubRôle: Gateway → Destinations
gateway_rsa (privée):
Compilée DANS l'image gateway
Utilisée par sshproxy pour rebond: ssh -i /etc/sshproxy/gateway_rsa testuser@dest
gateway_rsa.pub (publique):
Copié dans dest1/dest2:/home/testuser/.ssh/authorized_keys
Signature: autorise la gateway
Génération:
ssh-keygen -t ed25519 -f keys/gateway_rsa -N ""
1. Client Windows
Lit: keys/lab_rsa (privée)
2. Docker compose lance gateway
Lit: gateway/Dockerfile
Compile: sshproxy (depuis sources GitHub)
Copie: keys/gateway_rsa dans /etc/sshproxy
Copie: keys/lab_rsa.pub dans authorized_keys
Copie: gateway/sshd_config
Copie: gateway/sshproxy.yaml
Copie: gateway/sshproxy-wrapper.sh
Lance: /usr/sbin/sshd -D
3. Docker compose lance dest1/dest2
Lit: dest/Dockerfile
Copie: keys/gateway_rsa.pub dans authorized_keys
Copie: dest/sshd_config
Lance: /usr/sbin/sshd -D
4. Client se connecte
ssh -i keys/lab_rsa -p 2222 localhost
↓
Gateway sshd lit authorized_keys
Retrouve lab_rsa.pub
Lance ForceCommand: /usr/sbin/sshproxy-wrapper
↓
Wrapper lance /usr/sbin/sshproxy
↓
sshproxy lit gateway/sshproxy.yaml
Choisit dest1 ou dest2 au hasard
Exécute rebond SSH avec keys/gateway_rsa
↓
Destination sshd lit authorized_keys
Retrouve gateway_rsa.pub
Exécute commande
↓
Résultat retourné au client
| Fichier | Responsabilité | Critique? |
|---|---|---|
| docker-compose.yaml | Orchestration 3 conteneurs | ⭐⭐⭐ |
| gateway/Dockerfile | Build + permissions | ⭐⭐⭐ |
| gateway/sshd_config | ForceCommand interception | ⭐⭐⭐ |
| gateway/sshproxy.yaml | -tt + destinations | ⭐⭐⭐ |
| gateway/sshproxy-wrapper.sh | Lance sshproxy | ⭐⭐ |
| dest/Dockerfile | Build destination | ⭐⭐ |
| dest/sshd_config | SSH normal | ⭐⭐ |
| keys/lab_rsa | Auth client→gateway | ⭐⭐⭐ |
| keys/gateway_rsa | Auth gateway→dest | ⭐⭐⭐ |
☐ Créer docker-compose.yaml (3 services + réseau)
☐ Créer gateway/Dockerfile (build + config)
☐ Créer gateway/sshd_config (ForceCommand crucial!)
☐ Créer gateway/sshproxy.yaml (-tt crucial!)
☐ Créer gateway/sshproxy-wrapper.sh
☐ Créer dest/Dockerfile (simple)
☐ Créer dest/sshd_config (SSH normal)
☐ Générer keys/lab_rsa + lab_rsa.pub
☐ Générer keys/gateway_rsa + gateway_rsa.pub
☐ docker compose up -d
☐ ssh -p 2222 -i keys/lab_rsa testuser@localhost 'hostname'
☐ Voir dest1 ou dest2? ✓ Succès!