feat(security): durcissement edge funklab.online (vraie IP client + rate-limit + TLS/headers) (#95)

- Traefik externalTrafficPolicy: Local → IP client réelle (fin du SNAT kube-proxy)
- middleware ratelimit par IP (100/min, burst 200) sur les 6 routes publiques
- middleware security-headers (HSTS, nosniff, X-Frame SAMEORIGIN, Referrer-Policy)
- TLSOption globale : plancher TLS 1.2 + ciphers modernes
- Guacamole REMOTE_IP_VALVE → ban anti-bruteforce par IP (fin du piège n°5)
- nftables : fermeture des ports Internet legacy 9080/9081 (HTTP clair redondant)
- allowCrossNamespace pour mutualiser les middlewares depuis infra
- docs : section Durcissement (public-domain.md) + CAA OVH + pièges à jour

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ALI YESILKAYA 2026-07-07 22:58:24 +02:00 committed by GitHub
parent a13b5a70cd
commit fe0aa89ffa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 178 additions and 19 deletions

View file

@ -117,8 +117,10 @@ Config côté Authentik (UI) — Redirect URI par app : voir le tableau de
## Pièges / notes
1. **Tout est en HTTP** (pas de TLS) — accepté y compris pour l'accès Internet
(cf. section ci-dessus), avec garde-fous réseau + mots de passe dédiés.
1. **HTTPS sur Internet, HTTP en interne** : l'accès public passe par
`*.funklab.online` en **TLS Let's Encrypt** (durcissement 2026-07-07) ; les routes
internes `*.lab.local` restent en HTTP clair (LAN de confiance). L'issuer OIDC est
donc le domaine HTTPS (cf. piège n°2).
2. **JWKS via le Service interne** (`authentik.auth.svc.cluster.local:9000`) : l'appel
serveur→serveur de Guacamole ne dépend pas de la résolution `lab.local` des pods.
L'issuer, lui, reste `http://auth.lab.local/...` (doit matcher le claim `iss` des
@ -132,9 +134,13 @@ Config côté Authentik (UI) — Redirect URI par app : voir le tableau de
le génère depuis le nom (« Portail consoles » → `portail-consoles`) et l'issuer/JWKS
deviennent faux → log Guacamole `Non 200 status code (404) ... /o/guacamole/jwks/`
et token rejeté. Corriger : Applications → Edit → Slug.
5. **Anti-bruteforce intégré** (extension `ban`) : 5 échecs → IP bloquée ~5 min. Derrière
Traefik, l'IP vue est celle du proxy → **le blocage touche tout le monde**. Patienter
ou redémarrer le pod guacamole pour purger.
5. **Anti-bruteforce intégré** (extension `ban`) : 5 échecs → IP bloquée ~5 min.
**Corrigé (2026-07-07)** : `REMOTE_IP_VALVE_ENABLED=true` (deployment) + Traefik en
`externalTrafficPolicy: Local` → Guacamole lit l'IP client réelle (X-Forwarded-For), le
ban est **par IP** et non plus global. Avant ce fix, l'IP vue était celle du pod Traefik
→ le blocage touchait tout le monde. Si un ban global réapparaît : vérifier que la valve
est active et que Traefik n'est pas repassé en `Cluster`. Purge immédiate : redémarrer le
pod guacamole.
6. **User `console` sans sudo** (volontaire) : le portail sert à observer/opérer léger.
L'administration passe par les comptes admin habituels, pas par Guacamole.
7. **Enregistrement des sessions** : possible (guacd + volume partagé) mais non configuré

View file

@ -20,8 +20,10 @@ Internet ─▶ grafana.funklab.online ─┐ DNS OVH : *.funklab.online → 82
- **Split-horizon** : dnsmasq résout `*.funklab.online → Traefik (192.168.10.200)` en
interne → le LAN utilise les **mêmes URLs** sans sortir sur Internet.
- **Ports historiques conservés** : le hub reste aussi joignable en `kaya.freeboxos.fr:9081/9080`
(bascule non destructive).
- **Ports historiques `9080/9081` fermés côté Internet** (durcissement 2026-07-07) :
l'accès direct HTTP clair à Authentik/Guacamole n'existe plus depuis le WAN — tout
passe par le domaine en HTTPS. Les VIPs `.201/.202` restent joignables en LAN.
(Penser à retirer aussi les redirections Freebox `9080/9081`.)
## Prérequis (une fois, côté fournisseurs)
@ -119,6 +121,51 @@ Manifests : `k8s/apps/*/ingress-public.yaml`, `k8s/infra/monitoring/ingressroute
Détail de l'ajout d'une app au hub : `admin/k8s/auth-portal-admin.md`.
## Durcissement (edge) — état 2026-07-07
Couche de sécurité appliquée à toutes les routes `funklab.online`. Manifests :
`k8s/infra/traefik/{values.yaml,middlewares.yaml,tls-options.yaml}` (Traefik **hors
ArgoCD** → `kubectl apply` + `helm upgrade`).
| Mesure | Où | Effet |
|---|---|---|
| **IP client réelle** | `service.spec.externalTrafficPolicy: Local` (values.yaml) | Traefik voit l'IP source réelle (sinon SNAT kube-proxy → IP d'un nœud). Prérequis du rate-limit par IP et du ban Guacamole par IP. |
| **Rate-limit par IP** | Middleware `ratelimit` (infra) sur chaque route | ~100 req/min soutenu, burst 200, **par IP client**. Anti-scan/bruteforce volumétrique. |
| **En-têtes sécurité** | Middleware `security-headers` (infra) | HSTS 1 an+subdomains, `nosniff`, `X-Frame-Options: SAMEORIGIN`, `Referrer-Policy`. |
| **TLS ≥ 1.2** | `TLSOption` globale `default/default` | Plancher TLS 1.2 + ciphers modernes (TLS 1.3 auto). |
| **Ban Guacamole par IP** | `REMOTE_IP_VALVE_ENABLED` (deployment guacamole) | Le ban 5-échecs vise l'IP réelle, plus tout le monde (fin du piège n°5). |
| **Ports 9080/9081 fermés (WAN)** | rôle `gateway` (nftables) | Supprime le chemin HTTP clair direct vers Authentik/Guacamole. |
> Les middlewares du namespace `infra` sont référencés cross-namespace →
> `providers.kubernetesCRD.allowCrossNamespace: true` requis (values.yaml).
**Cross-check DNS (à faire côté OVH)** : ajouter un enregistrement **CAA** pour
restreindre l'émission de certificats à Let's Encrypt uniquement :
```
funklab.online. CAA 0 issue "letsencrypt.org"
funklab.online. CAA 0 iodef "mailto:aliyesilkaya93@gmail.com"
```
**Application** (Traefik est hors ArgoCD) :
```bash
helm upgrade traefik traefik/traefik -n infra --version 40.1.0 \
-f k8s/infra/traefik/values.yaml # externalTrafficPolicy + allowCrossNamespace
kubectl apply -f k8s/infra/traefik/middlewares.yaml
kubectl apply -f k8s/infra/traefik/tls-options.yaml
kubectl apply -f k8s/argocd-bootstrap/ingressroute-public.yaml # ArgoCD non auto-sync
ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags gateway # ports legacy
```
Les IngressRoutes des apps `ai/auth/monitoring` sont synchronisées par ArgoCD (merge main).
**Vérifier** :
```bash
curl -sI https://auth.funklab.online | grep -i 'strict-transport\|x-frame'
nmap --script ssl-enum-ciphers -p 443 auth.funklab.online | grep -i tlsv1
```
**Pistes suivantes** (non faites) : MFA/TOTP Authentik (protège tout le hub),
CrowdSec bouncer Traefik (réputation IP), restreindre ArgoCD au LAN+VPN (IPAllowList).
## Pièges
1. **Cert bloqué en « TRAEFIK DEFAULT CERT »** : DNS pas encore propagé ou Freebox