Paillasse/docs/runbooks/https.md

61 lines
3.5 KiB
Markdown
Raw Normal View History

# Runbook — HTTPS, en-têtes de sécurité, page de statut (étape 12)
## Où sont les choses
| Élément | Emplacement |
|---|---|
| Certificat | `/etc/letsencrypt/live/syllabuslab.fr/` (un seul certificat : `syllabuslab.fr`, `www`, et `status` quand son DNS existe) |
| Renouvellement | `certbot.timer` (deux fois par jour), authentificateur nginx, puis `systemctl reload nginx` |
| Alerte d'expiration | métrique `syllabus_certificat_expiration_timestamp` (script `/usr/local/sbin/syllabus-expiration-certificat`, cron quotidien), règles `CertificatExpireBientot` et `CertificatNonMesure` (`kolla/config/prometheus/alertes.rules`) |
| Vhost | `ansible/roles/portail/templates/nginx-portail.conf.j2` → `/etc/nginx/sites-available/portail.conf` |
| TLS et en-têtes | `/etc/nginx/snippets/syllabus-tls.conf`, `syllabus-entetes.conf` (rôle `portail`) |
| CSP | `portail/app/Http/Middleware/PolitiqueSecuriteContenu.php` ; violations dans `storage/logs/laravel.log` (« Violation CSP ») |
| Décisions | [ADR 0004](../adr/0004-https-csp-et-exposition.md) |
Tout est posé par `ansible-playbook portail.yml`.
## Vérifier
```
curl -sSI https://syllabuslab.fr/connexion | grep -iE "strict-transport|content-security|x-frame"
echo | openssl s_client -connect syllabuslab.fr:443 -servername syllabuslab.fr 2>/dev/null | openssl x509 -noout -dates -ext subjectAltName
ssh paillasse "sudo certbot renew --dry-run" # renouvellement simulé (environnement de test Let's Encrypt)
ssh paillasse "sudo grep -c 'Violation CSP' /var/www/portail/storage/logs/laravel.log"
```
## Activer la page de statut
1. Ajouter chez OVH : `status.syllabuslab.fr` A `163.172.4.195`.
2. Vérifier qu'il est publié : `dig +short A status.syllabuslab.fr @ns111.ovh.net`.
3. Dans Uptime Kuma (par tunnel), créer une page de statut avec l'identifiant (slug) `syllabus` et y mettre les sondes à publier.
4. `cd ansible && script -q /dev/null ansible-playbook portail.yml -i inventory.ini` : le rôle détecte le nom, l'ajoute au certificat et active le site.
5. Vérifier : `https://status.syllabuslab.fr` affiche la page ; `https://status.syllabuslab.fr/dashboard` et `/metrics` répondent 404.
## Si le certificat va expirer (alerte)
```
ssh paillasse "systemctl status certbot.timer; sudo journalctl -u certbot --since -3d | tail -30"
ssh paillasse "sudo certbot renew"
```
Causes probables : port 80 inaccessible depuis Internet, DNS modifié,
configuration Nginx invalide (`sudo nginx -t`). Limite Let's Encrypt :
5 échecs de validation par heure et par nom — corriger avant de réessayer.
## Ajouter un script à une page de l'application
La CSP stricte bloque tout script sans le nonce de la requête :
```
<script nonce="{{ Vite::cspNonce() }}">…</script>
```
Pas de `onclick="…"` : utiliser `addEventListener` dans un script avec nonce.
Pas de CDN : passer par Vite (`resources/js/`).
## Pièges (évités ou rencontrés)
- Évité par conception : une redirection `return 301` au niveau `server` s'exécute avant toute `location`, elle risquerait de court-circuiter le défi ACME que certbot insère au renouvellement. Les redirections sont dans `location /` ; `certbot renew --dry-run` réussit.
- `X25519MLKEM768` (recommandé par Mozilla v6.0) demande OpenSSL 3.5 ; Debian 12 a OpenSSL 3.0 : retiré par précaution (non essayé). À réintroduire au passage à Debian 13.
- Depuis Internet, un scan peut montrer 21, 554 et 1723 ouverts : c'est la box du réseau qui scanne (même résultat vers `192.0.2.1`, adresse inexistante). Côté serveur : `sudo ss -tlnp` et `sudo nft list chain inet filter input`.