#07 — rgz-gateway
PLANIFIÉ
Priorité: 🔴 CRITIQUE · Type: TYPE A · Conteneur: rgz-gateway · Code: scripts/gateway/ + scripts/qos/
Dépendances: Aucune
Description
rgz-gateway est le pare-feu et routeur central de la plateforme RGZ. Il tourne dans un conteneur Alpine 3.19 avec nftables, iproute2, tc (traffic control) et les outils réseau nécessaires. Sa mission est triple : appliquer le modèle de sécurité deny-all (interdire tout le trafic par défaut, n'autoriser que ce qui est explicitement permis), réaliser le NAT/SNAT par revendeur pour l'isolation inter-VLAN, et appliquer le QoS HTB+fq_codel pour garantir la qualité de service des abonnés WiFi.
La politique de sécurité nftables est "deny-all" : toutes les connexions entrantes et sortantes sont refusées par défaut. Seules les exceptions explicitement configurées sont autorisées : accès Internet des abonnés authentifiés RADIUS, trafic MGMT vers les adresses de management, flux SNMP vers les CPE, etc. Les VLANs sont alloués dans la plage 100-499 (un par revendeur, calculé par l'outil #31), chacun isolé des autres par des règles nftables distinctes — un abonné VLAN 142 ne peut pas atteindre un abonné VLAN 150.
Le QoS est implémenté en deux couches. La première couche (htb_setup.sh — outil #27) configure des classes HTB (Hierarchical Token Bucket) avec tc : classe MGMT (priorité haute, trafic de management et VoIP), classe Interactive (trafic web normal), classe Bulk (téléchargements, P2P). La deuxième couche (dscp_marking.sh — outil #28) marque les paquets avec les valeurs DSCP appropriées (EF pour MGMT, AF41 pour Interactive, BE pour Bulk), ce qui permet aux équipements réseau intermédiaires de respecter la priorité QoS.
La règle LL#40 est critique sur ce service : il ne faut jamais utiliser nft flush ruleset sur un serveur Docker, car cela détruirait les chains iptables-nft générées par Docker (qui utilise iptables-nft en backend). La règle LL#41 complète cela : les tables nftables custom persistent sur l'hôte même après le restart du conteneur, donc l'entrypoint doit supprimer sélectivement ses tables custom avant de les recréer.
Architecture Interne
rgz-gateway (Alpine 3.19 + nftables + iproute2 + tc)
│
├── nftables rules (scripts/gateway/rgz-main.nft)
│ │
│ ├── table inet rgz_filter
│ │ ├── chain input — deny-all inbound, allow ESTABLISHED
│ │ ├── chain forward — deny-all between VLANs
│ │ │ ├── allow VLAN→Internet (abonnés authentifiés)
│ │ │ ├── deny VLAN→VLAN (isolation revendeurs)
│ │ │ └── allow MGMT→all
│ │ └── chain output — allow localhost, log drops
│ │
│ └── table ip rgz_nat
│ └── chain postrouting — SNAT par revendeur (masquerade par VLAN)
│
├── QoS HTB (scripts/qos/htb_setup.sh — outil #27)
│ ├── Root qdisc HTB sur interface wan (eth0)
│ ├── Class 1:10 MGMT — CIR=10Mbps, MIR=50Mbps, prio=1
│ ├── Class 1:20 Interactive — CIR=5Mbps/user, MIR=MIR_dynamique, prio=2
│ └── Class 1:30 Bulk — CIR=1Mbps, MIR=MIR_dynamique, prio=3
│ └── fq_codel qdisc (anti-bufferbloat)
│
└── DSCP Marking (scripts/qos/dscp_marking.sh — outil #28)
├── tcp dport {80,443} → DSCP AF41 (Interactive)
├── tcp dport {22,161,3799} → DSCP EF (MGMT)
└── default → DSCP BE (Bulk)
Isolation VLAN (exemple avec 3 revendeurs):
VLAN 142 (Kossou) : 10.142.0.0/24 → Internet (OK) | VLAN 143 (INTERDIT)
VLAN 143 (Gbéto) : 10.143.0.0/24 → Internet (OK) | VLAN 142 (INTERDIT)
VLAN 150 (Tech) : 10.150.0.0/24 → Internet (OK) | VLAN 142,143 (INTERDIT)Configuration
Variables d'environnement
| Variable | Exemple | Description |
|---|---|---|
WAN_INTERFACE | eth0 | Interface réseau WAN (Internet) |
LAN_INTERFACE | eth1 | Interface réseau LAN (VLAN trunks) |
MGMT_CIDR | 172.23.0.0/16 | Réseau Docker management |
VLAN_RANGE_START | 100 | Premier VLAN revendeur |
VLAN_RANGE_END | 499 | Dernier VLAN revendeur |
Fichiers importants
scripts/gateway/
├── rgz-main.nft # Règles nftables deny-all, NAT, SNAT par VLAN
├── nftables_generator.py # #32 — Génère dynamiquement les règles par revendeur
└── watch_config.sh # Hot-reload quand la config change
scripts/qos/
├── htb_setup.sh # #27 — HTB + fq_codel via tc
└── dscp_marking.sh # #28 — Marquage DSCP (nftables mangle)
docker/gateway/
├── Dockerfile # alpine:3.19 + nftables + iproute2 + python3
└── entrypoint.sh # Nettoyage tables custom + chargement règlesrgz-main.nft (structure)
# LL#40: JAMAIS flush ruleset → suppression sélective par table
# LL#41: L'entrypoint supprime ces tables avant de les recréer
table inet rgz_filter {
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
iif lo accept
tcp dport 22 ip saddr 172.23.0.0/16 accept # SSH depuis MGMT
drop
}
chain forward {
type filter hook forward priority 0; policy drop;
ct state established,related accept
# Abonnés vers Internet
iifname "vlan*" oifname $WAN_INTERFACE ct state new accept
# Isolation inter-VLAN : refus croisé
iifname "vlan*" oifname "vlan*" drop log prefix "INTER-VLAN-DROP: "
}
chain output {
type filter hook output priority 0; policy accept;
}
}
table ip rgz_nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname $WAN_INTERFACE masquerade
}
}entrypoint.sh (LL#40 + LL#41)
#!/bin/sh
# LL#40: Ne jamais utiliser 'nft flush ruleset' — détruit chains Docker iptables-nft
# LL#41: Supprimer sélectivement nos tables custom au démarrage
# Supprimer les tables custom de la session précédente (persistent sur l'hôte)
nft delete table inet rgz_filter 2>/dev/null || true
nft delete table ip rgz_nat 2>/dev/null || true
# Charger les nouvelles règles
nft -f /etc/nftables/rgz-main.nft
# Configurer le QoS HTB
sh /scripts/qos/htb_setup.sh
# Marquer DSCP
sh /scripts/qos/dscp_marking.sh
# Garder le conteneur actif
exec tail -f /dev/nullQoS — Classes HTB
| Classe | Interface | CIR | MIR (dynamique) | DSCP | Usage |
|---|---|---|---|---|---|
| 1:10 MGMT | WAN | 10 Mbps | 50 Mbps | EF (46) | SSH, SNMP, CoA, management |
| 1:20 Interactive | WAN | 5 Mbps/user | DBA calculé | AF41 (34) | HTTP, HTTPS, DNS |
| 1:30 Bulk | WAN | 1 Mbps/user | DBA calculé | BE (0) | Téléchargements, P2P |
Healthcheck
# Vérifier que nftables est chargé
docker exec rgz-gateway nft list ruleset | grep -c "chain" && echo "OK"
# Vérifier les tables créées
docker exec rgz-gateway nft list tables
# Vérifier QoS HTB
docker exec rgz-gateway tc qdisc show dev eth0
# Tester le forward (abonné → Internet)
docker exec rgz-gateway nft list chain inet rgz_filter forward
# Status du conteneur
docker inspect rgz-gateway --format='{}'Sécurité
| Règle | Implémentation |
|---|---|
| LL#40 nftables | Jamais nft flush ruleset — supprimer table par table sélectivement |
| LL#41 Persistance | entrypoint.sh fait nft delete table inet rgz_filter avant rechargement |
| Deny-all | Policy drop sur toutes les chains input/forward, exceptions explicites |
| Isolation VLAN | Drop explicite des paquets inter-VLAN avec logging |
| NET_ADMIN | Conteneur requiert cap_add: [NET_ADMIN, NET_RAW] dans docker-compose |
Commandes Utiles
# Démarrage avec rebuild
docker compose -f /home/claude-dev/RGZ/docker-compose.core.yml up -d --build rgz-gateway
# Logs (inclut les DROP loggés)
docker logs rgz-gateway -f --tail=100
# Lister toutes les règles nftables actives
docker exec rgz-gateway nft list ruleset
# Voir les compteurs par règle
docker exec rgz-gateway nft list ruleset -a
# Statistiques QoS HTB en temps réel
docker exec rgz-gateway watch -n1 "tc -s qdisc show dev eth0"
# Ajouter dynamiquement une règle VLAN (via nftables_generator.py — outil #32)
docker exec rgz-gateway python3 /scripts/gateway/nftables_generator.py \
--add-vlan 142 --subnet 10.142.0.0/24
# Tester la connectivité d'un abonné simulé
docker exec rgz-gateway nft list chain inet rgz_filter forward
# Voir les paquets droppés (logs syslog)
docker exec rgz-gateway dmesg | grep "INTER-VLAN-DROP"Implémentation TODO
- [x] Dockerfile créé (
docker/gateway/Dockerfile) - [x] entrypoint.sh créé (
docker/gateway/entrypoint.sh) - [x] Service défini dans
docker-compose.core.yml - [x] Variables d'env dans
.env.example - [ ]
scripts/gateway/rgz-main.nft— Règles deny-all, forward VLAN→WAN, isolation - [ ]
scripts/gateway/nftables_generator.py— #32 Génération dynamique par revendeur - [ ]
scripts/gateway/watch_config.sh— Inotifywait + hot-reload - [ ]
scripts/qos/htb_setup.sh— #27 Configuration HTB + fq_codel - [ ]
scripts/qos/dscp_marking.sh— #28 Marquage DSCP par type de trafic - [ ] Tests de performance QoS (iperf3 — outil #79)
- [ ] Tests isolation VLAN (ping inter-VLAN doit échouer)
- [ ] Validation LL#40 et LL#41 sur serveur Docker réel
Dernière mise à jour: 2026-02-21