Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018BAUeCFpDkRD6tU5wGsc1C
172 lines
6.1 KiB
Markdown
172 lines
6.1 KiB
Markdown
# Configuration Cloudflare — production
|
|
|
|
Cloudflare est la première ligne de défense : DNS, anti-DDoS, WAF, cache.
|
|
Le firewall Hetzner n'accepte 80/443 **que** depuis les rangs Cloudflare, donc
|
|
si le proxy est désactivé sur un enregistrement, ce domaine devient
|
|
inaccessible. C'est voulu : personne ne doit pouvoir taper l'IP d'origine.
|
|
|
|
Le plan Free suffit en phase 1 (≈ 100 utilisateurs). Le plan Pro (20 €/mois,
|
|
prévu au budget à partir de 1 000 utilisateurs) ajoute le WAF managé et
|
|
l'analyse de bots.
|
|
|
|
---
|
|
|
|
## 1. Enregistrements DNS
|
|
|
|
Toutes les valeurs `<IP_APP_01>` viennent de `make tf-output`.
|
|
|
|
| Type | Nom | Contenu | Proxy | TTL |
|
|
|---|---|---|---|---|
|
|
| A | `xpeditis.com` | `<IP_APP_01>` | **Proxifié** | Auto |
|
|
| A | `www` | `<IP_APP_01>` | **Proxifié** | Auto |
|
|
| A | `app` | `<IP_APP_01>` | **Proxifié** | Auto |
|
|
| A | `api` | `<IP_APP_01>` | **Proxifié** | Auto |
|
|
| A | `grafana` | `<IP_APP_01>` | **Proxifié** | Auto |
|
|
| AAAA | idem si IPv6 activée | `<IPv6_APP_01>` | **Proxifié** | Auto |
|
|
|
|
**Aucun enregistrement ne pointe vers db-01.** Son IP publique ne sert qu'au
|
|
SSH d'administration et ne doit apparaître nulle part en DNS.
|
|
|
|
### Messagerie (obligatoire pour que les e-mails arrivent)
|
|
|
|
| Type | Nom | Contenu |
|
|
|---|---|---|
|
|
| TXT | `xpeditis.com` | `v=spf1 include:spf.brevo.com -all` |
|
|
| TXT | `mail._domainkey` | clé DKIM fournie par Brevo |
|
|
| TXT | `_dmarc` | `v=DMARC1; p=quarantine; rua=mailto:dmarc@xpeditis.com; pct=100` |
|
|
|
|
Sans SPF/DKIM/DMARC, les confirmations de réservation et les liens magiques
|
|
transporteurs partent en spam — un défaut de production silencieux et coûteux.
|
|
Commencez à `p=quarantine`, passez à `p=reject` après deux semaines de rapports
|
|
propres.
|
|
|
|
---
|
|
|
|
## 2. Réglages SSL/TLS
|
|
|
|
| Réglage | Valeur | Pourquoi |
|
|
|---|---|---|
|
|
| Mode de chiffrement | **Full (strict)** | Cloudflare vérifie le certificat Let's Encrypt du serveur. En « Flexible », le trafic Cloudflare → origine serait en clair. |
|
|
| Always Use HTTPS | Activé | |
|
|
| Minimum TLS Version | **1.2** | TLS 1.0/1.1 sont cassés et refusés par la plupart des référentiels de conformité. |
|
|
| TLS 1.3 | Activé | |
|
|
| Automatic HTTPS Rewrites | Activé | |
|
|
| HSTS | **Activé après vérification** | Voir l'avertissement ci-dessous. |
|
|
|
|
> **HSTS est irréversible pendant un an.** Ne l'activez qu'une fois certain que
|
|
> *tous* les sous-domaines servent bien du HTTPS valide. Traefik pose déjà
|
|
> l'en-tête (`k8s/base/08-traefik-middlewares.yaml`) ; l'activer aussi côté
|
|
> Cloudflare ajoute la protection avant même que la requête n'atteigne le
|
|
> serveur.
|
|
|
|
---
|
|
|
|
## 3. Règles WAF
|
|
|
|
### 3.1 Bloquer l'accès direct aux chemins d'administration
|
|
|
|
```
|
|
(http.host eq "api.xpeditis.com" and starts_with(http.request.uri.path, "/api/docs"))
|
|
```
|
|
→ Action : **Block**
|
|
|
|
La documentation Swagger est déjà désactivée en production par `main.ts`, mais
|
|
une règle de bordure protège même en cas d'erreur de configuration.
|
|
|
|
### 3.2 Limiter les tentatives de connexion
|
|
|
|
Rate limiting (Security → WAF → Rate limiting rules) :
|
|
|
|
| Champ | Valeur |
|
|
|---|---|
|
|
| Expression | `starts_with(http.request.uri.path, "/api/v1/auth/login")` |
|
|
| Requêtes | 10 |
|
|
| Période | 1 minute |
|
|
| Par | Adresse IP |
|
|
| Action | Block, 10 minutes |
|
|
|
|
Cette limite s'ajoute à celle de Traefik (`rate-limit-auth`) et à celle de
|
|
NestJS (`CustomThrottlerGuard`). Trois couches indépendantes : une erreur de
|
|
configuration sur l'une ne laisse pas la porte ouverte.
|
|
|
|
### 3.3 Protéger le webhook Stripe
|
|
|
|
```
|
|
(http.host eq "api.xpeditis.com" and starts_with(http.request.uri.path, "/api/v1/subscriptions/webhook") and not ip.src in {IP_STRIPE})
|
|
```
|
|
→ Action : **Block**
|
|
|
|
Les rangs d'IP Stripe sont publiés sur
|
|
`https://stripe.com/files/ips/ips_webhooks.txt`. La signature du webhook est
|
|
déjà vérifiée côté applicatif ; ceci évite simplement que du bruit atteigne
|
|
l'application.
|
|
|
|
### 3.4 Filtrage géographique — à décider consciemment
|
|
|
|
Xpeditis sert des transitaires européens. Bloquer tout sauf l'Europe réduit
|
|
massivement le bruit, mais coupe aussi les transitaires asiatiques légitimes
|
|
(les connecteurs transporteurs partent du serveur, ils ne sont pas concernés).
|
|
|
|
**Recommandation** : ne pas bloquer par pays au lancement. Activer plutôt
|
|
« Bot Fight Mode » (gratuit) et surveiller les journaux un mois avant de
|
|
décider.
|
|
|
|
---
|
|
|
|
## 4. Cache
|
|
|
|
| Chemin | Règle |
|
|
|---|---|
|
|
| `api.xpeditis.com/*` | **Bypass cache** — une réponse d'API mise en cache servirait les données d'un utilisateur à un autre. |
|
|
| `app.xpeditis.com/_next/static/*` | Cache Everything, Edge TTL 1 an (contenu au nom versionné). |
|
|
| `app.xpeditis.com/*` | Standard (Next.js gère ses propres en-têtes). |
|
|
|
|
> La règle de bypass sur l'API est **critique**. Un cache mal placé sur une
|
|
> route authentifiée est une fuite de données, pas un problème de performance.
|
|
|
|
---
|
|
|
|
## 5. Jeton API pour cert-manager
|
|
|
|
`My Profile → API Tokens → Create Token → Edit zone DNS`
|
|
|
|
| Permission | Portée |
|
|
|---|---|
|
|
| Zone / DNS / Edit | Zone **xpeditis.com** uniquement |
|
|
| Zone / Zone / Read | Zone **xpeditis.com** uniquement |
|
|
|
|
N'utilisez **jamais** la clé globale du compte : elle permettrait à
|
|
cert-manager — ou à quiconque lirait le Secret — de rediriger tout votre trafic.
|
|
|
|
Le jeton alimente le Secret `cert-manager/cloudflare-api-token`
|
|
(`k8s/base/03-secrets.template.yaml`).
|
|
|
|
---
|
|
|
|
## 6. Accès à Grafana
|
|
|
|
Deux options, au choix :
|
|
|
|
- **Liste d'IP** (par défaut) — middleware Traefik `admin-ip-allowlist`,
|
|
à renseigner dans `k8s/base/08-traefik-middlewares.yaml`.
|
|
- **Cloudflare Access** (Zero Trust, gratuit jusqu'à 50 utilisateurs) —
|
|
authentification par e-mail à usage unique devant `grafana.xpeditis.com`.
|
|
Préférable si votre IP est dynamique.
|
|
|
|
---
|
|
|
|
## 7. Vérification
|
|
|
|
```bash
|
|
# Le proxy est-il bien actif ? (l'IP retournée doit être une IP Cloudflare)
|
|
dig +short app.xpeditis.com
|
|
|
|
# L'origine est-elle injoignable en direct ?
|
|
curl -sS --max-time 5 --connect-to app.xpeditis.com:443:<IP_APP_01>:443 \
|
|
https://app.xpeditis.com/ # doit échouer par timeout
|
|
|
|
# SPF / DKIM / DMARC
|
|
dig +short TXT xpeditis.com
|
|
dig +short TXT _dmarc.xpeditis.com
|
|
```
|