|
@@ -0,0 +1,540 @@
|
|
|
|
|
+# Documentation complète : Debian vierge → SSH proxy transparent
|
|
|
|
|
+
|
|
|
|
|
+## Vue d'ensemble de l'architecture
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+[Windows Client]
|
|
|
|
|
+ ↓ (clé lab_rsa)
|
|
|
|
|
+[Gateway sshproxy] ← SSH sur port 2222
|
|
|
|
|
+ ↓ (clé gateway_rsa, transparent)
|
|
|
|
|
+[Destination 1 ou 2]
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## NIVEAU 1: Infrastructure Docker (docker-compose.yaml)
|
|
|
|
|
+
|
|
|
|
|
+### Rôle
|
|
|
|
|
+Définit 3 conteneurs Debian isolés dans un réseau privé avec IPs fixes.
|
|
|
|
|
+
|
|
|
|
|
+```yaml
|
|
|
|
|
+services:
|
|
|
|
|
+ gateway: # Conteneur gateway (le proxy)
|
|
|
|
|
+ build:
|
|
|
|
|
+ context: .
|
|
|
|
|
+ dockerfile: gateway/Dockerfile
|
|
|
|
|
+ container_name: sshproxy-gateway
|
|
|
|
|
+ hostname: gateway # Nom du conteneur
|
|
|
|
|
+ ports:
|
|
|
|
|
+ - "2222:22" # Expose SSH sur port 2222 de l'hôte
|
|
|
|
|
+ networks:
|
|
|
|
|
+ sshproxy_net:
|
|
|
|
|
+ ipv4_address: 172.30.0.10 # IP fixe interne au réseau Docker
|
|
|
|
|
+ restart: unless-stopped
|
|
|
|
|
+
|
|
|
|
|
+ dest1: # Conteneur destination 1
|
|
|
|
|
+ build:
|
|
|
|
|
+ context: .
|
|
|
|
|
+ dockerfile: dest/Dockerfile
|
|
|
|
|
+ container_name: sshproxy-dest1
|
|
|
|
|
+ hostname: dest1 # Nom du conteneur
|
|
|
|
|
+ networks:
|
|
|
|
|
+ sshproxy_net:
|
|
|
|
|
+ ipv4_address: 172.30.0.11 # IP fixe pour sshproxy
|
|
|
|
|
+ restart: unless-stopped
|
|
|
|
|
+
|
|
|
|
|
+ dest2: # Conteneur destination 2 (même config que dest1)
|
|
|
|
|
+ build:
|
|
|
|
|
+ context: .
|
|
|
|
|
+ dockerfile: dest/Dockerfile
|
|
|
|
|
+ container_name: sshproxy-dest2
|
|
|
|
|
+ hostname: dest2
|
|
|
|
|
+ networks:
|
|
|
|
|
+ sshproxy_net:
|
|
|
|
|
+ ipv4_address: 172.30.0.12
|
|
|
|
|
+ restart: unless-stopped
|
|
|
|
|
+
|
|
|
|
|
+networks:
|
|
|
|
|
+ sshproxy_net: # Réseau bridge isolé
|
|
|
|
|
+ name: sshproxy_net
|
|
|
|
|
+ driver: bridge # Type de réseau Docker
|
|
|
|
|
+ ipam:
|
|
|
|
|
+ config:
|
|
|
|
|
+ - subnet: 172.30.0.0/24 # Plage IP privée
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**Clés concepts**:
|
|
|
|
|
+- **Port 2222**: Accès SSH depuis Windows via `ssh -p 2222 localhost`
|
|
|
|
|
+- **IPs statiques**: Permet à sshproxy de cibler dest1/dest2 de manière prévisible
|
|
|
|
|
+- **Réseau privé**: Conteneurs isolés, ne voient que les autres conteneurs du réseau
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## NIVEAU 2: Gateway — Dockerfile multi-stage
|
|
|
|
|
+
|
|
|
|
|
+Le Dockerfile gateway a **2 stages**:
|
|
|
|
|
+
|
|
|
|
|
+### Stage 1: Builder (compilation Go)
|
|
|
|
|
+
|
|
|
|
|
+```dockerfile
|
|
|
|
|
+FROM golang:1.24-bookworm AS builder # Image Go complète (compilateur + dépendances)
|
|
|
|
|
+ARG SSHPROXY_VERSION=2.1.0 # Version de sshproxy à compiler
|
|
|
|
|
+
|
|
|
|
|
+RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
|
|
|
+ git ca-certificates make && rm -rf /var/lib/apt/lists/*
|
|
|
|
|
+ # ↑ Dépendances minimales pour cloner + compiler Go
|
|
|
|
|
+
|
|
|
|
|
+WORKDIR /build # Répertoire de travail
|
|
|
|
|
+
|
|
|
|
|
+RUN git clone --depth 1 --branch v${SSHPROXY_VERSION} \
|
|
|
|
|
+ https://github.com/cea-hpc/sshproxy.git .
|
|
|
|
|
+ # ↑ Clone sshproxy depuis GitHub (version 2.1.0)
|
|
|
|
|
+ # --depth 1 = clone léger (historique court)
|
|
|
|
|
+
|
|
|
|
|
+RUN go build -mod=vendor -ldflags "-X main.SshproxyVersion=${SSHPROXY_VERSION}" \
|
|
|
|
|
+ -o bin/sshproxy github.com/cea-hpc/sshproxy/cmd/sshproxy && \
|
|
|
|
|
+ go build -mod=vendor -ldflags "-X main.SshproxyVersion=${SSHPROXY_VERSION}" \
|
|
|
|
|
+ -o bin/sshproxy-dumpd github.com/cea-hpc/sshproxy/cmd/sshproxy-dumpd && \
|
|
|
|
|
+ go build -mod=vendor -ldflags "-X main.SshproxyVersion=${SSHPROXY_VERSION}" \
|
|
|
|
|
+ -o bin/sshproxy-replay github.com/cea-hpc/sshproxy/cmd/sshproxy-replay && \
|
|
|
|
|
+ go build -mod=vendor -ldflags "-X main.SshproxyVersion=${SSHPROXY_VERSION}" \
|
|
|
|
|
+ -o bin/sshproxyctl github.com/cea-hpc/sshproxy/cmd/sshproxyctl
|
|
|
|
|
+ # ↑ Compile 4 binaires sshproxy dans ./bin/
|
|
|
|
|
+ # -mod=vendor = utilise les dépendances vendorisées (dans le repo)
|
|
|
|
|
+ # -ldflags "-X main.SshproxyVersion=..." = injecte la version dans le binaire
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**Pourquoi 2 stages?**
|
|
|
|
|
+- Stage 1 (builder): Contient Go compiler (1 GB+) — lourd
|
|
|
|
|
+- Stage 2 (final): Copie que les binaires compilés — léger
|
|
|
|
|
+
|
|
|
|
|
+### Stage 2: Image finale
|
|
|
|
|
+
|
|
|
|
|
+```dockerfile
|
|
|
|
|
+FROM debian:bookworm-slim # Image Debian minimale (~60 MB vs 1.2 GB golang)
|
|
|
|
|
+
|
|
|
|
|
+RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
|
|
|
+ openssh-server \ # Daemon SSH
|
|
|
|
|
+ ca-certificates && \ # Certificats SSL/TLS
|
|
|
|
|
+ rm -rf /var/lib/apt/lists/* # Nettoie cache apt
|
|
|
|
|
+
|
|
|
|
|
+# ──── BINAIRES SSHPROXY ────
|
|
|
|
|
+COPY --from=builder /build/bin/sshproxy /usr/sbin/sshproxy
|
|
|
|
|
+COPY --from=builder /build/bin/sshproxy-dumpd /usr/sbin/sshproxy-dumpd
|
|
|
|
|
+COPY --from=builder /build/bin/sshproxyctl /usr/bin/sshproxyctl
|
|
|
|
|
+COPY --from=builder /build/bin/sshproxy-replay /usr/bin/sshproxy-replay
|
|
|
|
|
+# ↑ Copie binaires compilés du stage builder vers l'image finale
|
|
|
|
|
+
|
|
|
|
|
+RUN chmod 755 /usr/sbin/sshproxy /usr/sbin/sshproxy-dumpd \
|
|
|
|
|
+ /usr/bin/sshproxyctl /usr/bin/sshproxy-replay
|
|
|
|
|
+# ↑ Rend les binaires exécutables
|
|
|
|
|
+
|
|
|
|
|
+# ──── COMPTE UTILISATEUR ────
|
|
|
|
|
+RUN useradd -m -s /bin/bash testuser && \
|
|
|
|
|
+ echo "testuser:testuser" | chpasswd && \
|
|
|
|
|
+ mkdir -p /home/testuser/.ssh && \
|
|
|
|
|
+ chmod 700 /home/testuser/.ssh
|
|
|
|
|
+# ↑ Crée compte testuser
|
|
|
|
|
+# -m = crée home directory
|
|
|
|
|
+# -s /bin/bash = shell par défaut
|
|
|
|
|
+# chmod 700 = seul testuser peut lister son .ssh
|
|
|
|
|
+
|
|
|
|
|
+# ──── AUTHENTIFICATION GATEWAY→DESTINATIONS ────
|
|
|
|
|
+# La clé gateway_rsa est utilisée par sshproxy pour se connecter à dest1/dest2
|
|
|
|
|
+RUN mkdir -p /etc/sshproxy && chmod 755 /etc/sshproxy
|
|
|
|
|
+# ↑ Crée répertoire pour config sshproxy
|
|
|
|
|
+# chmod 755 = rend traversable par testuser
|
|
|
|
|
+
|
|
|
|
|
+COPY keys/gateway_rsa /etc/sshproxy/gateway_rsa
|
|
|
|
|
+# ↑ Copie clé privée (générée avant le build)
|
|
|
|
|
+
|
|
|
|
|
+RUN chmod 600 /etc/sshproxy/gateway_rsa && chown testuser:testuser /etc/sshproxy/gateway_rsa
|
|
|
|
|
+# ↑ chmod 600 = seul le propriétaire peut lire
|
|
|
|
|
+# chown testuser = testuser est propriétaire (CRUCIAL!)
|
|
|
|
|
+# → sshproxy s'exécute en tant que testuser, donc elle peut lire la clé
|
|
|
|
|
+
|
|
|
|
|
+# ──── AUTHENTIFICATION CLIENTS→GATEWAY ────
|
|
|
|
|
+# Les clients (Windows) utilisent lab_rsa pour se connecter à la gateway
|
|
|
|
|
+COPY keys/lab_rsa.pub /home/testuser/.ssh/authorized_keys
|
|
|
|
|
+# ↑ Clé publique du client dans authorized_keys de la gateway
|
|
|
|
|
+
|
|
|
|
|
+RUN chmod 600 /home/testuser/.ssh/authorized_keys && \
|
|
|
|
|
+ chown -R testuser:testuser /home/testuser/.ssh
|
|
|
|
|
+# ↑ Permissions SSH standard: seul le propriétaire peut lire
|
|
|
|
|
+
|
|
|
|
|
+# ──── CONFIGURATION SSHD ────
|
|
|
|
|
+RUN mkdir -p /run/sshd
|
|
|
|
|
+# ↑ Répertoire nécessaire au daemon sshd
|
|
|
|
|
+
|
|
|
|
|
+COPY gateway/sshd_config /etc/ssh/sshd_config
|
|
|
|
|
+# ↑ Configuration personnalisée SSH daemon
|
|
|
|
|
+
|
|
|
|
|
+# ──── CONFIGURATION SSHPROXY ────
|
|
|
|
|
+COPY gateway/sshproxy.yaml /etc/sshproxy/sshproxy.yaml
|
|
|
|
|
+# ↑ Config du proxy (destinations, logique de routage, etc.)
|
|
|
|
|
+
|
|
|
|
|
+# ──── WRAPPER SSHPROXY ────
|
|
|
|
|
+COPY gateway/sshproxy-wrapper.sh /usr/sbin/sshproxy-wrapper
|
|
|
|
|
+RUN chmod 755 /usr/sbin/sshproxy-wrapper
|
|
|
|
|
+# ↑ Script shell qui détecte shell interactif vs commande
|
|
|
|
|
+
|
|
|
|
|
+EXPOSE 22
|
|
|
|
|
+# ↑ Déclare que le port 22 écoute (docker compose le remaponne sur 2222)
|
|
|
|
|
+
|
|
|
|
|
+CMD ["/usr/sbin/sshd", "-D", "-e"]
|
|
|
|
|
+# ↑ Lance sshd en foreground (-D) avec log stderr (-e)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## NIVEAU 3: Gateway — Configuration SSH (sshd_config)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+Port 22
|
|
|
|
|
+ListenAddress 0.0.0.0
|
|
|
|
|
+# ↑ Écoute SSH sur 0.0.0.0:22
|
|
|
|
|
+# (remappé sur 127.0.0.1:2222 par docker-compose)
|
|
|
|
|
+
|
|
|
|
|
+# ──── AUTHENTIFICATION ────
|
|
|
|
|
+PasswordAuthentication no
|
|
|
|
|
+# ↑ Désactive auth par mot de passe
|
|
|
|
|
+# Force utilisation des clés SSH uniquement
|
|
|
|
|
+
|
|
|
|
|
+PubkeyAuthentication yes
|
|
|
|
|
+# ↑ Active authentification par clé publique
|
|
|
|
|
+
|
|
|
|
|
+AuthorizedKeysFile .ssh/authorized_keys
|
|
|
|
|
+# ↑ Chemin des clés publiques acceptées (relatif au home de l'utilisateur)
|
|
|
|
|
+# Pour testuser: /home/testuser/.ssh/authorized_keys
|
|
|
|
|
+
|
|
|
|
|
+PermitRootLogin no
|
|
|
|
|
+# ↑ Interdit connexion SSH en tant que root (sécurité)
|
|
|
|
|
+
|
|
|
|
|
+# ──── FORCECOMMAND : LE CŒUR DE LA MAGIE ────
|
|
|
|
|
+ForceCommand /usr/sbin/sshproxy-wrapper
|
|
|
|
|
+# ↑ CRUCIAL: Toute connexion SSH exécute d'abord ce wrapper
|
|
|
|
|
+# Cela intercepte CHAQUE commande SSH et la passe à sshproxy
|
|
|
|
|
+# C'est ce qui rend le proxy transparent
|
|
|
|
|
+
|
|
|
|
|
+# ──── SÉCURITÉ RÉSEAU ────
|
|
|
|
|
+AllowTcpForwarding no
|
|
|
|
|
+# ↑ Désactive le tunneling SSH (ssh -L / ssh -R)
|
|
|
|
|
+# Force les utilisateurs à utiliser le proxy directement
|
|
|
|
|
+
|
|
|
|
|
+X11Forwarding no
|
|
|
|
|
+# ↑ Désactive X11 forwarding (affichage graphique sur SSH)
|
|
|
|
|
+
|
|
|
|
|
+# ──── KEEPALIVE ────
|
|
|
|
|
+ClientAliveInterval 30
|
|
|
|
|
+ClientAliveCountMax 3
|
|
|
|
|
+# ↑ Envoie un ping toutes les 30s après 3 sans réponse = déconnexion
|
|
|
|
|
+# Évite les connexions zombies
|
|
|
|
|
+
|
|
|
|
|
+LogLevel INFO
|
|
|
|
|
+# ↑ Niveau de log (DEBUG pour débugging, INFO en production)
|
|
|
|
|
+
|
|
|
|
|
+HostKey /etc/ssh/ssh_host_ed25519_key
|
|
|
|
|
+HostKey /etc/ssh/ssh_host_rsa_key
|
|
|
|
|
+# ↑ Clés d'identité du daemon SSH (générées auto au premier démarrage)
|
|
|
|
|
+# Permettent aux clients de vérifier qu'ils parlent au bon serveur
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## NIVEAU 4: Gateway — Wrapper sshproxy (sshproxy-wrapper.sh)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+#!/bin/bash
|
|
|
|
|
+# Ce script s'exécute TOUJOURS en premier pour chaque connexion SSH
|
|
|
|
|
+# (à cause de ForceCommand dans sshd_config)
|
|
|
|
|
+
|
|
|
|
|
+if [ -z "$SSH_ORIGINAL_COMMAND" ]; then
|
|
|
|
|
+ # Cas 1: Pas de commande fournie
|
|
|
|
|
+ # = Shell interactif (utilisateur tape ssh gateway sans commande)
|
|
|
|
|
+ exec /usr/sbin/sshproxy
|
|
|
|
|
+ # ↑ Exécute sshproxy en mode shell interactif
|
|
|
|
|
+ # sshproxy va ouvrir un shell sur la destination choisie
|
|
|
|
|
+ # L'utilisateur peut taper des commandes interactivement
|
|
|
|
|
+else
|
|
|
|
|
+ # Cas 2: Commande fournie
|
|
|
|
|
+ # = Exécution de commande (ssh gateway 'commande')
|
|
|
|
|
+ exec /usr/sbin/sshproxy
|
|
|
|
|
+ # ↑ Exécute sshproxy avec la commande
|
|
|
|
|
+ # sshproxy proxifie la commande vers la destination
|
|
|
|
|
+ # Retour du résultat à l'utilisateur
|
|
|
|
|
+fi
|
|
|
|
|
+
|
|
|
|
|
+# Note: Les deux cas font la même chose!
|
|
|
|
|
+# sshproxy détecte automatiquement si c'est interactif ou commande
|
|
|
|
|
+# Ce wrapper pourrait être simplifié en:
|
|
|
|
|
+# exec /usr/sbin/sshproxy
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**Pourquoi ce wrapper?**
|
|
|
|
|
+- Permet de faire du preprocessing avant sshproxy si nécessaire
|
|
|
|
|
+- Future évolution: ajouter de l'audit, des ACLs, etc.
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## NIVEAU 5: Gateway — Configuration sshproxy (sshproxy.yaml)
|
|
|
|
|
+
|
|
|
|
|
+```yaml
|
|
|
|
|
+---
|
|
|
|
|
+log: "/tmp/sshproxy-{user}.log"
|
|
|
|
|
+# ↑ Fichier de log
|
|
|
|
|
+# {user} = remplacé par le nom d'utilisateur (ex: /tmp/sshproxy-testuser.log)
|
|
|
|
|
+
|
|
|
|
|
+log_level: "debug"
|
|
|
|
|
+# ↑ Niveau de verbosité des logs (debug = très détaillé)
|
|
|
|
|
+
|
|
|
|
|
+# ──── COMMANDE SSH UTILISÉE POUR LE REBOND ────
|
|
|
|
|
+ssh:
|
|
|
|
|
+ exe: "/usr/bin/ssh"
|
|
|
|
|
+ # ↑ Chemin vers le binaire ssh à utiliser pour les rebonds
|
|
|
|
|
+
|
|
|
|
|
+ args:
|
|
|
|
|
+ - "-v"
|
|
|
|
|
+ # ↑ Verbose: affiche les logs SSH (aide au debugging)
|
|
|
|
|
+
|
|
|
|
|
+ - "-tt"
|
|
|
|
|
+ # ↑ CRUCIAL: Force PTY allocation sur TOUS les rebonds
|
|
|
|
|
+ # -t = demande allocation PTY (terminal pseudo)
|
|
|
|
|
+ # -tt = force même si pas de TTY en entrée
|
|
|
|
|
+ # Permet les shells interactifs sur la destination
|
|
|
|
|
+
|
|
|
|
|
+ - "-i"
|
|
|
|
|
+ # ↑ Spécifie clé privée...
|
|
|
|
|
+
|
|
|
|
|
+ - "/etc/sshproxy/gateway_rsa"
|
|
|
|
|
+ # ↑ ...qui est gateway_rsa
|
|
|
|
|
+ # Utilisée pour auth gateway→dest1/dest2
|
|
|
|
|
+
|
|
|
|
|
+ - "-o"
|
|
|
|
|
+ - "StrictHostKeyChecking=no"
|
|
|
|
|
+ # ↑ Désactive vérification de l'identité du serveur distant
|
|
|
|
|
+ # Évite les "ECDSA key fingerprint... Are you sure?" en non-interactif
|
|
|
|
|
+
|
|
|
|
|
+ - "-o"
|
|
|
|
|
+ - "UserKnownHostsFile=/dev/null"
|
|
|
|
|
+ # ↑ Désactive known_hosts
|
|
|
|
|
+ # Évite les "Warning: Permanently added..." lors du rebond
|
|
|
|
|
+
|
|
|
|
|
+# ──── CONFIGURATION ETCD (pour sessions persistantes) ────
|
|
|
|
|
+etcd:
|
|
|
|
|
+ endpoints: []
|
|
|
|
|
+ # ↑ Pas d'endpoints etcd = mode stateless
|
|
|
|
|
+ # Pas de persistance de session
|
|
|
|
|
+
|
|
|
|
|
+ mandatory: false
|
|
|
|
|
+ # ↑ etcd n'est pas obligatoire
|
|
|
|
|
+ # Si pas d'etcd, utiliser le mode stateless par défaut
|
|
|
|
|
+
|
|
|
|
|
+# ──── DESTINATIONS DU PROXY ────
|
|
|
|
|
+dest:
|
|
|
|
|
+ - "172.30.0.11:22" # dest1: IP fixe Docker + port SSH
|
|
|
|
|
+ - "172.30.0.12:22" # dest2: IP fixe Docker + port SSH
|
|
|
|
|
+
|
|
|
|
|
+# ──── STRATÉGIE DE SÉLECTION DES DESTINATIONS ────
|
|
|
|
|
+route_select: "random"
|
|
|
|
|
+# ↑ Chaque connexion choisit aléatoirement entre dest1/dest2
|
|
|
|
|
+# Alternative: "round_robin" = alternance stricte
|
|
|
|
|
+
|
|
|
|
|
+mode: "balanced"
|
|
|
|
|
+# ↑ Mode balanced = répartition équilibrée
|
|
|
|
|
+# Essaie de garder le nombre de sessions équilibré
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**Flux d'exécution sshproxy**:
|
|
|
|
|
+1. Client Windows: `ssh -p 2222 testuser@localhost 'hostname'`
|
|
|
|
|
+2. sshd gateway accepte la connexion (clé lab_rsa validée)
|
|
|
|
|
+3. ForceCommand lance sshproxy-wrapper
|
|
|
|
|
+4. Wrapper lance `/usr/sbin/sshproxy` avec la commande 'hostname'
|
|
|
|
|
+5. sshproxy lit sshproxy.yaml
|
|
|
|
|
+6. Choisit random: dest1 ou dest2
|
|
|
|
|
+7. Exécute: `ssh -tt -i /etc/sshproxy/gateway_rsa testuser@172.30.0.12 hostname`
|
|
|
|
|
+8. dest2 accepte (clé gateway_rsa.pub reconnue)
|
|
|
|
|
+9. Résultat 'dest2' retourné à Windows
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## NIVEAU 6: Destinations — Dockerfile
|
|
|
|
|
+
|
|
|
|
|
+```dockerfile
|
|
|
|
|
+FROM debian:bookworm-slim
|
|
|
|
|
+# ↑ Même image de base que la gateway (pour cohérence)
|
|
|
|
|
+
|
|
|
|
|
+RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
|
|
|
+ openssh-server && \
|
|
|
|
|
+ rm -rf /var/lib/apt/lists/*
|
|
|
|
|
+# ↑ Installe uniquement sshd
|
|
|
|
|
+# Pas besoin de sshproxy sur les destinations
|
|
|
|
|
+
|
|
|
|
|
+# ──── COMPTE UTILISATEUR ────
|
|
|
|
|
+RUN useradd -m -s /bin/bash testuser && \
|
|
|
|
|
+ echo "testuser:testuser" | chpasswd && \
|
|
|
|
|
+ mkdir -p /home/testuser/.ssh && \
|
|
|
|
|
+ chmod 700 /home/testuser/.ssh
|
|
|
|
|
+# ↑ Même compte que sur la gateway
|
|
|
|
|
+# Permet des connexions cohérentes
|
|
|
|
|
+
|
|
|
|
|
+# ──── AUTHENTIFICATION GATEWAY→DESTINATION ────
|
|
|
|
|
+COPY keys/gateway_rsa.pub /home/testuser/.ssh/authorized_keys
|
|
|
|
|
+# ↑ Accepte la clé publique de la gateway
|
|
|
|
|
+# C'est la clé privée que la gateway utilise pour se connecter
|
|
|
|
|
+
|
|
|
|
|
+RUN chmod 600 /home/testuser/.ssh/authorized_keys && \
|
|
|
|
|
+ chown -R testuser:testuser /home/testuser/.ssh
|
|
|
|
|
+# ↑ Permissions standard SSH
|
|
|
|
|
+
|
|
|
|
|
+# ──── CONFIGURATION SSHD ────
|
|
|
|
|
+RUN mkdir -p /run/sshd
|
|
|
|
|
+COPY dest/sshd_config /etc/ssh/sshd_config
|
|
|
|
|
+
|
|
|
|
|
+EXPOSE 22
|
|
|
|
|
+CMD ["/usr/sbin/sshd", "-D", "-e"]
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## NIVEAU 7: Destinations — Configuration SSH (dest/sshd_config)
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+Port 22
|
|
|
|
|
+ListenAddress 0.0.0.0
|
|
|
|
|
+# ↑ Écoute standard SSH
|
|
|
|
|
+
|
|
|
|
|
+# ──── AUTHENTIFICATION ────
|
|
|
|
|
+PasswordAuthentication no
|
|
|
|
|
+PubkeyAuthentication yes
|
|
|
|
|
+AuthorizedKeysFile .ssh/authorized_keys
|
|
|
|
|
+PermitRootLogin no
|
|
|
|
|
+# ↑ Mêmes règles que la gateway
|
|
|
|
|
+# Authentification par clé uniquement
|
|
|
|
|
+
|
|
|
|
|
+# ──── DIFFÉRENCE CLÉE ────
|
|
|
|
|
+# PAS DE ForceCommand ici!
|
|
|
|
|
+# Les destinations acceptent SSH normalement
|
|
|
|
|
+# (Pas de proxy intermédiaire)
|
|
|
|
|
+
|
|
|
|
|
+AllowTcpForwarding no
|
|
|
|
|
+X11Forwarding no
|
|
|
|
|
+ClientAliveInterval 30
|
|
|
|
|
+ClientAliveCountMax 3
|
|
|
|
|
+LogLevel INFO
|
|
|
|
|
+HostKey /etc/ssh/ssh_host_ed25519_key
|
|
|
|
|
+HostKey /etc/ssh/ssh_host_rsa_key
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**Différence gateway vs dest**:
|
|
|
|
|
+- **Gateway**: ForceCommand /usr/sbin/sshproxy-wrapper (intercepte tout)
|
|
|
|
|
+- **Destinations**: Aucun ForceCommand (SSH normal)
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## NIVEAU 8: Gestion des clés SSH
|
|
|
|
|
+
|
|
|
|
|
+Trois clés SSH en jeu:
|
|
|
|
|
+
|
|
|
|
|
+### 1. lab_rsa (Windows → Gateway)
|
|
|
|
|
+```
|
|
|
|
|
+Client Windows Gateway
|
|
|
|
|
+ [lab_rsa.pub] ←→ [authorized_keys]
|
|
|
|
|
+ clé privée clé publique
|
|
|
|
|
+
|
|
|
|
|
+ ssh -i lab_rsa testuser@gateway
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2. gateway_rsa (Gateway → Destinations)
|
|
|
|
|
+```
|
|
|
|
|
+ Gateway dest1/dest2
|
|
|
|
|
+ [gateway_rsa] ←→ [gateway_rsa.pub]
|
|
|
|
|
+ clé privée dans authorized_keys
|
|
|
|
|
+
|
|
|
|
|
+ sshproxy exécute:
|
|
|
|
|
+ ssh -i /etc/sshproxy/gateway_rsa testuser@dest1
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 3. Clés d'identité daemon SSH (host keys)
|
|
|
|
|
+```
|
|
|
|
|
+Chaque daemon SSH a sa propre paire de clés RSA/ED25519
|
|
|
|
|
+Permet aux clients de vérifier l'identité du serveur
|
|
|
|
|
+Auto-générées au premier démarrage
|
|
|
|
|
+Chemin: /etc/ssh/ssh_host_*
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## FLUX COMPLET D'UNE CONNEXION
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+1. Windows client lance:
|
|
|
|
|
+ ssh -p 2222 -i lab_rsa testuser@localhost 'hostname'
|
|
|
|
|
+
|
|
|
|
|
+2. Connexion établie à Gateway (172.30.0.10:22 via port 2222)
|
|
|
|
|
+
|
|
|
|
|
+3. Gateway sshd:
|
|
|
|
|
+ - Vérifie clé: lab_rsa.pub == /home/testuser/.ssh/authorized_keys ✓
|
|
|
|
|
+ - Valide utilisateur: testuser ✓
|
|
|
|
|
+
|
|
|
|
|
+4. sshd exécute ForceCommand:
|
|
|
|
|
+ - Lance: /usr/sbin/sshproxy-wrapper
|
|
|
|
|
+
|
|
|
|
|
+5. sshproxy-wrapper détecte:
|
|
|
|
|
+ - SSH_ORIGINAL_COMMAND = "hostname"
|
|
|
|
|
+ - Exécute: /usr/sbin/sshproxy
|
|
|
|
|
+
|
|
|
|
|
+6. sshproxy lit sshproxy.yaml:
|
|
|
|
|
+ - Destinations: ["172.30.0.11:22", "172.30.0.12:22"]
|
|
|
|
|
+ - Sélection: random
|
|
|
|
|
+ - Choisit: 172.30.0.12 (dest2)
|
|
|
|
|
+
|
|
|
|
|
+7. sshproxy exécute:
|
|
|
|
|
+ ssh -tt -i /etc/sshproxy/gateway_rsa testuser@172.30.0.12 'hostname'
|
|
|
|
|
+
|
|
|
|
|
+8. Connection Gateway→dest2 établie:
|
|
|
|
|
+ - Vérifie clé: gateway_rsa (privée de la gateway)
|
|
|
|
|
+ - Accepte via: gateway_rsa.pub (publique sur dest2)
|
|
|
|
|
+ - Valide utilisateur: testuser ✓
|
|
|
|
|
+
|
|
|
|
|
+9. dest2 sshd exécute:
|
|
|
|
|
+ /bin/bash -c 'hostname'
|
|
|
|
|
+
|
|
|
|
|
+10. Résultat:
|
|
|
|
|
+ dest2
|
|
|
|
|
+
|
|
|
|
|
+11. Retour à Windows via Gateway
|
|
|
|
|
+ Affiche: dest2
|
|
|
|
|
+ Exit status: 0
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## RÉSUMÉ: Points critiques pour la transparence
|
|
|
|
|
+
|
|
|
|
|
+| Point | Pourquoi |
|
|
|
|
|
+|-------|---------|
|
|
|
|
|
+| **ForceCommand sshproxy-wrapper** | Intercepte chaque SSH et la proxifie |
|
|
|
|
|
+| **chown testuser gateway_rsa** | sshproxy (testuser) peut lire la clé privée |
|
|
|
|
|
+| **-tt dans sshproxy.yaml** | Alloue PTY pour shells interactifs |
|
|
|
|
|
+| **IPs statiques (172.30.0.x)** | sshproxy doit cibler des IPs fixes/prévisibles |
|
|
|
|
|
+| **Pas de ForceCommand sur dest** | Les destinations acceptent SSH normal |
|
|
|
|
|
+| **route_select: random** | Répartition automatique des connexions |
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Commandes utiles
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# Test simple commande
|
|
|
|
|
+ssh -p 2222 testuser@localhost 'hostname'
|
|
|
|
|
+
|
|
|
|
|
+# Test shell interactif
|
|
|
|
|
+ssh -p 2222 testuser@localhost
|
|
|
|
|
+
|
|
|
|
|
+# Vérifier les logs sshproxy
|
|
|
|
|
+docker exec sshproxy-gateway cat /tmp/sshproxy-testuser.log
|
|
|
|
|
+
|
|
|
|
|
+# Tester round-robin (doit altern dest1/dest2)
|
|
|
|
|
+for i in {1..10}; do ssh -p 2222 testuser@localhost 'hostname'; sleep 0.5; done
|
|
|
|
|
+```
|
|
|
|
|
+
|