Linux — utilisation avancée et administration · Étape 02

Déploie Apache dans une DMZ et publie-le en HTTPS

Publie un service Linux exposé sans ouvrir le SI : place Apache derrière Nginx dans une DMZ, borne les flux, configure DNS et TLS, prouve la restauration, durcis le service puis injecte des pannes contrôlées.

Durée indicative · ~2 h 45Niveau intermédiairePrérequis conseillé · Linux avancé ; Réseaux leçons 12 à 19 ; filtrage inter-VLAN ; méthode BTS de preuve et de remédiationPratique · TP
Intégration BTS

« 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.

0
Ta progression

Chargement de l’état… Se connecter pour synchroniser.