241 lines
6.3 KiB
Markdown
241 lines
6.3 KiB
Markdown
# 10 — Ingress, TLS et Cloudflare
|
|
|
|
---
|
|
|
|
## Architecture TLS
|
|
|
|
Deux approches possibles, que vous pouvez combiner :
|
|
|
|
```
|
|
Option 1 — TLS Cloudflare uniquement (plus simple)
|
|
Browser → Cloudflare (TLS terminé) → HTTP vers Hetzner LB → Pods
|
|
|
|
Option 2 — TLS de bout en bout (plus sécurisé)
|
|
Browser → Cloudflare → HTTPS vers Hetzner LB → cert-manager TLS → Pods
|
|
|
|
Recommandation : Option 2 avec Cloudflare en "Full (strict)" mode
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration Cloudflare
|
|
|
|
### 1. Ajouter les entrées DNS
|
|
|
|
Dans votre dashboard Cloudflare → Votre domaine → DNS → Records :
|
|
|
|
```
|
|
Type Name Content Proxy TTL
|
|
A api <IP_LB_HETZNER> ✅ ON Auto
|
|
A app <IP_LB_HETZNER> ✅ ON Auto
|
|
A @ <IP_LB_HETZNER> ✅ ON Auto
|
|
```
|
|
|
|
Pour obtenir l'IP du Load Balancer Hetzner :
|
|
```bash
|
|
hcloud load-balancer list
|
|
# ID NAME TYPE LOCATION PUBLIC NET PRIVATE NET
|
|
# 12345 xpeditis-lb lb11 fsn1 1.2.3.4 / 2001::... 10.0.0.2
|
|
```
|
|
|
|
### 2. SSL/TLS Mode
|
|
|
|
Cloudflare → Votre domaine → SSL/TLS → Overview :
|
|
- Sélectionnez **Full (strict)** ← obligatoire si cert-manager gère les certicats côté Hetzner
|
|
|
|
### 3. Page Rules / Transform Rules
|
|
|
|
Cloudflare → Votre domaine → Rules → Page Rules :
|
|
|
|
```
|
|
Rule 1 : Force HTTPS
|
|
If URL matches: http://api.xpeditis.com/*
|
|
Then: Always Use HTTPS
|
|
|
|
Rule 2 : Force HTTPS frontend
|
|
If URL matches: http://app.xpeditis.com/*
|
|
Then: Always Use HTTPS
|
|
```
|
|
|
|
### 4. WAF Rules (optionnel mais recommandé)
|
|
|
|
Cloudflare → Security → WAF → Managed Rules :
|
|
- Activer **Cloudflare Managed Ruleset** (gratuit)
|
|
- Activer **Cloudflare OWASP Core Ruleset** (gratuit)
|
|
|
|
Custom Rules pour Xpeditis :
|
|
```
|
|
Rule: Block rate search abuse
|
|
If: (http.request.uri.path contains "/api/v1/rates/search") AND (rate(1m) > 60)
|
|
Then: Block
|
|
|
|
Rule: Protect Stripe webhook
|
|
If: (http.request.uri.path eq "/api/v1/subscriptions/webhook") AND (not ip.src in {151.101.0.0/17})
|
|
Then: Block ← Autorise uniquement les IPs Stripe
|
|
```
|
|
|
|
### 5. Cache Rules (pour les assets frontend)
|
|
|
|
Cloudflare → Caching → Cache Rules :
|
|
```
|
|
Rule: Cache Next.js static assets
|
|
If: (http.request.uri.path contains "/_next/static/")
|
|
Then: Cache Everything, TTL 1 year
|
|
```
|
|
|
|
---
|
|
|
|
## Vérification du certificat TLS (cert-manager)
|
|
|
|
Après le déploiement de l'Ingress :
|
|
|
|
```bash
|
|
# Vérifier l'état du certificat
|
|
kubectl get certificate -n xpeditis-prod
|
|
# NAME READY SECRET AGE
|
|
# xpeditis-tls-prod True xpeditis-tls-prod 5m ← READY=True = succès
|
|
|
|
# Si READY=False, debugger :
|
|
kubectl describe certificate xpeditis-tls-prod -n xpeditis-prod
|
|
kubectl describe certificaterequest -n xpeditis-prod
|
|
kubectl logs -n cert-manager deployment/cert-manager | tail -50
|
|
|
|
# Voir les challenges ACME en cours
|
|
kubectl get challenge -n xpeditis-prod
|
|
# Si des challenges sont en attente, vérifier que le DNS Cloudflare pointe bien vers le LB
|
|
```
|
|
|
|
### Tester la chaîne TLS
|
|
|
|
```bash
|
|
# Tester le certificat
|
|
curl -I https://api.xpeditis.com/api/v1/health
|
|
# HTTP/2 200
|
|
# server: traefik
|
|
# content-type: application/json
|
|
|
|
# Détails du certificat
|
|
openssl s_client -connect api.xpeditis.com:443 -servername api.xpeditis.com 2>/dev/null | openssl x509 -noout -dates
|
|
# notBefore=Apr 1 00:00:00 2026 GMT
|
|
# notAfter=Jun 30 00:00:00 2026 GMT ← Let's Encrypt = 90 jours, renouvellement auto à 60 jours
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration WebSocket Socket.IO
|
|
|
|
Socket.IO nécessite une configuration spécifique pour fonctionner derrière Traefik + Cloudflare.
|
|
|
|
### Cloudflare WebSocket
|
|
|
|
Cloudflare → Votre domaine → Network → WebSockets :
|
|
- **Activer WebSockets** (désactivé par défaut sur le plan Free)
|
|
|
|
> Note : Sur le plan Free Cloudflare, les WebSockets sont supportés mais avec un timeout de 100s. Pour les connexions persistantes Socket.IO, configurez des reconnexions côté client.
|
|
|
|
### Traefik Sticky Sessions
|
|
|
|
La configuration des sticky sessions dans `k8s/07-ingress.yaml` garantit que les reconnexions WebSocket retombent sur le même pod (important pour Socket.IO avant l'implémentation Redis adapter) :
|
|
|
|
```yaml
|
|
annotations:
|
|
traefik.ingress.kubernetes.io/service.sticky.cookie: "true"
|
|
traefik.ingress.kubernetes.io/service.sticky.cookie.name: "XPEDITIS_BACKEND"
|
|
traefik.ingress.kubernetes.io/service.sticky.cookie.secure: "true"
|
|
```
|
|
|
|
### Test WebSocket
|
|
|
|
```bash
|
|
# Test avec wscat (npm install -g wscat)
|
|
wscat -c "wss://api.xpeditis.com/notifications" \
|
|
-H "Authorization: Bearer <JWT_TOKEN>"
|
|
|
|
# La connexion doit s'établir et recevoir :
|
|
# {"event":"unread_count","data":{"count":0}}
|
|
# {"event":"recent_notifications","data":[...]}
|
|
```
|
|
|
|
---
|
|
|
|
## Traefik Dashboard (accès restreint)
|
|
|
|
```bash
|
|
# Traefik a un dashboard utile pour debugger les routes
|
|
# Activer l'accès avec authentification
|
|
|
|
# Générer un mot de passe htpasswd
|
|
htpasswd -nb admin <MOT_DE_PASSE> | base64
|
|
|
|
# Créer un Middleware BasicAuth
|
|
cat > /tmp/traefik-auth.yaml << 'EOF'
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: traefik-dashboard-auth
|
|
namespace: kube-system
|
|
type: kubernetes.io/basic-auth
|
|
stringData:
|
|
username: admin
|
|
password: <MOT_DE_PASSE>
|
|
---
|
|
apiVersion: traefik.io/v1alpha1
|
|
kind: Middleware
|
|
metadata:
|
|
name: dashboard-auth
|
|
namespace: kube-system
|
|
spec:
|
|
basicAuth:
|
|
secret: traefik-dashboard-auth
|
|
---
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: Ingress
|
|
metadata:
|
|
name: traefik-dashboard
|
|
namespace: kube-system
|
|
annotations:
|
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
|
traefik.ingress.kubernetes.io/router.middlewares: "kube-system-dashboard-auth@kubernetescrd"
|
|
spec:
|
|
ingressClassName: traefik
|
|
tls:
|
|
- hosts:
|
|
- traefik.xpeditis.com
|
|
secretName: traefik-tls
|
|
rules:
|
|
- host: traefik.xpeditis.com
|
|
http:
|
|
paths:
|
|
- path: /
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: traefik
|
|
port:
|
|
number: 9000
|
|
EOF
|
|
|
|
kubectl apply -f /tmp/traefik-auth.yaml
|
|
```
|
|
|
|
---
|
|
|
|
## Checklist TLS
|
|
|
|
```bash
|
|
echo "=== Test endpoints ==="
|
|
curl -sf https://api.xpeditis.com/api/v1/health | jq .
|
|
curl -sf https://app.xpeditis.com/ | head -5
|
|
|
|
echo "=== Certificats ==="
|
|
kubectl get certificate -n xpeditis-prod
|
|
kubectl get certificaterequest -n xpeditis-prod
|
|
|
|
echo "=== Ingress ==="
|
|
kubectl get ingress -n xpeditis-prod
|
|
|
|
echo "=== Test HTTPS force ==="
|
|
curl -L http://api.xpeditis.com/api/v1/health
|
|
# Doit être redirigé vers HTTPS
|
|
```
|