# Réseau — nftables, routage, NAT Tout ce qui suit s'exécute sur **storage-01** sauf mention contraire. --- ## Interfaces réseau storage-01 | Interface | IP | Rôle | |---|---|---| | `enp4s0` | `192.168.1.200` | WAN — vers Freebox (LAN domestique) | | `enp6s0f3u2c2` | `192.168.10.1` | LAN cluster — vers machines | > Noms contre-intuitifs : `enp6s0f3u2c2` est une carte USB-Ethernet (cluster), > `enp4s0` est la carte PCIe (WAN). --- ## Topologie physique — switch cluster Le LAN cluster `192.168.10.0/24` repose sur **un switch Ethernet physique**. storage-01 n'a qu'une seule interface côté cluster (`enp6s0f3u2c2`, `192.168.10.1`) : elle ne peut pas relier 4 machines en direct, donc un switch fait le fan-out. ``` Freebox (192.168.1.0/24, WAN domestique) │ enp4s0 (192.168.1.200) storage-01 ── enp6s0f3u2c2 (192.168.10.1) │ [ SWITCH cluster ] ← switch physique (modèle à confirmer) ├── gpu-01 192.168.10.20 ├── compute-01 192.168.10.11 ├── compute-02 192.168.10.12 └── compute-03 192.168.10.13 ``` | Élément | Valeur | |---|---| | Présence d'un switch | **Oui** — indispensable au câblage (1 NIC cluster sur storage-01 ↔ 4 machines) | | Modèle / marque | ⚠️ **non documenté** — à relever physiquement (étiquette au dos) | | Type (managé / non-managé) | à confirmer | | Nb de ports utilisés | ≥ 5 (storage-01 + gpu-01 + 3 compute) | | Managé ? | inconnu — pas de VLAN ni LACP configuré côté Talos/storage-01 à ce jour | > À compléter : noter la référence exacte du switch (mod. + ports) lors d'un prochain > passage physique au cluster. Le reste de la topologie L3 (routage, NAT) est ci-dessous. --- ## Route statique poste perso Pour atteindre le LAN cluster depuis le poste (`192.168.1.10`) : ```bash # Route permanente (NetworkManager) nmcli connection modify enp12s0 +ipv4.routes "192.168.10.0/24 192.168.1.200" nmcli connection up enp12s0 # Vérifier ip route | grep 192.168.10 ping 192.168.10.20 # gpu-01 ``` La route statique Freebox (`192.168.10.0/24 → 192.168.1.200`) est aussi configurée dans l'interface Freebox pour que tous les équipements du LAN domestique puissent atteindre le cluster. --- ## nftables Géré par Ansible — rôle `gateway`, template `nftables.conf.j2`. **Ne jamais modifier manuellement** — les changements seront écrasés au prochain `ansible-playbook`. ```bash # Voir toutes les règles actives sudo nft list ruleset # Voir les paquets bloqués (logs kernel) sudo journalctl -k | grep nft-drop # Recharger après modification manuelle d'urgence sudo systemctl reload nftables # Appliquer via Ansible (méthode correcte) ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags gateway ``` ### Ports ouverts | Port | Proto | Source | Service | |---|---|---|---| | 22 | TCP | 192.168.1.0/24, 192.168.10.0/24 | SSH | | 53 | TCP/UDP | 192.168.10.0/24 | DNS (dnsmasq) | | 111, 2049 | TCP/UDP | 192.168.10.0/24 | NFS | | 5432 | TCP | 192.168.10.0/24 | PostgreSQL | | 6333, 6334 | TCP | 192.168.10.0/24 | Qdrant | | 8080 | TCP | 192.168.1.0/24, 192.168.10.0/24 | Hermes gateway | | 9000, 9001 | TCP | 192.168.10.0/24 | MinIO | | 9093 | TCP | 192.168.10.0/24 | AlertManager webhook (réception alertes Prometheus) | | 9100 | TCP | 192.168.10.0/24 | node_exporter (métriques Prometheus — inclut ROCm via textfile_collector) | | 9119 | TCP | 192.168.1.10 uniquement | Hermes dashboard | > **Règle nftables importante** : les règles doivent être insérées **avant** la règle `drop` terminale. > Utiliser `nft insert rule inet filter input position ` et non `nft add rule` > (qui ajoute en fin de chaîne, après le drop). > Vérifier l'ordre : `sudo nft -n -a list chain inet filter input` ### Forwarding ``` LAN domestique (192.168.1.0/24) → LAN cluster (192.168.10.0/24) : new+established (admin) LAN cluster → WAN : new+established (NAT sortant pour les nœuds) WAN → LAN cluster : established+related uniquement (réponses NAT) ``` --- ## IP Forwarding ```bash # Vérifier (doit être = 1) sysctl net.ipv4.ip_forward ``` --- ## DNS — /etc/hosts storage-01 ```bash cat /etc/hosts # 192.168.10.20 gpu-01 ← ajouté manuellement (dnsmasq non utilisé par storage-01 lui-même) ``` > storage-01 utilise 1.1.1.1 / 9.9.9.9 comme resolvers, pas son propre dnsmasq. > Les entrées critiques doivent être dans `/etc/hosts`. --- ## Debug NAT / forwarding ```bash # Depuis gpu-01 — vérifier que le trafic sort par storage-01 ssh gpu-01 "curl -s https://ifconfig.me" # doit retourner l'IP publique Freebox ssh gpu-01 "traceroute 8.8.8.8" # Paquets passant par le NAT sudo nft list table ip nat # Tester le routage depuis le poste perso traceroute 192.168.10.20 ping 192.168.10.11 # compute-01 ``` --- ## Commandes utiles ```bash # Table de routage storage-01 ip route show # Stats trafic interfaces ip -s link show enp4s0 ip -s link show enp6s0f3u2c2 # Connexions actives ss -tnp ``` --- ## Surveillance réseau active — blackbox_exporter Sondes **actives** (ICMP / HTTP / DNS) qui complètent les métriques *passives* du node_exporter. Elles répondent aux questions que `up{}` ne couvre pas : *« a-t-on internet ? »*, *« dnsmasq résout-il encore *.lab.local ? »*, *« quelle latence sur le LAN ? »*, *« le service répond-il de bout en bout via Traefik ? »*. ### Architecture ``` Prometheus (in-cluster) │ scrape /probe?target=…&module=… (jobs blackbox-icmp / -http / -dns) ▼ blackbox-exporter.monitoring.svc.cluster.local:9115 (ns monitoring) │ exécute la sonde réelle ├── ICMP → 192.168.10.1/.11/.12/.13/.20, 1.1.1.1, 9.9.9.9 ├── HTTP → http://.lab.local (DNS du pod = dnsmasq → Traefik) └── DNS → 192.168.10.1:53 (dns_lab : *.lab.local ; dns_external : forwarding) ``` | Élément | Emplacement | |---|---| | Déploiement (ArgoCD, chart Helm 11.13.0) | `k8s/apps-of-apps/apps/blackbox-exporter.yaml` | | Config blackbox (modules, ICMP, DNS du pod) | `k8s/infra/blackbox-exporter/values.yaml` | | Cibles + relabeling | `k8s/infra/monitoring/values.yaml` (jobs `blackbox-*`) | | Alertes | `k8s/infra/monitoring/alerts/alerts-network.yaml` | | Outil vocal Asa `network_status` + contexte `reseau` | `stt/server/stt_server/{tools,sources,contexts}.py` | > Le pod blackbox a `dnsPolicy: None` + `dnsConfig` pointant sur **dnsmasq (192.168.10.1)** > avec repli `1.1.1.1`. Conséquence : les sondes HTTP `*.lab.local` empruntent le **vrai** > chemin (DNS lab → Traefik), et une panne dnsmasq fait échouer les sondes lab mais **pas** > les sondes internet (qui retombent sur 1.1.1.1). ### Métriques clés (PromQL) ```promql probe_success{job=~"blackbox-.*"} # 1 = OK, 0 = échec probe_success{job="blackbox-icmp",scope="internet"} # accès internet (ancres) probe_success{job="blackbox-dns",module="dns_lab"} # dnsmasq résout *.lab.local ? probe_icmp_duration_seconds{scope="lan",phase="rtt"} # latence LAN (RTT) probe_http_status_code{job="blackbox-http"} # code HTTP renvoyé probe_duration_seconds{job="blackbox-http"} # temps de réponse service ``` ### Alertes (`alerts-network.yaml`) `InternetDown` (crit) · `DnsLabResolutionFailed` (crit) · `DnsForwardingFailed` (warn) · `GatewayUnreachable` (crit) · `ClusterHostUnreachable` (warn) · `ServiceEndpointDown` (warn) · `HighLanLatency` (warn) · `SlowServiceResponse` (warn) · `BlackboxExporterDown` (crit). Elles partent dans le même pipeline AlertManager → webhook Hermes + n8n → Gmail. ### Vérifications après déploiement ```bash # Le pod tourne ? kubectl get pods -n monitoring -l app.kubernetes.io/name=prometheus-blackbox-exporter # Cibles blackbox vues par Prometheus (doivent être UP, health=up) # prometheus.lab.local → Status → Targets → blackbox-icmp / -http / -dns # Tester une sonde à la main depuis un pod du cluster kubectl run -n monitoring bb-test --rm -it --image=curlimages/curl --restart=Never -- \ 'curl -s "http://blackbox-exporter:9115/probe?target=1.1.1.1&module=icmp" | grep probe_success' ``` ### Caveats / points de vigilance - **ICMP** nécessite la capability `NET_RAW` (activée dans `values.yaml`) — possible car la ns `monitoring` est en PodSecurity **privileged**. - **Pare-feu hôtes** : le ping vers `192.168.10.1` (storage-01) passe (la règle gateway accepte le LAN cluster), mais **gpu-01 / compute** peuvent **dropper l'ICMP** selon leur firewall hôte. Si `ClusterHostUnreachable` se déclenche alors que l'hôte est vivant, vérifier qu'il accepte l'echo-request depuis `192.168.10.0/24` (côté flannel, le trafic pod sort masqué en IP de nœud). - **Sondes HTTP** : un service derrière auth ou qui renvoie 3xx non suivi sortira en échec — ajuster le module (`valid_status_codes`) ou retirer la cible dans `monitoring/values.yaml`. - **Ajouter une cible** = éditer la liste `targets` du job concerné dans `k8s/infra/monitoring/values.yaml`, puis `git push` (ArgoCD resync ~3 min).