Proxy Squid HA

Concepts : proxy forward et filtrage Layer 7

Un proxy forward (ou proxy direct) est un intermediaire entre les clients du reseau interne et Internet. Contrairement a un reverse proxy (qui protege les serveurs), le forward proxy protege les clients en controlant et filtrant leur acces sortant.

HTTP vs HTTPS a travers un proxy

  • HTTP : le proxy recoit la requete en clair, peut inspecter l'URL complete, mettre en cache la reponse et filtrer le contenu.
  • HTTPS : le client envoie une requete HTTP CONNECT domaine:443. Le proxy cree un tunnel TCP sans voir le contenu chiffre. Le filtrage se fait uniquement sur le nom de domaine (SNI), pas sur l'URL ou le contenu.

Mise en cache

Squid peut stocker localement les reponses HTTP pour les servir plus rapidement lors des requetes suivantes. Pour HTTPS (tunnel CONNECT), la mise en cache n'est pas possible car le contenu est chiffre de bout en bout.

graph LR
    subgraph "Requete HTTP"
        C1["Client"] -->|"GET http://..."| P1["Proxy<br/>(voit tout)"]
        P1 -->|"Forward"| S1["Serveur"]
    end

    subgraph "Requete HTTPS"
        C2["Client"] -->|"CONNECT domaine:443"| P2["Proxy<br/>(tunnel opaque)"]
        P2 -->|"Tunnel TCP"| S2["Serveur"]
    end

Pourquoi Squid et non le proxy Fortigate ?

Le Fortigate VM64 integre un proxy explicite natif sur le port 8080. En conditions normales, ce proxy gere HTTP et HTTPS. Cependant, notre Fortigate de lab n'a pas la licence FortiGuard enregistree :

Fonctionnalite Fortigate (sans licence) Squid
Proxy HTTP Fonctionne Fonctionne
Proxy HTTPS (CONNECT) KO -- Bloque Fonctionne (tunnel)
Filtrage par domaine FQDN policies (L3/L4) ACL dstdomain (L7)
Haute disponibilite HA native Keepalived (VRRP)
Cout de licence FortiGuard requis Gratuit (open source)

Decision d'architecture

Le proxy Squid a ete deploye specifiquement pour contourner la limitation HTTPS du proxy Fortigate non licence. Il fournit un filtrage Layer 7 complementaire aux policies FQDN Layer 3/4 du Fortigate, creant un double filtrage.


Architecture du cluster Squid HA

graph TB
    subgraph CLIENTS["Toutes les VMs de l'infrastructure"]
        VM1["VM Services"]
        VM2["VM SOC"]
        VM3["VM Supervision"]
        VMN["..."]
    end

    subgraph DMZ["VLAN Proxy — 10.15.50.0/29"]
        SQUID1["Squid 1<br/>10.15.50.1<br/>MASTER (priority 100)"]
        SQUID2["Squid 2<br/>10.15.50.2<br/>BACKUP (priority 90)"]
        VIP["VIP Keepalived<br/>10.15.50.3:3128<br/>VRID 50"]
        SQUID1 --- VIP
        SQUID2 --- VIP
    end

    subgraph FW["Fortigate"]
        P47["Policy 47<br/>NAT + FQDN groups"]
    end

    VM1 -->|"port 3128"| VIP
    VM2 -->|"port 3128"| VIP
    VM3 -->|"port 3128"| VIP
    VMN -->|"port 3128"| VIP
    VIP --> P47
    P47 --> NET["Internet<br/>(domaines autorises)"]

    style VIP fill:#e67e22,color:#fff
    style SQUID1 fill:#27ae60,color:#fff
    style SQUID2 fill:#3498db,color:#fff
