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) :
- Editer
/etc/squid/squid.conf - Ajouter le domaine dans l'ACL
dstdomain(ex:.nouveau-domaine.com) - Recharger la configuration :
systemctl reload squid
Etape 2 -- Ajouter le FQDN au Fortigate¶
- Creer un objet Address de type FQDN sur le Fortigate
- Ajouter l'objet au Address Group correspondant (ex:
GRP-Repos-Publiques)
Etape 3 -- Tester l'acces¶
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.