ansible-squid
Déploiement d'un proxy web Squid sur Debian, piloté depuis Semaphore et déclenché par Gitea Actions.
Le rôle couvre les ACL réseau, le filtrage de domaines, les quatre méthodes d'authentification (aucune, basic, LDAP/AD, Kerberos), le mode explicite et l'interception transparente, et le déchiffrement TLS (SSL Bump).
1. Contraintes assumées
| Contrainte | Conséquence dans le dépôt |
|---|---|
Le conteneur semaphore-app n'embarque aucune collection Ansible |
Le rôle n'utilise que ansible.builtin. Pas de requirements.yml, rien à installer. |
Le paquet Debian squid n'est pas compilé avec OpenSSL |
Quand squid_ssl_bump vaut true, le rôle installe squid-openssl à la place. APT remplace l'un par l'autre. |
| Une configuration Squid invalide casse le service | squid.conf est déployé avec validate: squid -k parse, et la CI rejoue ce contrôle sur six scénarios avant tout déploiement. |
| Un port intercepté ne peut pas porter d'authentification | Les ports interceptés sont nommés et exemptés automatiquement (ACL myportname). Le contrôle y reste basé sur l'adresse source. |
2. Arborescence
ansible.cfg configuration Ansible (callback default + result_format yaml)
site.yml playbook unique, groupe « squid »
inventory/hosts.yml inventaire d'exemple
group_vars/all/main.yml variables communes
group_vars/squid/main.yml paramétrage du proxy
group_vars/squid/vault.yml.example secrets à chiffrer (ou à mettre dans Semaphore)
examples/auth-*.yml un exemple complet par méthode d'authentification
roles/squid/
defaults/main.yml toutes les variables surchargeables
vars/main.yml chemins des helpers Debian, raccourcis calculés
tasks/assert.yml validation des variables avant toute action
tasks/install.yml paquets, répertoires, sauvegarde de la conf d'origine
tasks/ssl_bump.yml autorité de certification et base de certificats générés
tasks/auth.yml fichiers de la méthode retenue, nettoyage des autres
tasks/configure.yml listes de filtrage puis squid.conf (avec validation)
tasks/service.yml cache éventuel, activation, flush des handlers
tasks/verify.yml ports, syntaxe, requête de bout en bout
templates/squid.conf.j2 gabarit principal
templates/auth/*.j2 un fragment par méthode
templates/lists/domains.txt.j2
tests/ rendu hors ligne et scénarios utilisés par la CI
scripts/openbao-env.sh lecture des secrets Semaphore dans OpenBao
scripts/trigger-semaphore.sh déclenchement et suivi de la tâche Semaphore
.gitea/workflows/lint.yml qualité + validation de la configuration générée
.gitea/workflows/deploy.yml déploiement via Semaphore
3. Prérequis
Sur la cible : Debian 12 ou 13, accès SSH avec un compte disposant de
sudo, sortie Internet.
Côté Semaphore (projet Production, celui déjà utilisé pour Centreon) :
- Clé d'accès Gitea existante (
svc-semaphore, type « Login with password »). - Dépôt :
https://gitea.tips-of-mine.com/Tips-Of-Mine/ansible-squid.git, branchemain. - Inventaire de type
filepointant surinventory/hosts.yml, avec la clé SSH du compteansible. - Groupe de variables (menu Variable Groups depuis la 2.19) nommé
Squid, pour les secrets :squid_ldap_bind_password,squid_kerberos_keytab_b64,squid_ssl_ca_key_content. - Modèle
Déploiement Squidsursite.yml.
Côté Gitea : trois secrets de dépôt seulement — OPENBAO_ADDR,
OPENBAO_ROLE_ID, OPENBAO_SECRET_ID. Tout le reste vit dans OpenBao sous
secret/squid : semaphore_url, semaphore_token, semaphore_project_id,
semaphore_template_id.
4. Démarrage rapide
# 1. Renseigner l'inventaire
$EDITOR inventory/hosts.yml
# 2. Ajuster le paramétrage
$EDITOR group_vars/squid/main.yml
# 3. Déployer
ansible-playbook site.yml
Depuis Semaphore, lancer le modèle Déploiement Squid. Depuis Gitea,
onglet Actions → Déploiement Squid → Run workflow, avec au besoin
un --limit, des étiquettes (install, ssl, auth, config, service,
verify) ou le mode simulation.
5. Variables principales
| Variable | Défaut | Rôle |
|---|---|---|
squid_mode |
both |
explicit, intercept ou les deux |
squid_http_port |
3128 |
port du proxy explicite |
squid_intercept_http_port |
3129 |
port d'interception HTTP |
squid_intercept_https_port |
3130 |
port d'interception HTTPS (SSL Bump) |
squid_allowed_networks |
10.0.4.0/24 |
réseaux autorisés |
squid_denied_sources |
[] |
adresses refusées avant toute autre règle |
squid_filter_mode |
blocklist |
blocklist ou allowlist |
squid_denied_domains |
[] |
domaines interdits |
squid_allowed_domains |
[] |
domaines autorisés (obligatoire en allowlist) |
squid_auth_method |
none |
none, basic, ldap, kerberos |
squid_ssl_bump |
false |
déchiffrement TLS |
squid_no_bump_domains |
3 entrées | domaines relayés sans déchiffrement |
squid_cache_enabled |
false |
cache disque |
squid_log_to_syslog |
false |
journalisation vers syslog plutôt qu'en fichier |
squid_verify |
true |
contrôles de fin de déploiement |
La liste exhaustive et commentée est dans roles/squid/defaults/main.yml.
Un point de vigilance : en mode allowlist, tout ce qui n'est pas dans
squid_allowed_domains est refusé, y compris les domaines de mise à jour du
système. Le rôle refuse d'ailleurs de partir si la liste est vide.
6. Les quatre authentifications
Chaque méthode dispose d'un exemple prêt à copier dans group_vars/squid/ :
examples/auth-none.yml— contrôle par adresse source uniquement. Seule méthode compatible avec l'interception.examples/auth-basic.yml— comptes locaux. Les condensats se génèrent avecopenssl passwd -apr1(saisie interactive, rien dans l'historique).examples/auth-ldap.yml— annuaire AD, avec restriction optionnelle par groupe. Le mot de passe du compte de service est lu dans un fichier (-W) et n'apparaît jamais dansps.examples/auth-kerberos.yml— SSO domaine. Contient les commandessetspnetktpassà passer côté contrôleur de domaine, et l'encodage du keytab en base64.
Changer de méthode suffit : tasks/auth.yml supprime les fichiers de celles
qui ne sont plus retenues.
7. SSL Bump
Par défaut le rôle génère une autorité auto-signée
(squid_ssl_ca_self_signed: true). En production, fournir plutôt une
autorité issue de ta PKI via squid_ssl_ca_cert_content et
squid_ssl_ca_key_content, alimentées par Semaphore ou OpenBao.
Le certificat public est déposé sur la cible dans
/usr/local/share/ca-certificates/squid-proxy-ca.crt. Il doit être
distribué à tous les postes clients, sinon chaque site HTTPS produira une
erreur de certificat. Sur un parc AD, une GPO « Autorités de certification
racines de confiance » fait l'affaire.
Les domaines de squid_no_bump_domains sont relayés sans déchiffrement
(ssl_bump splice) : à alimenter avec la banque, la santé, les impôts, et
tout ce qui pratique l'épinglage de certificat. Les domaines interdits sont
coupés dès le SNI (ssl_bump terminate), avant même le déchiffrement.
8. Mode interception
Le rôle configure Squid ; la redirection du trafic reste à faire sur le firewall. Sur OPNsense, deux règles de NAT de type port forward depuis le réseau client :
| Protocole | Port source | Destination | Redirection |
|---|---|---|---|
| TCP | 80 | toute | IP_du_proxy:3129 |
| TCP | 443 | toute | IP_du_proxy:3130 |
Le proxy lui-même doit être exclu de ces règles, faute de quoi le trafic sortant de Squid revient sur Squid.
Pour le mode explicite, le plus simple reste un fichier PAC distribué par
GPO, ou la variable d'environnement http_proxy sur les serveurs Linux.
9. Vérifications
Le rôle termine par une série de contrôles (squid_verify) : ouverture des
ports, squid -k parse sur la configuration en place, et une requête réelle
à travers le proxy quand l'authentification le permet.
À la main, sur la cible :
# Version et syntaxe
squid -k parse >/dev/null && echo "configuration valide"
# Test explicite
curl -sS -o /dev/null -w '%{http_code}\n' -x http://127.0.0.1:3128 http://www.debian.org/
# Test d'un domaine interdit (403 attendu)
curl -sS -o /dev/null -w '%{http_code}\n' -x http://127.0.0.1:3128 http://doubleclick.net/
# Dix dernières lignes du journal, sans le détail des requêtes internes
tail -n 10 /var/log/squid/access.log
Deux comportements normaux à ne pas chercher à corriger :
WARNING: HTTP requires the use of Viaau démarrage : conséquence directe devia off, choisi pour ne pas annoncer le proxy aux serveurs distants.logfile_rotate 0: la rotation est confiée à logrotate, qui appellesquid -k rotate. Le fichier/etc/squid/conf.d/n'est volontairement pas inclus, la configuration est entièrement pilotée par le rôle.
10. Intégration continue
lint.yml (à chaque push et chaque PR) :
yamllintsur tout le dépôt ;ansible-linten profil production ;ansible-playbook --syntax-check;- rendu des six scénarios de
tests/scenarios/puis validation de chaquesquid.confparsquid -k parse, avec un vrai Squid installé dans le job. C'est ce contrôle qui a détecté, avant livraison, une inclusion de gabarit qui collait deux directives sur la même ligne.
deploy.yml (push sur main touchant le code Ansible, ou lancement
manuel) : lecture des secrets dans OpenBao par AppRole, déclenchement du
modèle Semaphore, puis attente du résultat. Le job échoue si la tâche
Semaphore échoue.
Les jetons ne sont jamais affichés : openbao-env.sh les masque
(::add-mask::) et n'écrit que l'URL Semaphore visée.
11. Pièges connus
- Bit d'exécution des scripts : si les fichiers de
scripts/arrivent sans droit d'exécution depuis Windows, corriger une fois pour toutes avecgit update-index --chmod=+x scripts/openbao-env.sh scripts/trigger-semaphore.sh. Le workflow applique de toute façon unchmod +xavant appel. - Fins de ligne :
.gitattributesforce le LF sur les.yml,.j2,.shet.cfg. - Première exécution avec SSL Bump : l'installation de
squid-opensslremplace le paquetsquidet redémarre le service. Prévoir une courte coupure si le proxy est déjà en production.
12. Modèle par serveur (fragments conf.d)
Chaque machine autorisée possède une fiche dans servers/, chaque
regroupement une fiche dans groups/. Le rôle en dérive un fichier par
entité dans /etc/squid/conf.d/, chargé par le socle avant le
http_access deny all final.
# servers/srv-warda-01.yml
name: srv-warda-01
env: prod
sources:
- srv-warda-01.tips-of-mine.local
groups: [windows] # documentaire : l'appartenance fait foi côté groupe
rules:
- domains: [javadl.oracle.com, www.java.com]
ports: [https]
# groups/windows.yml
name: windows
members: # seules ces machines bénéficient du groupe
- srv-warda-01.tips-of-mine.local
rules:
- domains: [download.windowsupdate.com]
ports: [http, https]
Fichiers produits : 00-ports.conf (catalogue de ports partagé),
10-groupe-<nom>.conf, 20-<serveur>.conf.
Garantie de non-accès
Une machine n'obtient un flux que si son FQDN figure explicitement dans une
ACL src. Trois mécanismes la protègent :
squid_allow_localnetbascule automatiquement à false dès qu'une fiche existe : plus aucune autorisation globale par réseau.- Le rôle refuse de déployer si un membre de groupe n'a pas de fiche serveur correspondante.
http_access deny allclôt le socle, après l'include.
Nommage des ACL de destination
Le nom est dérivé du domaine lui-même : go.microsoft.com devient
go_microsoft_com, .datadoghq.com devient _datadoghq_com. Même domaine
= toujours le même nom et la même valeur, donc deux fiches ne peuvent pas
définir la même ACL avec des contenus différents. C'est ce qui se produit
aujourd'hui entre plusieurs fragments écrits à la main.
Ports
Le catalogue vit dans squid_port_acls et n'est rendu qu'une fois, dans
00-ports.conf. Les fiches ne référencent que des clés (https, sftp,
8443…) ; une clé absente du catalogue fait échouer le déploiement avec la
liste des ports fautifs.
Reprise de l'existant
python3 scripts/import-conf-d.py /etc/squid/conf.d --sortie servers/
Le script produit une fiche par fragment et un rapport d'anomalies. Passé
sur les cinq fichiers de production fournis, il a relevé : une ACL
référencée mais jamais définie (Squid refuse de démarrer dans ce cas), un
domaine terminé par /, une adresse IP en dstdomain, une ligne tronquée
et plusieurs ACL déclarées deux fois. --rapport-seul fait l'audit sans
rien écrire.
Points vérifiés sur Squid 6.14
- Les noms d'ACL sont insensibles à la casse :
srv-warda-02_prodetsrv-warda-02_proddésignent la même ACL. - Une ACL référencée sans être définie est fatale, pas un avertissement.
dns_v4_firstest obsolète depuis Squid 6 et génère une erreur au démarrage :squid_dns_v4_firstest donc àfalsepar défaut.acl <nom> src <fqdn>impose une résolution DNS au démarrage. Si un nom ne résout plus, Squid refuse de démarrer. Des sources en adresses IP suppriment cette dépendance.
13. Rapports d'utilisation (SARG)
Désactivé par défaut. Activation :
squid_reports_enabled: true
Le rôle installe sarg depuis les dépôts Debian, génère /etc/sarg/sarg.conf,
un script /usr/local/sbin/sarg-rapport.sh et les entrées /etc/cron.d/
correspondantes, puis publie les rapports par un nginx local.
Périodes et consultation
Trois périodes, réglables par squid_sarg_periods : daily (la veille),
weekly (7 jours glissants), monthly (mois précédent). Les rapports
atterrissent dans /var/www/sarg/{quotidien,hebdomadaire,mensuel} et sont
consultables sur le port 8081, restreint aux réseaux de
squid_sarg_web_allowed — par défaut les mêmes que squid_allowed_networks.
Aucune exposition publique, pas d'indexation, pas de cache navigateur.
Le script passe à SARG le journal courant et access.log.1 s'il existe,
pour couvrir une rotation intervenue entre-temps.
Contenu des rapports
topusers, topsites, sites_users, users_sites, denied et
auth_failures. Sans authentification, records_without_userid: ip rattache
chaque ligne à l'adresse source ; avec LDAP ou Kerberos, les rapports sont
nominatifs.
Le rapport denied est le plus utile au quotidien : il liste les tentatives
refusées, donc les machines qui cherchent à sortir sans y être autorisées.
Points vérifiés sur SARG 2.4.0
- La directive
languagen'existe plus et provoqueUnknown option language. Elle a été retirée du gabarit ;charsetsuffit. - Le type de rapport
date_timeéchoue à créer le répertoire de son graphique (Cannot open .../graph.html). Il est volontairement absent des valeurs par défaut. L'ajouter àsquid_sarg_report_typefait réapparaître l'erreur. - SARG ne crée pas les sous-répertoires de période : le rôle s'en charge.
Vie privée
Avec le SSL Bump actif, les rapports contiennent les URL complètes, pas seulement les noms de domaine. Deux leviers :
squid_sarg_privacy: true # masque les URL, conserve les agrégats
squid_sarg_exclude_hosts: # domaines absents des rapports
- .ameli.fr
squid_sarg_exclude_users: []
squid_sarg_keep: 90 # nombre de rapports conservés par période
En entreprise, un rapport nominatif d'historique de navigation relève du suivi individuel : information des personnes, inscription au registre des traitements et durée de conservation définie sont à cadrer avant la mise en service.