> ## Documentation Index
> Fetch the complete documentation index at: https://docs.snakysec.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 08 restore tls certs

# Runbook 08 — Restauration certificats TLS Let's Encrypt

## 1. Quand activer

| Scénario                                                                    | Activer ?                                |
| --------------------------------------------------------------------------- | ---------------------------------------- |
| Browser warning "certificate expired" sur snakysec.com                      | **OUI**                                  |
| Traefik logs : `acme: error: 403 :: urn:ietf:params:acme:error:rateLimited` | **OUI** (rate limit)                     |
| Volume `traefik-acme` corrompu / supprimé                                   | **OUI**                                  |
| Cert valide mais wrong domain (Subject Alternative Names)                   | **OUI** (re-issue avec bonne config)     |
| Reconstruction VPS (runbook 03)                                             | **OUI** automatique au démarrage Traefik |

## 2. Objectifs

* **RPO** : N/A (certs régénérables auto)
* **RTO cible** : 15 minutes (force re-issue)
* **Limite Let's Encrypt** : 5 duplicates/semaine, 50 issuances/semaine par registered domain

## 3. Procédure standard (force re-issue)

### 3.1 Wipe volume traefik-acme

```bash theme={null}
ssh mssp@vps.snakysec.com
cd /opt/mssp/app/platform

# Stop Traefik
make traefik-down

# Wipe ACME storage (supprime acme.json contenant les certs + account key)
docker run --rm \
  -v platform_traefik-acme:/acme \
  alpine sh -c "rm -f /acme/acme.json"
```

### 3.2 Restart Traefik (re-issue auto)

```bash theme={null}
make traefik-up
docker logs -f mssp-traefik
```

Attendre les logs :

```
INF Register... acme=...
INF Test certificate is going to be issued for domain "snakysec.com"
INF Certificate obtained for domains [snakysec.com] from CA Let's Encrypt
```

Durée typique : 30-60 secondes pour le challenge HTTP-01.

### 3.3 Validation

```bash theme={null}
# Test cert externe
echo | openssl s_client -servername snakysec.com -connect snakysec.com:443 2>/dev/null | \
  openssl x509 -noout -dates -issuer
# attendu : 
#   notBefore=<aujourd'hui>
#   notAfter=<aujourd'hui + 90 jours>
#   issuer=CN=R3, O=Let's Encrypt, C=US

# Test browser
curl -sI https://snakysec.com/api/health
# attendu : HTTP/2 200, pas d'erreur SSL
```

## 4. Procédure rate-limited

Si Let's Encrypt refuse pour rate-limit (5 duplicates/semaine atteint) :

### 4.1 Switch staging temporairement

```bash theme={null}
# Editer compose/traefik.prod.yml — ajouter caServer staging
docker compose -f compose/_common.yml -f compose/traefik.prod.yml exec traefik \
  cat /etc/traefik/traefik.yml | grep -A2 acme
```

Modifier la config Traefik (variable d'environnement ou flag CLI) :

```yaml theme={null}
# Dans traefik.prod.yml, ajouter à command:
command:
  - "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
```

Redéployer :

```bash theme={null}
make traefik-down
docker run --rm \
  -v platform_traefik-acme:/acme \
  alpine sh -c "rm -f /acme/acme.json"
make traefik-up
```

Cert staging valide la chaîne (untrusted browser warning, mais HTTPS fonctionne).
Sert de "tampon" en attendant que la fenêtre rate-limit se reset (7 jours rolling).

### 4.2 Bascule fallback ZeroSSL

Si Let's Encrypt vraiment HS plusieurs jours :

```yaml theme={null}
- "--certificatesresolvers.zerossl.acme.email=admin@snakysec.com"
- "--certificatesresolvers.zerossl.acme.eabkid=${ZEROSSL_EAB_KID}"
- "--certificatesresolvers.zerossl.acme.eabhmackey=${ZEROSSL_EAB_HMAC}"
- "--certificatesresolvers.zerossl.acme.caserver=https://acme.zerossl.com/v2/DV90"
```

ZeroSSL keys à provisionner depuis [https://app.zerossl.com](https://app.zerossl.com) (compte gratuit).
Stocker dans Vault `mssp/data/platform/zerossl_eab_*`.

### 4.3 Retour à Let's Encrypt

Une fois la fenêtre passée, retirer la config staging/ZeroSSL et reprendre §3.

## 5. Communication client

Aucune en cas standard (procédure \< 15 min, pas d'impact si fait pendant
heures creuses). Si un client a vu un browser warning :

```
Suite à un renouvellement automatique de notre certificat TLS, certaines
sessions ont pu présenter un avertissement temporaire dans le navigateur.
La situation est rétablie. Aucune donnée n'a été exposée — la connexion
restait chiffrée par notre certificat précédent jusqu'au renouvellement.
```

## 6. Erreurs courantes

| Erreur                                                          | Solution                                                                                                   |
| --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| `acme: error: 400 :: urn:ietf:params:acme:error:invalidContact` | Email manquant dans Traefik config — ajouter `--certificatesresolvers.letsencrypt.acme.email=...`          |
| `acme: error: 403 :: ...rateLimited`                            | 5 duplicates/semaine atteint — switch staging ou ZeroSSL §4                                                |
| `connection refused on port 80`                                 | Firewall bloque port 80 (requis pour HTTP-01) — `ufw allow 80/tcp`                                         |
| Cert valide mais wildcard manquant                              | Pour `*.snakysec.com`, utiliser DNS-01 challenge (plus complexe, requis pour wildcard) — non implémenté V1 |

| Version | Date       | Auteur             |
| ------- | ---------- | ------------------ |
| 1.0     | 2026-04-26 | Nicolas Schiffgens |
