remove history
This commit is contained in:
commit
f92c9f0a1a
78 files changed
+3262
No files matched your search
@@ -0,0 +1,397 @@
|
||||
# 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) :
|
||||
|
||||
1. Clé d'accès Gitea existante (`svc-semaphore`, type « Login with password »).
|
||||
2. Dépôt : `https://gitea.tips-of-mine.com/Tips-Of-Mine/ansible-squid.git`,
|
||||
branche `main`.
|
||||
3. Inventaire de type `file` pointant sur `inventory/hosts.yml`, avec la clé
|
||||
SSH du compte `ansible`.
|
||||
4. 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`.
|
||||
5. Modèle `Déploiement Squid` sur `site.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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
avec `openssl 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 dans `ps`.
|
||||
- `examples/auth-kerberos.yml` — SSO domaine. Contient les commandes
|
||||
`setspn` et `ktpass` à 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 :
|
||||
|
||||
```bash
|
||||
# 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 Via` au démarrage : conséquence directe
|
||||
de `via off`, choisi pour ne pas annoncer le proxy aux serveurs distants.
|
||||
- `logfile_rotate 0` : la rotation est confiée à logrotate, qui appelle
|
||||
`squid -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) :
|
||||
|
||||
1. `yamllint` sur tout le dépôt ;
|
||||
2. `ansible-lint` en profil **production** ;
|
||||
3. `ansible-playbook --syntax-check` ;
|
||||
4. rendu des six scénarios de `tests/scenarios/` puis validation de chaque
|
||||
`squid.conf` par `squid -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 avec
|
||||
`git update-index --chmod=+x scripts/openbao-env.sh scripts/trigger-semaphore.sh`.
|
||||
Le workflow applique de toute façon un `chmod +x` avant appel.
|
||||
- **Fins de ligne** : `.gitattributes` force le LF sur les `.yml`, `.j2`,
|
||||
`.sh` et `.cfg`.
|
||||
- **Première exécution avec SSL Bump** : l'installation de `squid-openssl`
|
||||
remplace le paquet `squid` et 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.
|
||||
|
||||
```yaml
|
||||
# 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]
|
||||
```
|
||||
|
||||
```yaml
|
||||
# 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 :
|
||||
|
||||
1. `squid_allow_localnet` bascule **automatiquement à false** dès qu'une
|
||||
fiche existe : plus aucune autorisation globale par réseau.
|
||||
2. Le rôle refuse de déployer si un membre de groupe n'a pas de fiche
|
||||
serveur correspondante.
|
||||
3. `http_access deny all` clô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
|
||||
|
||||
```bash
|
||||
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_prod` et
|
||||
`srv-warda-02_prod` désignent la même ACL.
|
||||
- Une ACL référencée sans être définie est **fatale**, pas un avertissement.
|
||||
- `dns_v4_first` est **obsolète** depuis Squid 6 et génère une erreur au
|
||||
démarrage : `squid_dns_v4_first` est donc à `false` par 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 :
|
||||
|
||||
```yaml
|
||||
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 `language` n'existe plus et provoque `Unknown option language`.
|
||||
Elle a été retirée du gabarit ; `charset` suffit.
|
||||
- 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_type` fait 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 :
|
||||
|
||||
```yaml
|
||||
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.
|
||||
|
||||
Reference in new issue
Block a user