Parametre Valeur
Squid 1 (MASTER) 10.15.50.1, priority 100
Squid 2 (BACKUP) 10.15.50.2, priority 90
VIP Keepalived 10.15.50.3:3128
VRID 50
Temps de failover ~4 secondes
Version Squid 5.5
Systeme Rocky Linux 9.6
Config identique /etc/squid/squid.conf sur les deux noeuds
NTP 10.15.100.72, 10.15.100.73 (chrony)
DNS 10.15.100.225, 10.15.100.226 (FreeIPA)

Keepalived et VRRP

Qu'est-ce que VRRP ?

Le protocole VRRP (Virtual Router Redundancy Protocol, RFC 5798) permet a plusieurs serveurs de partager une adresse IP virtuelle (VIP). Un seul serveur est MASTER a la fois et repond au trafic. Si le MASTER tombe, le BACKUP prend le relais automatiquement.

Le basculement se fait par gratuitous ARP : le nouveau MASTER envoie une trame ARP non sollicitee pour annoncer que la VIP est maintenant associee a sa propre adresse MAC. Les switches et routeurs mettent a jour leur table ARP immediatement.

Configuration keepalived

sequenceDiagram
    participant S1 as Squid 1 (MASTER)
    participant S2 as Squid 2 (BACKUP)
    participant VIP as VIP 10.15.50.3

    Note over S1,S2: Fonctionnement normal
    S1->>S2: VRRP Advertisement (chaque seconde)
    S1-->>VIP: Trafic gere par MASTER

    Note over S1: Squid crash !
    S1->>S1: Health check echoue (fall=2)
    S1->>S1: Priority 100-30 = 70 < 90
    S2->>VIP: Gratuitous ARP
    Note over S2: Devient MASTER (~4s)
    S2-->>VIP: Trafic gere par nouveau MASTER
Parametre keepalived Valeur
Health check Script : pgrep squid
Utilisateur du script keepalived_script
Intervalle du check 2 secondes
Fall (echecs avant action) 2 echecs consecutifs
Weight (penalite sur echec) -30 (priority MASTER passe de 100 a 70, inferieur au BACKUP a 90)

Pourquoi fall=2 et weight=-30 ?

fall=2 evite les faux positifs (un seul echec ne declenche pas le basculement). weight=-30 fait passer la priority du MASTER (100-30=70) en dessous de celle du BACKUP (90), provoquant l'election d'un nouveau MASTER.


Double filtrage : Squid + Fortigate

Le trafic sortant est filtre a deux niveaux independants :

Niveau Composant Couche Mecanisme Granularite
1 Squid Layer 7 (applicatif) ACL dstdomain Nom de domaine exact ou wildcard
2 Fortigate Layer 3/4 (reseau) FQDN Address Groups Resolution DNS → IP
graph LR
    VM["VM<br/>(http_proxy)"] -->|"TCP 3128"| SQUID["Squid<br/>ACL dstdomain<br/>(Layer 7)"]
    SQUID -->|"HTTP/HTTPS"| FGT["Fortigate<br/>FQDN groups<br/>(Layer 3/4)"]
    FGT -->|"NAT"| NET["Internet"]

    SQUID -.->|"403 Forbidden"| VM
    FGT -.->|"Drop + Log"| SQUID

    style SQUID fill:#e67e22,color:#fff
    style FGT fill:#e74c3c,color:#fff

Les deux filtres doivent autoriser le domaine

Un domaine doit etre present dans la whitelist Squid ET dans un FQDN group Fortigate pour que le trafic passe. Un oubli sur l'un des deux bloquera la connexion.


Whitelist complete des domaines (ACL Squid)

Repos et packages (11 domaines)

Domaine Usage
.rockylinux.org Depots Rocky Linux 9
.fedoraproject.org EPEL
download.docker.com Docker CE
.elastic.co Elasticsearch, Kibana, Logstash
packages.wazuh.com Wazuh
.releases.hashicorp.com Vault, Terraform, Packer
repo.zabbix.com Zabbix
packages.gitlab.com GitLab CE
registry.npmjs.org npm
pypi.org Python Package Index
files.pythonhosted.org Telechargement packages Python

Docker registries (7 domaines)

