« Une DMZ est sûre dès que le serveur web est sur un autre sous-réseau. »
La séparation d’adresses ne suffit pas. Une DMZ n’a de valeur que si les flux sont explicitement bornés, les accès inutiles sont refusés, le service est observable et restaurable, et les preuves montrent que l’exposition publique n’ouvre pas le réseau interne.
01Ce TP assemble l’existant au lieu de le réécrire
Tu dois déjà savoir résoudre un nom, observer HTTP/TLS, filtrer avec un pare-feu stateful, publier un service et diagnostiquer de bout en bout. Réutilise notamment :
reseaux/resoudre-noms-dns
reseaux/observer-http-https-tls
reseaux/diagnostiquer-service-bout-en-bout
reseaux/filtrer-flux-inter-vlan-nftables
reseaux/comprendre-nat-publication-services
reseaux/superviser-symptomes-alerter
reseaux/sauvegarder-documenter-exploitation
hardening/etablir-etat-initial-surfaces-exposition
hardening/reduire-services-ports-logiciels-inutiles
hardening/organiser-patching-changement-validation-rollback
hardening/durcir-chaine-sauvegarde-prouver-restauration
bts-sisr/construire-dossier-preuves
bts-sisr/conduire-diagnostic-remediation
Ici, le nouveau geste est l’orchestration : service Linux + DMZ + reverse proxy + TLS + filtrage + restauration + durcissement + panne contrôlée.
02Besoin de SORIA Distribution
Un portail de démonstration doit être accessible depuis une zone simulant Internet, sans rendre le LAN interne joignable.
Architecture de laboratoire :
CLIENT-EXT
|
| DNS + HTTPS 443
v
[ PARE-FEU / ROUTEUR ]
|
+------ DMZ 10.50.70.0/24 -------------------------+
| |
| SRV-PROXY01 SRV-WEB01 |
| 10.50.70.10 10.50.70.20 |
| Nginx : 80/443 ----------> Apache : 8080 |
| |
+---------------------------------------------------+
|
+------ LAN-ADMIN 10.50.10.0/24 --------------------+
ADMIN01
Les adresses sont des exemples pédagogiques. Adapte-les au plan validé de ton laboratoire.
Nom du service :
portal.dmz.soria.test
03Commence par la matrice de flux
Ne crée aucune règle avant d’avoir écrit ce qui doit fonctionner et ce qui doit échouer.
| Source | Destination | Service | Décision | Justification |
|---|---|---|---|---|
| CLIENT-EXT | SRV-PROXY01 | TCP 443 | AUTORISER | service publié |
| CLIENT-EXT | SRV-PROXY01 | TCP 80 | optionnel | redirection HTTP vers HTTPS |
| SRV-PROXY01 | SRV-WEB01 | TCP 8080 | AUTORISER | reverse proxy vers Apache |
| ADMIN01 | SRV-PROXY01 / SRV-WEB01 | SSH 22 | AUTORISER | administration depuis LAN-ADMIN seulement |
| CLIENT-EXT | SRV-WEB01 | TCP 8080 | REFUSER | backend non exposé directement |
| CLIENT-EXT | LAN-ADMIN | tout | REFUSER | isolation du SI interne |
| DMZ | LAN-ADMIN | tout sauf besoin documenté | REFUSER | limitation des mouvements latéraux |
La règle fondamentale est simple : l’exposition nécessaire est une exception, pas une politique générale.
Conserve une copie de cette matrice dans ton dossier de preuves.
04Établis l’état initial des deux serveurs
Sur SRV-PROXY01 et SRV-WEB01 :
hostnamectl
ip -br address
ip route
ss -lntup
systemctl --failed
sudo journalctl -p warning -b --no-pager | tail -n 30
Sur le pare-feu, exporte ou capture aussi :
interfaces / zones
routes utiles
règles actuellement actives
politique par défaut
Cette photographie est la preuve avant. Elle permet aussi de savoir ce qu’il faudra restaurer si le changement échoue.
05Installe Apache sur le backend
Sur SRV-WEB01 Debian/Ubuntu :
sudo apt update
sudo apt install -y apache2
sudo systemctl enable --now apache2
sudo systemctl status apache2 --no-pager
Crée un contenu borné :
sudo install -d -o root -g root -m 0755 /var/www/soria-portal
cat <<'EOF' | sudo tee /var/www/soria-portal/index.html >/dev/null
<!doctype html>
<html lang="fr">
<head><meta charset="utf-8"><title>SORIA Distribution</title></head>
<body><h1>Portail DMZ SORIA Distribution</h1><p>Backend Apache opérationnel.</p></body>
</html>
EOF
Crée un VirtualHost qui n’écoute que sur le port backend 8080 :
cat <<'EOF' | sudo tee /etc/apache2/sites-available/soria-portal.conf >/dev/null
Listen 8080
<VirtualHost *:8080>
ServerName portal.dmz.soria.test
DocumentRoot /var/www/soria-portal
<Directory /var/www/soria-portal>
Options -Indexes
AllowOverride None
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/soria-portal-error.log
CustomLog ${APACHE_LOG_DIR}/soria-portal-access.log combined
</VirtualHost>
EOF
sudo a2dissite 000-default.conf
sudo a2ensite soria-portal.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
ss -lntp | grep ':8080'
Vérifie depuis SRV-PROXY01 :
curl -i http://10.50.70.20:8080/
Mais depuis CLIENT-EXT, l’accès direct au port 8080 devra échouer après application du filtrage.
06Installe Nginx comme reverse proxy
Sur SRV-PROXY01 :
sudo apt update
sudo apt install -y nginx openssl
sudo systemctl enable --now nginx
Avant TLS, prépare une configuration de proxy minimale :
cat <<'EOF' | sudo tee /etc/nginx/sites-available/soria-portal >/dev/null
server {
listen 80;
server_name portal.dmz.soria.test;
location / {
proxy_pass http://10.50.70.20:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
EOF
sudo ln -sfn /etc/nginx/sites-available/soria-portal /etc/nginx/sites-enabled/soria-portal
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
Test local :
curl -i -H 'Host: portal.dmz.soria.test' http://127.0.0.1/
Le code HTTP ne suffit pas : vérifie aussi les journaux Apache et Nginx pour établir la chaîne client → proxy → backend.
07Crée un certificat TLS de laboratoire vérifiable
Pour ce TP isolé, crée un certificat auto-signé avec SAN. Il sert à apprendre la chaîne TLS ; il ne représente pas une procédure de certificat public de production.
sudo install -d -m 0700 /etc/nginx/tls
sudo openssl req -x509 -newkey rsa:2048 -nodes -days 30 \
-keyout /etc/nginx/tls/portal.key \
-out /etc/nginx/tls/portal.crt \
-subj '/CN=portal.dmz.soria.test' \
-addext 'subjectAltName=DNS:portal.dmz.soria.test'
sudo chmod 0600 /etc/nginx/tls/portal.key
openssl x509 -in /etc/nginx/tls/portal.crt -noout -subject -issuer -dates -ext subjectAltName
Remplace la configuration Nginx par :
server {
listen 80;
server_name portal.dmz.soria.test;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name portal.dmz.soria.test;
ssl_certificate /etc/nginx/tls/portal.crt;
ssl_certificate_key /etc/nginx/tls/portal.key;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://10.50.70.20:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Puis :
sudo nginx -t
sudo systemctl reload nginx
08Relie DNS sans tricher avec le navigateur
Dans le DNS du laboratoire, crée l’enregistrement correspondant à la vue utilisée par CLIENT-EXT :
portal.dmz.soria.test -> adresse de publication du proxy
Si ton laboratoire simule l’extérieur derrière NAT, la cible DNS est l’adresse publiée du pare-feu. Si le client de test est directement routé vers la DMZ, elle peut être 10.50.70.10.
Depuis CLIENT-EXT :
getent hosts portal.dmz.soria.test
# ou : dig +short portal.dmz.soria.test
curl -vk https://portal.dmz.soria.test/
openssl s_client -connect portal.dmz.soria.test:443 \
-servername portal.dmz.soria.test </dev/null 2>/dev/null |
openssl x509 -noout -subject -issuer -dates -ext subjectAltName
-k accepte le certificat auto-signé uniquement pour le test de laboratoire. La preuve TLS sérieuse reste la lecture du certificat, de son SAN et de ses dates.
09Applique le filtrage et prouve aussi les refus
Transpose la matrice de flux avec le pare-feu du fil rouge. Réutilise la logique stateful de reseaux/filtrer-flux-inter-vlan-nftables ou les règles équivalentes sur OPNsense.
Politique attendue :
CLIENT-EXT -> PROXY:443 PASS
CLIENT-EXT -> PROXY:80 PASS si redirection retenue
PROXY -> WEB:8080 PASS
ADMIN -> PROXY/WEB:22 PASS depuis LAN-ADMIN seulement
CLIENT-EXT -> WEB:8080 BLOCK
CLIENT-EXT -> LAN-ADMIN:* BLOCK
DMZ -> LAN-ADMIN:* BLOCK sauf exception documentée
retours de connexions établies PASS selon le moteur stateful
Recette depuis plusieurs zones :
# depuis CLIENT-EXT
curl -vk https://portal.dmz.soria.test/
nc -vz 10.50.70.20 8080 # doit échouer
nc -vz 10.50.10.10 22 # doit échouer
# depuis ADMIN01
ssh <compte-lab>@10.50.70.10
ssh <compte-lab>@10.50.70.20
# depuis SRV-PROXY01
curl -f http://10.50.70.20:8080/
Une capture d’un accès autorisé ne prouve pas l’isolation. Il faut conserver au moins un test négatif attendu.
10Teste la restauration avant de durcir
Avant toute modification restrictive, sauvegarde la configuration et le contenu nécessaires au service :
# SRV-WEB01
sudo tar -czf /root/soria-web-before-hardening.tgz \
/etc/apache2/sites-available/soria-portal.conf \
/var/www/soria-portal
sudo sha256sum /root/soria-web-before-hardening.tgz
# SRV-PROXY01
sudo tar -czf /root/soria-proxy-before-hardening.tgz \
/etc/nginx/sites-available/soria-portal \
/etc/nginx/tls/portal.crt \
/etc/nginx/tls/portal.key
sudo sha256sum /root/soria-proxy-before-hardening.tgz
Le simple fait d’avoir une archive n’est pas une preuve de restauration. Sur un snapshot de laboratoire ou après copie des fichiers de test, effectue une restauration contrôlée, puis :
sudo apache2ctl configtest
sudo nginx -t
curl -f http://10.50.70.20:8080/
curl -fk https://portal.dmz.soria.test/
Note : snapshot et archive locale facilitent le TP, mais ne remplacent pas une stratégie de sauvegarde indépendante. Le but ici est de prouver le chemin de restauration avant de fermer les accès.
11Durcis sans casser le service pédagogique
Établis d’abord les différences observables :
ss -lntup
sudo apache2ctl -M
sudo nginx -T 2>/dev/null | grep -E 'server_tokens|ssl_protocols|listen|proxy_pass'
Puis applique seulement des changements justifiés :
Apache : désactiver l'indexation ; limiter les modules inutiles si le laboratoire permet de les identifier ; conserver le backend sur 8080.
Nginx : server_tokens off ; TLS 1.2/1.3 ; clé privée mode 0600 ; aucun site par défaut.
SSH : administration uniquement depuis LAN-ADMIN via le pare-feu ; ne pas couper l'accès de secours du laboratoire.
Système: paquets à jour selon la fenêtre de changement ; services inutiles arrêtés après identification.
Exemple Nginx dans le bloc http :
server_tokens off;
Après chaque changement :
sudo apache2ctl configtest
sudo nginx -t
systemctl --failed
ss -lntup
curl -fk https://portal.dmz.soria.test/
Ton dossier doit contenir une comparaison avant / après / effet / limite, pas une liste de recommandations copiées.
12Injecte trois pannes contrôlées
Panne A — règle HTTPS retirée
Désactive temporairement uniquement la règle autorisant CLIENT-EXT -> PROXY:443.
Attendu :
DNS reste résolu
Nginx reste actif
le port 443 devient inaccessible depuis CLIENT-EXT
Le diagnostic doit donc séparer service local et chemin réseau.
Panne B — certificat incohérent
Sur un snapshot, configure temporairement un certificat dont le SAN ne contient pas portal.dmz.soria.test, puis recharge Nginx si nginx -t l’autorise.
Attendu : connexion TCP possible mais identité TLS non conforme au nom demandé.
Restaure ensuite le certificat attendu.
Panne C — backend Apache arrêté
sudo systemctl stop apache2
Attendu : Nginx est joignable en 443 mais le proxy ne peut plus satisfaire la requête applicative. Observe le code retourné et le journal d’erreur Nginx, puis :
sudo systemctl start apache2
curl -fk https://portal.dmz.soria.test/
Ne cumule pas les trois pannes. Injecte, observe, diagnostique, corrige et vérifie une cause à la fois.
13Construis la preuve BTS
Pour chaque exigence, conserve une preuve synthétique selon :
EXIGENCE
-> CONTEXTE
-> ACTION
-> RÉSULTAT / VÉRIFICATION
-> LIMITE
Jeu minimal attendu :
1. schéma CLIENT-EXT / pare-feu / DMZ / LAN-ADMIN
2. matrice de flux validée
3. résolution DNS de portal.dmz.soria.test
4. certificat : subject + SAN + dates
5. requête HTTPS réussie via Nginx
6. accès direct CLIENT-EXT -> Apache:8080 refusé
7. accès CLIENT-EXT -> LAN-ADMIN refusé
8. preuve proxy -> backend
9. checksum + test de restauration avant hardening
10. état avant/après hardening
11. une panne contrôlée, son diagnostic, sa correction et la recette finale
12. limite explicitée : laboratoire / certificat auto-signé / adresses simulées
Aucun mot de passe, clé privée, jeton, cookie ou secret ne doit entrer dans la preuve.
14Recette finale
Le TP n’est terminé que si toutes les affirmations suivantes sont démontrées :
[ ] le nom DNS attendu se résout
[ ] CLIENT-EXT atteint le service en HTTPS
[ ] le certificat présenté contient le SAN attendu
[ ] le backend Apache n'est pas directement exposé au client externe
[ ] le LAN interne reste inaccessible depuis CLIENT-EXT
[ ] le proxy atteint Apache sur le seul flux nécessaire
[ ] l'administration vient de la zone prévue
[ ] la restauration a été testée avant le durcissement
[ ] le service fonctionne encore après durcissement
[ ] une panne contrôlée a été détectée, expliquée, corrigée et retestée
[ ] les journaux utiles permettent de relier l'incident au bon composant
[ ] aucune preuve ne contient de secret
Ce résultat est plus important qu’une configuration « impressionnante » : le service est publié, mais son exposition reste expliquée, bornée, testée et réversible.