Rôle
Proxy HTTPS transparent pour le VLAN IoT et proxy explicite pour les hôtes internes. Tout le trafic HTTP/HTTPS des objets connectés passe par cette stack pour inspection et analyse antivirus en temps réel.
Architecture
Trois containers Podman sur VyOS, issus d'un seul dépôt GitHub :
| Container | Image | Version | Taille |
|---|---|---|---|
| squid | squid-hardened | 7.5 | ~25 MB |
| c-icap | c-icap-hardened | 0.6.4 | ~18 MB |
| clamav | clamav-hardened | 1.4.2 | ~22 MB |
Total combiné : ~65 MB pour une stack proxy complète avec antivirus. Les trois images sont FROM scratch (tier Platine) avec un init binaire Go dédié.
Mode transparent : PBR + nft REDIRECT
Le trafic du VLAN IoT est intercepté via Policy Based Routing (table 100). Les règles PBR redirigent les paquets HTTP/443 vers le container Squid sans configuration côté client :
- PBR marque le trafic IoT sortant
- La table de routage 100 dirige vers le namespace réseau Squid
- Un service systemd (
squid-redirect.service) injecte les règles nft REDIRECT dans le netns du container :- Port 80 → 3129 (HTTP intercept)
- Port 443 → 3131 (HTTPS intercept SSL Bump)
SSL Bump : peek + splice
Sur le port 3131, Squid utilise la stratégie peek+splice pour l'interception HTTPS :
- Peek : lecture du SNI (Server Name Indication) dans le ClientHello TLS sans déchiffrement
- Splice : tunnel TCP direct vers le serveur destination après inspection du SNI
Cette approche permet le filtrage par domaine et l'inspection ICAP sans générer de certificats dynamiques (pas de MITM complet).
ICAP : pont vers ClamAV
c-icap reçoit les requêtes/réponses de Squid via le protocole ICAP (Internet Content Adaptation Protocol) et les transmet à ClamAV pour analyse antivirus :
- Mode RESPMOD : analyse le corps des réponses HTTP
- Seuil de taille configurable (fichiers > 25 MB ignorés)
- Verdict : si ClamAV détecte un malware, c-icap retourne un bloc ICAP → Squid renvoie une page d'erreur au client
Flux de requête
flowchart LR
Client["Client IoT"] -->|"PBR table 100"| NFT["nft REDIRECT"]
NFT -->|"port 3129/3131"| Squid["Squid<br/>peek+splice"]
Squid -->|"ICAP REQMOD"| CICAP["c-icap"]
CICAP -->|"clamd protocol"| ClamAV["ClamAV<br/>scan"]
ClamAV -->|"clean"| CICAP
CICAP -->|"200 OK"| Squid
Squid --> Destination["Destination"]
ClamAV -->|"infected"| Block["Bloque"]
Init Go et healthchecks
Chaque container possède un binaire init Go compilé statiquement qui assure :
- PID file : écriture du PID du processus principal pour supervision
- Signal 0 healthcheck : vérification que le processus est vivant (kill -0)
- Séquence de démarrage ordonnée : attente des dépendances avant lancement
ClamAV : freshclam avant clamd
L'init Go de ClamAV exécute freshclam (mise à jour des signatures) avant de démarrer clamd. Cela garantit que les définitions virales sont à jour dès le premier scan.
c-icap : attente de clamd
L'init Go de c-icap attend que clamd soit joignable en TCP avant de démarrer le service :
- 120 tentatives de connexion TCP
- Intervalle de 1 seconde entre chaque tentative
- Échec fatal si clamd n'est pas prêt après 2 minutes
Configuration Squid notable
negative_dns_ttl 1 seconds: évite de cacher les résolutions DNS échouées trop longtempshost_verify_strict: contrôle la vérification de cohérence entre le SNI et l'IP résolue. Désactivé en mode transparent car les CDN utilisent du round-robin DNSdns_nameservers: pointe vers le cache DNS local (BIND9) pour cohérence avec les résolutions client
Gotcha : cohérence DNS
Squid et les clients doivent résoudre via le même cache DNS (BIND9). Deux caches différents = IPs différentes pour les CDN en round-robin = échec de la vérification host = erreur 409.
Le symptôme typique : Docker pull échoue avec http: server gave HTTP response to HTTPS client car Squid répond en HTTP quand la vérification host échoue.
Solution : s'assurer que le container Squid résout via BIND9 (même instance que les clients) grâce aux règles DNAT du firewall.
Liens
- Code source : squid-hardened
- Image Docker : Docker Hub
Laisser un commentaire