Domaine Usage
registry-1.docker.io Docker Hub (pull images)
auth.docker.io Docker Hub (authentification token)
production.cloudflare.docker.com Docker Hub (CDN Cloudflare)
ghcr.io GitHub Container Registry
quay.io Red Hat Quay
.github.com GitHub (releases, archives tar.gz)
.githubusercontent.com GitHub (contenu raw, assets binaires)

Threat Intelligence (6 domaines)

Domaine Usage
.abuse.ch URLhaus, MalwareBazaar, Feodo Tracker, ThreatFox
api.abuseipdb.com API AbuseIPDB (reputation IP)
otx.alienvault.com AlienVault OTX (IOC feeds pulse)
.virustotal.com VirusTotal (analyse fichiers, URLs, hashes)
.circl.lu CIRCL Luxembourg (feeds MISP, hashlookup)
botvrij.eu IOC feeds Botvrij (IP/domaines malveillants)

Cloud et identite (8 domaines)

Domaine Usage
.microsoftonline.com Entra ID (authentification, tokens)
.microsoft.com Graph API, portail Azure
.windows.net Azure (blob storage, vault, monitor)
.msftauth.net Entra ID (MFA, authenticator)
.amazonaws.com AWS (S3, STS, IAM, EC2, SSM)
.azure.com Azure (management, portal)
.azure.net Azure (services internes)
aadcdn.msftauth.net Entra ID (CDN assets statiques)

Domaines internes

Domaine Usage
.infra.indio Tous les services internes (GitLab, Nexus, Vault, etc.)

Configuration Squid expliquee

Les directives cles du fichier /etc/squid/squid.conf :

Directive Role Valeur
http_port Port d'ecoute du proxy 3128
acl whitelist dstdomain Liste de domaines autorises Tous les domaines ci-dessus
http_access allow whitelist Autorise les domaines de l'ACL Avant le deny
http_access deny all Bloque tout le reste Derniere regle
access_log Log de toutes les requetes /var/log/squid/access.log
cache_dir Stockage du cache ufs /var/spool/squid 10000 16 256

Identique sur les deux noeuds

Le fichier squid.conf est strictement identique sur Squid 1 et Squid 2. La configuration est deploye via Ansible pour garantir la coherence.


Integration Ansible

Toutes les VMs de l'infrastructure utilisent le proxy via les variables definies dans group_vars/all.yml :

# group_vars/all.yml
fortigate_proxy: "http://10.15.50.3:3128"
fortigate_no_proxy: "localhost,127.0.0.1,10.15.80.*,10.15.100.*,10.15.50.*,repo.infra.indio,gitlab.infra.indio,*.infra.indio"
Variable Role
fortigate_proxy URL du proxy pour HTTP et HTTPS (VIP Squid)
fortigate_no_proxy Adresses qui ne passent pas par le proxy (services internes, Nexus, GitLab)

Le role common injecte ces variables dans /etc/environment et dans la configuration de dnf/yum pour que tous les outils systeme utilisent le proxy automatiquement.


Procedure : ajouter un nouveau domaine

Etape 1 -- Modifier la whitelist Squid

Sur les deux serveurs Squid (ou via le playbook Ansible) :

  1. Editer /etc/squid/squid.conf
  2. Ajouter le domaine dans l'ACL dstdomain (ex: .nouveau-domaine.com)
  3. Recharger la configuration : systemctl reload squid

Etape 2 -- Ajouter le FQDN au Fortigate

  1. Creer un objet Address de type FQDN sur le Fortigate
  2. Ajouter l'objet au Address Group correspondant (ex: GRP-Repos-Publiques)

Etape 3 -- Tester l'acces

# Depuis une VM concernee
curl -x http://10.15.50.3:3128 -v https://nouveau-domaine.com

Ne pas oublier l'un des deux niveaux

Le domaine doit etre ajoute aux deux niveaux (Squid + Fortigate). Sinon le trafic sera bloque par l'un ou l'autre filtre.