audit : la piste sort de la machine auditee, et quelqu un regarde
auditd tournait, onze regles etaient armees, et rien de tout cela ne servait a grand-chose. Quatre manques, mesures avant d etre combles. 1. Rien ne sortait. Alloy ne contenait aucune reference a l audit et les cinq greffons etaient inactifs. Il lit maintenant audit.log et le pousse vers Loki — sans toucher une permission, alloy etant deja dans le groupe adm. On ecarte le greffon syslog : journald limite le debit, et une rafale d evenements est exactement le moment qui compte. 2. Aucune sonde. Elle mesure la COLLECTE, pas l armement : le nombre de regles est precisement le chiffre qui restait bon pendant la panne du 2026-08-30. Il part en perfdata, jamais en verdict. 3. Retention non declaree. Mesuree a 4,6 Mo/jour au repos ; portee de 40 a 128 Mo. Depuis (1), le local n est plus l archive mais un tampon. 4. Les regles ignoraient la cle privee de l hote. -w /etc/step/ partout, et -w /etc/step-ca/ sur la seule autorite : auditctl refuse un watch vers un chemin absent et fait echouer le chargement entier. Verifie sur l autorite seule d abord, puis 14/14 : regles armees, auditd actif, sonde a 0, et les quatorze hotes presents dans Loki sous job=audit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
This commit is contained in:
parent
1b89e83b0c
commit
5f5af70a9c
13 changed files with 331 additions and 8 deletions
73
CHANGELOG.md
73
CHANGELOG.md
|
|
@ -1,5 +1,78 @@
|
|||
# CHANGELOG — Set-OPS
|
||||
|
||||
## 2026-09-11 (2) — La piste d'audit sort de la machine auditee
|
||||
|
||||
`auditd` tournait, onze regles etaient armees, et rien de tout cela ne servait a grand-chose.
|
||||
Quatre manques, mesures avant d'etre combles.
|
||||
|
||||
### 1. Rien ne sortait de la machine
|
||||
|
||||
C'etait le trou decisif. La configuration d'Alloy contenait **zero** reference a l'audit, et
|
||||
les cinq greffons d'`auditd` etaient tous `active = no`. La piste vivait uniquement sur la
|
||||
machine auditee : qui la compromet possede la preuve de l'avoir fait, et le fichier est
|
||||
precisement ce qu'on efface en premier.
|
||||
|
||||
Alloy lit maintenant `/var/log/audit/audit.log` et le pousse vers Loki. **Aucune permission
|
||||
a poser** — mesure, pas suppose :
|
||||
|
||||
uid=999(alloy) groupes=989(alloy),4(adm),999(systemd-journal)
|
||||
drwxr-x--- 2 root adm /var/log/audit
|
||||
|
||||
ON A ECARTE L'AUTRE VOIE, et pour une raison precise : activer le greffon `syslog.conf`
|
||||
ferait passer les evenements par journald, deja collecte — mais journald applique une LIMITE
|
||||
DE DEBIT. Une rafale d'evenements d'audit, c'est-a-dire exactement le moment qui compte,
|
||||
serait tronquee en silence.
|
||||
|
||||
L'activation DERIVE de l'appartenance au groupe (`serveur_durci` dans `group_names`), pas
|
||||
d'une liste par instance : une liste de plus qui suit une autre prendrait du retard.
|
||||
|
||||
### 2. Aucune sonde, alors que le depot racontait lui-meme la panne
|
||||
|
||||
`roles/auditd/` n'avait pas de `meta/` du tout. Et son propre `defaults/main.yml` documentait
|
||||
l'incident du 2026-08-30 : onze regles armees dans le noyau sur quinze machines ou `auditd`
|
||||
etait mort, `auditctl -l` les affichant toutes.
|
||||
|
||||
La sonde `audit` mesure donc la COLLECTE — service actif **et** journal qui a bouge. Le
|
||||
nombre de regles part en **perfdata, jamais en verdict** : c'est exactement le chiffre qui
|
||||
restait bon pendant la panne.
|
||||
|
||||
Declaree dans `roles/serveur_durci/meta/` (le GROUPE) et deposee par `roles/auditd/` : la
|
||||
derivation de supervision ne traverse pas les roles-taches. Meme lecon que la sonde
|
||||
`correctifs`, deplacee la veille.
|
||||
|
||||
### 3. La retention n'etait declaree nulle part
|
||||
|
||||
Mesure sur `infra-edge-01` au repos, deploiement termine :
|
||||
|
||||
3 380 octets / 60 s -> ~4,6 Mo/jour
|
||||
Debian : 8 Mo x 5 = 40 Mo -> ~9 jours
|
||||
|
||||
Sauf qu'une reconstruction a elle seule en brule 4 Mo. Portee a 16 Mo x 8 = 128 Mo (~28
|
||||
jours), et le raisonnement a change en route : depuis (1), l'archive n'est plus ici, elle est
|
||||
chez le collecteur. Le local n'est plus qu'un TAMPON pour traverser une panne de Loki.
|
||||
|
||||
### 4. Les regles ignoraient le materiel qui signe tout le reste
|
||||
|
||||
Elles surveillaient `passwd`, `sudoers`, `sshd_config`, `/etc/apt/` — les fichiers par
|
||||
lesquels on prend un COMPTE. Aucune ne regardait `/etc/step/certs/`, la cle privee de
|
||||
l'hote : qui la copie parle ensuite au nom de la machine devant toute la flotte, sans
|
||||
toucher a un mot de passe ni declencher une seule des regles precedentes.
|
||||
|
||||
-w /etc/step/ -p wa -k pki
|
||||
-w /etc/step-ca/ -p wa -k pki-autorite (autorite seulement)
|
||||
|
||||
**LA SECONDE EST CONDITIONNELLE, ET CE N'EST PAS UN DETAIL.** `auditctl` REFUSE un `-w` vers
|
||||
un chemin absent, et `augenrules` fait alors echouer le chargement ENTIER — `auditd` ne
|
||||
demarre plus, faute de sa dependance. Poser cette ligne sur les treize machines qui ne sont
|
||||
pas l'autorite rejouerait exactement la panne du 2026-08-30. Verifie sur l'autorite d'abord,
|
||||
seule : 13 regles armees, `audit-rules` non en echec, sonde a 0.
|
||||
|
||||
### Un effet de bord assume
|
||||
|
||||
Creer `roles/serveur_durci/` pour porter la declaration en fait un role a part entiere : il
|
||||
lui faut son README et sa `meta/authentification.yml`, comme `serveur_debian`. Trois preuves
|
||||
l'ont exige (P29, P31, P48) — elles ont fait exactement leur travail.
|
||||
|
||||
## 2026-09-11 (1) — Reconstruction a froid : les noms derives naissent justes
|
||||
|
||||
Quatrieme reconstruction depuis zero de Chezlepro, demandee pour une raison precise : trois
|
||||
|
|
|
|||
|
|
@ -41,16 +41,16 @@
|
|||
| P26 | Integrations universelles : aucun hote laisse de cote | AFF-108 | ✅ OK | 14 hote(s) x 6 integration(s) universelle(s) : aucune lacune, aucune recopie (0 exemption(s) derivee(s) du service rendu). |
|
||||
| P27 | Propriete des intrants : hebergeur et tenant separes | AFF-109 | ✅ OK | 8 cle(s) de cluster chez l'hebergeur, aucune recopiee dans les group_vars du tenant. |
|
||||
| P28 | Pools Proxmox : un par tenant, sans collision | AFF-110 | ✅ OK | CONFORME : 3 pool(s) Proxmox, 34 VM placee(s), aucun nom ni VMID en collision. |
|
||||
| P29 | Authentification : chaque role declare sa position | AFF-111 | ✅ OK | 32 role(s) serveur declares (interne-sans-auth 2, ldap-direct 2, sans-auth-humaine 21, socle-identite 2, web-sso 5) ; 2 lacune(s) nommee(s) : serveur_loki, serv |
|
||||
| P29 | Authentification : chaque role declare sa position | AFF-111 | ✅ OK | 33 role(s) serveur declares (interne-sans-auth 2, ldap-direct 2, sans-auth-humaine 22, socle-identite 2, web-sso 5) ; 2 lacune(s) nommee(s) : serveur_loki, serv |
|
||||
| P30 | SDN EVPN : zones, VNets et sous-reseaux derives | AFF-112 | ✅ OK | CONFORME : SDN EVPN, 3 zone(s), 15 VNet(s), 15 sous-reseau(x), aucune collision. |
|
||||
| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 59 scripts expliques et atteignables, 116 cibles make documentees, 67 roles avec README. |
|
||||
| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 59 scripts expliques et atteignables, 116 cibles make documentees, 68 roles avec README. |
|
||||
| P32 | Intrants exiges par les roles : tous fournis | — | ✅ OK | CONFORME : 38 exigence(s) de role, toutes satisfaites (137 cle(s) declaree(s) par l'instance). |
|
||||
| P33 | Aucune collision de port entre roles co-localises | — | ✅ OK | CONFORME : 34 revendication(s) de port, aucune collision entre roles co-localises (36 groupes). |
|
||||
| P34 | Chaque document declare son lecteur | — | ✅ OK | 44 document(s) declarent leur lecteur (37 genere(s) exempte(s)). |
|
||||
| P35 | Toute application exigeant une base en a une au plan | — | ✅ OK | 5 application(s) exigeant une base l'ont toutes (4 entree(s) au registre). |
|
||||
| P36 | Tout detenteur d'etat porte une sauvegarde | — | ✅ OK | 9 hote(s) de l'ecosysteme et 3 du site detiennent de l'etat, tous porteurs de `client_backup` (9 groupe(s) au catalogue). |
|
||||
| P37 | Le placement du tenant existe chez son hebergeur | — | ✅ OK | placement confronte a l'hebergeur monte (SITE-Chezlepro) : noeud, stockage, pont — tous offerts. |
|
||||
| P38 | Catalogue des services : la carte dit ce que le moteur fait | — | ✅ OK | Catalogue a jour : 40 role(s) serveur/client tous nommes, 41 groupe(s) cite(s) en table existent tous. |
|
||||
| P38 | Catalogue des services : la carte dit ce que le moteur fait | — | ✅ OK | Catalogue a jour : 41 role(s) serveur/client tous nommes, 41 groupe(s) cite(s) en table existent tous. |
|
||||
| P39 | Glossaire : tout mot employe est enseigne | — | ✅ OK | Glossaire complet : 81 terme(s) du jargon expliques, 15 lien(s) valides, 27 page(s) de wiki toutes atteignables. |
|
||||
| P40 | Parente : l'ecosysteme sait de quoi il descend | — | ✅ OK | Parente coherente : 4 depot(s), tous retrouves, tous porteurs d'un remote. |
|
||||
| P41 | Resolution d'instance : une seule, partagee | — | ✅ OK | Resolution unique : 55 script(s) passent par `inventory_rules`, 3 exemption(s) nommee(s). |
|
||||
|
|
@ -69,14 +69,14 @@
|
|||
| P54 | L'insemination ne reclame aucun secret du tenant | — | ✅ OK | 2 couche(s) d'insemination (serveur_debian, serveur_ops), 9 role(s) applique(s), aucun secret de tenant reclame. |
|
||||
| P55 | La cle du SITE ne nait que sur le runner d'un tenant | — | ✅ OK | 14 hote(s) : la cle du SITE ne nait que sur 1 runner(s) de tenant, celle du tenant sur 14. |
|
||||
| P56 | Gabarit minimal, et rien de retire n'est perdu | — | ✅ OK | Gabarit minimal : 4 role(s), tous indispensables au premier demarrage ; 14 role(s) retire(s), tous repris par le socle ou le durcissement. |
|
||||
| P57 | Comptes en prose : les chiffres du depot sur lui-meme | — | ✅ OK | Les comptes ecrits en prose correspondent a la mesure (68 preuves, 67 roles, 41 groupes). |
|
||||
| P57 | Comptes en prose : les chiffres du depot sur lui-meme | — | ✅ OK | Les comptes ecrits en prose correspondent a la mesure (68 preuves, 68 roles, 41 groupes). |
|
||||
| P58 | Habilitations : chaque service dit a quel GROUPE, et par quoi | — | ✅ OK | 8 habilitation(s) declarees, toutes nommant un groupe, un mecanisme connu et une raison ; les `role-realm` sont projetees. |
|
||||
| P59 | Enumerations annoncees : le nombre correspond a ce qui suit | — | ✅ OK | 2 enumeration(s) annoncee(s) correspondent a ce qu'elles annoncent (formes non ambigues seulement). |
|
||||
| P60 | Wiki publie : la forge sert ce que le depot dit | AFF-002 | ✅ OK | Le wiki publie correspond au depot : `wiki/` n'a pas bouge depuis `53e2f78` (publie le 2026-09-11). |
|
||||
| P61 | Schema du plan : il decrit tout ce que les plans contiennent | AFF-033 | ✅ OK | Le schema decrit 47 champ(s) sur 6 registres ; il couvre tout ce que les plans reels contiennent, et la FORME de chaque champ (scalaire / objet / table) corresp |
|
||||
| P62 | Schema du plan : il decrit tout ce que le MOTEUR accepte | AFF-033 | ✅ OK | Les 4 validateurs n'acceptent aucun champ que le schema ignore (applications:8, bases_donnees:4, domaines_publics:5, serveurs:3 champ(s) lus par validateur). |
|
||||
| P63 | cloud-init nait avec la VM et ne lui survit pas | — | ✅ OK | cloud-init est au gabarit (la premiere seconde), absent du socle (pas de va-et-vient), et retire par le durcissement — avec la garde qui verifie que le reseau s |
|
||||
| P64 | Sondes de supervision : declarees ET deposees | — | ✅ OK | 24 sonde(s) declaree(s) ET deposee(s), chacune avec sa raison et son `ttl` : client_journal/journaux, client_metrique/metriques, client_pki/certificat, serveur_ |
|
||||
| P64 | Sondes de supervision : declarees ET deposees | — | ✅ OK | 25 sonde(s) declaree(s) ET deposee(s), chacune avec sa raison et son `ttl` : client_journal/journaux, client_metrique/metriques, client_pki/certificat, serveur_ |
|
||||
| P65 | Depots tiers : demandes au cache, jamais en HTTPS direct | — | ✅ OK | 4 depot(s) tiers relaye(s) par le cache, aucun role ne les vise en https:// ecrit en dur. |
|
||||
| P66 | Clients OIDC : chaque URI vise un nom que le plan expose | — | ✅ OK | 4 client(s) OIDC, toutes leurs URI visent un FQDN que le plan expose (6 exposition(s)). |
|
||||
| P67 | Nom public : le service porte celui du plan, pas celui du role | — | ✅ OK | 6 service(s) expose(s) portent le nom du plan (6 groupe(s) derive(s)). |
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ Une directive qu'aucune garde ne vérifie finit par ne plus être vraie. Chaque
|
|||
| `socle-identite` | **est** la chaîne d'identité, ne peut pas se déléguer à elle-même | keycloak, openldap |
|
||||
| `ldap-direct` | protocole non-OIDC lié à LDAP | dovecot, postfix |
|
||||
| `interne-sans-auth` | interface joignable **dans** le tenant sans authentification, non exposée | prometheus, loki |
|
||||
| `sans-auth-humaine` | aucun point d'authentification humaine | 21 |
|
||||
| `sans-auth-humaine` | aucun point d'authentification humaine | 22 |
|
||||
|
||||
La preuve refuse **l'oubli et le mensonge** : un rôle sans déclaration, une portée
|
||||
inventée, un `web-sso` sans accès de secours ou sans posture de formulaire, un `web-sso
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ README de rôles). Cette page comble ces deux trous.
|
|||
|
||||
| Ce qu'on compte | Combien | Comment on le mesure |
|
||||
|---|---|---|
|
||||
| rôles | 67 | `roles/*/` |
|
||||
| README de rôles | 67 | `roles/*/README.md` — l'écart avec la ligne au-dessus est la dette |
|
||||
| rôles | 68 | `roles/*/` |
|
||||
| README de rôles | 68 | `roles/*/README.md` — l'écart avec la ligne au-dessus est la dette |
|
||||
| documents | 40 | `docs/*.md` |
|
||||
| pièces d'audit | 42 | `docs/audit/*` |
|
||||
| unités de wiki | 27 | `wiki/*.md` |
|
||||
|
|
|
|||
|
|
@ -23,3 +23,34 @@ auditd_enabled: true
|
|||
# de quelqu'un d'autre.
|
||||
auditd_fichiers_perimes:
|
||||
- 99-chezlepro.rules
|
||||
|
||||
# RETENTION LOCALE : UN TAMPON, PLUS UNE ARCHIVE (2026-09-11).
|
||||
#
|
||||
# Debian livre 8 Mo x 5 fichiers = 40 Mo. Mesure sur `infra-edge-01` au repos,
|
||||
# deploiement termine : 3 380 octets en 60 s, soit ~4,6 Mo/jour. Les 40 Mo tiennent
|
||||
# donc environ NEUF JOURS — sauf qu'une reconstruction a elle seule en brule 4 Mo : les
|
||||
# trois du 2026-09-10 auraient mange trois jours de piste.
|
||||
#
|
||||
# CE QUI CHANGE LE RAISONNEMENT : depuis aujourd'hui, Alloy expedie `audit.log` vers Loki
|
||||
# (`client_journal`). L'archive n'est plus ici — elle est chez le collecteur, hors de la
|
||||
# machine auditee, ce qui est le seul endroit ou elle ait une valeur de preuve. Ce qui
|
||||
# reste en local n'est plus qu'un TAMPON : de quoi traverser une panne de Loki sans
|
||||
# perdre la piste.
|
||||
#
|
||||
# 16 Mo x 8 = 128 Mo, soit ~28 jours au repos. Sur un disque de 40 Go c'est negligeable,
|
||||
# et ca couvre largement toute indisponibilite plausible du collecteur.
|
||||
#
|
||||
# CE CHOIX EST UNE DECISION D'EXPLOITATION, pas une derivation : deux lignes a changer si
|
||||
# la mesure du debit evolue.
|
||||
auditd_max_log_file: 16 # Mo par fichier
|
||||
auditd_num_logs: 8 # fichiers conserves
|
||||
|
||||
# SONDE « audit » — AGE MAXIMAL TOLERE SANS UNE SEULE ECRITURE.
|
||||
#
|
||||
# Repose sur une observation, et il faut le savoir : le journal bouge meme SANS activite
|
||||
# humaine. La regle `time-change` capte les ajustements d'horloge (218 evenements sur la
|
||||
# premiere heure d'une machine neuve), et les sessions `sudo` du deploiement le reste du
|
||||
# temps. Une heure de silence COMPLET n'est donc pas un creux normal : c'est soit
|
||||
# `disk_full_action = SUSPEND` qui a mordu, soit la collecte qui s'est arretee sans que le
|
||||
# service meure.
|
||||
auditd_sonde_age_max: 3600
|
||||
|
|
|
|||
|
|
@ -18,6 +18,29 @@
|
|||
notify: Restart auditd
|
||||
when: auditd_enabled | bool
|
||||
|
||||
# LA RETENTION EST UN CHOIX, DONC ELLE S'ECRIT (2026-09-11). Voir defaults/main.yml pour
|
||||
# l'arithmetique : depuis qu'Alloy expedie `audit.log` vers Loki, le local n'est plus
|
||||
# l'archive mais un TAMPON pour traverser une panne du collecteur.
|
||||
#
|
||||
# `lineinfile` plutot qu'un gabarit complet : `auditd.conf` porte une quinzaine de
|
||||
# reglages que Debian ajuste, et les reecrire tous nous rendrait responsables de choix
|
||||
# que nous n'avons pas faits.
|
||||
- name: Fixer la retention locale du journal d'audit
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/audit/auditd.conf
|
||||
regexp: "^{{ item.cle }}\\s*="
|
||||
line: "{{ item.cle }} = {{ item.valeur }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0640"
|
||||
loop:
|
||||
- { cle: "max_log_file", valeur: "{{ auditd_max_log_file }}" }
|
||||
- { cle: "num_logs", valeur: "{{ auditd_num_logs }}" }
|
||||
loop_control:
|
||||
label: "{{ item.cle }}"
|
||||
notify: Restart auditd
|
||||
when: auditd_enabled | bool
|
||||
|
||||
- name: Déployer les règles auditd Set-OPS
|
||||
ansible.builtin.template:
|
||||
src: 99-setops.rules.j2
|
||||
|
|
@ -55,3 +78,19 @@
|
|||
`auditd` depend — verifier `augenrules --check` et `auditd_fichiers_perimes`.
|
||||
Les regles peuvent etre ARMEES dans le noyau sans que personne ne collecte.
|
||||
when: auditd_enabled | bool
|
||||
|
||||
# LA SONDE MESURE LA COLLECTE, PAS L'ARMEMENT. Voir le gabarit : le 2026-08-30, onze
|
||||
# regles etaient armees dans le noyau sur quinze machines ou personne ne collectait.
|
||||
#
|
||||
# ELLE EST DECLAREE PAR LE GROUPE `serveur_durci` ET DEPOSEE ICI. La derivation de
|
||||
# supervision ne traverse pas les roles-taches : declaree dans `roles/auditd/meta/`, elle
|
||||
# serait restee invisible d'Icinga — et le menage de `client_sante` l'aurait effacee au
|
||||
# passage suivant. Meme lecon que la sonde `correctifs`, le 2026-09-10.
|
||||
- name: Deposer la sonde de collecte d'audit
|
||||
ansible.builtin.template:
|
||||
src: sonde-audit.sh.j2
|
||||
dest: /usr/local/lib/setops/sondes/audit.sh
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0750"
|
||||
when: auditd_enabled | bool
|
||||
|
|
|
|||
|
|
@ -13,6 +13,29 @@
|
|||
-w /etc/ssh/sshd_config.d/ -p wa -k sshd
|
||||
-w /etc/apt/ -p wa -k apt-config
|
||||
|
||||
# LE MATERIEL QUI SIGNE TOUT LE RESTE (2026-09-11).
|
||||
#
|
||||
# Les regles ci-dessus surveillent les fichiers par lesquels on prend un compte. Celles-ci
|
||||
# surveillent ce par quoi on prend une IDENTITE DE MACHINE : `/etc/step/certs/` porte la
|
||||
# cle privee de l'hote. Qui la copie parle ensuite au nom de la machine devant toute la
|
||||
# flotte — PostgreSQL en `verify-full`, Loki, l'annuaire — sans jamais toucher a un
|
||||
# mot de passe ni declencher une seule des regles precedentes.
|
||||
-w /etc/step/ -p wa -k pki
|
||||
{% if 'serveur_step_ca' in group_names %}
|
||||
|
||||
# LA RACINE DE CONFIANCE, ET ELLE N'EXISTE QUE SUR L'AUTORITE.
|
||||
#
|
||||
# `/etc/step-ca/` contient `password.txt` et `secrets/` : de quoi emettre un certificat
|
||||
# valide pour N'IMPORTE QUEL nom de l'ecosysteme. C'est le seul secret dont la copie ne
|
||||
# se repare pas par une rotation — il faut refaire la PKI entiere.
|
||||
#
|
||||
# LA GARDE EST CONDITIONNELLE, ET CE N'EST PAS UN DETAIL : `auditctl` REFUSE un `-w` vers
|
||||
# un chemin absent, et `augenrules` fait alors echouer le chargement ENTIER. Poser cette
|
||||
# ligne sur les treize machines qui ne sont pas l'autorite rejouerait exactement la panne
|
||||
# du 2026-08-30 — regles armees, personne pour collecter.
|
||||
-w /etc/step-ca/ -p wa -k pki-autorite
|
||||
{% endif %}
|
||||
|
||||
-a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k time-change
|
||||
-a always,exit -F arch=b64 -S sethostname,setdomainname -k system-locale
|
||||
|
||||
|
|
|
|||
48
roles/auditd/templates/sonde-audit.sh.j2
Normal file
48
roles/auditd/templates/sonde-audit.sh.j2
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#!/bin/bash
|
||||
# GENERE par Set-OPS (role auditd). Ne pas editer a la main.
|
||||
#
|
||||
# SONDE « audit » — QUELQU'UN COLLECTE-T-IL, vraiment ?
|
||||
#
|
||||
# ELLE NE COMPTE PAS LES REGLES, ET C'EST TOUT SON OBJET. Le 2026-08-30, sur les quinze
|
||||
# machines de Chezlepro, `auditctl -l` affichait onze regles armees dans le noyau pendant
|
||||
# qu'`auditd` etait mort : un doublon dans `rules.d/` faisait echouer `audit-rules.service`,
|
||||
# dont le demon depend. Une sonde qui aurait compte les regles aurait dit « vert » pendant
|
||||
# toute la panne. On mesure donc la COLLECTE — le service, puis l'ecriture.
|
||||
#
|
||||
# Contrat : docs/supervision-conception.md (API des greffons Nagios) — une ligne, 0/1/2.
|
||||
# Mise en defaut PAR PARAMETRE : `auditd_sonde_age_max` (le baisser a 1).
|
||||
set -uo pipefail
|
||||
|
||||
JOURNAL=/var/log/audit/audit.log
|
||||
AGE_MAX={{ auditd_sonde_age_max }}
|
||||
|
||||
# Les regles ne sont PAS le verdict : elles partent en perfdata, pour que le diagnostic
|
||||
# distingue « rien d'arme » de « arme mais personne ne collecte ».
|
||||
regles=$(auditctl -l 2>/dev/null | grep -cvE '^No rules$' || true)
|
||||
regles=${regles:-0}
|
||||
|
||||
if ! systemctl is-active --quiet auditd; then
|
||||
echo "auditd ne tourne pas : ${regles} regle(s) peuvent etre armees, personne ne collecte." \
|
||||
"| regles=${regles} age=U taille=0B"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ ! -f "${JOURNAL}" ]]; then
|
||||
echo "auditd tourne mais ${JOURNAL} n'existe pas : rien n'est ecrit." \
|
||||
"| regles=${regles} age=U taille=0B"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
taille=$(stat -c%s "${JOURNAL}" 2>/dev/null || echo 0)
|
||||
age=$(( $(date +%s) - $(stat -c%Y "${JOURNAL}" 2>/dev/null || echo 0) ))
|
||||
|
||||
if (( age > AGE_MAX )); then
|
||||
echo "auditd tourne mais n'a rien ecrit depuis ${age} s (seuil ${AGE_MAX} s) :" \
|
||||
"collecte suspendue, disque plein ou regles vides." \
|
||||
"| regles=${regles} age=${age}s;${AGE_MAX} taille=${taille}B"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Audit collecte : ecriture il y a ${age} s, ${regles} regle(s) armee(s)." \
|
||||
"| regles=${regles} age=${age}s;${AGE_MAX} taille=${taille}B"
|
||||
exit 0
|
||||
|
|
@ -80,3 +80,11 @@ client_journal_syslog_protocole: "tcp"
|
|||
# Le nom sous lequel les journaux recus apparaitront. Derive de la carte par l'inventaire
|
||||
# du site — jamais fabrique ici.
|
||||
client_journal_syslog_emetteur: "frontiere"
|
||||
|
||||
# LE JOURNAL D'AUDIT, EXPEDIE COMME LE RESTE (2026-09-11).
|
||||
#
|
||||
# DERIVE DE L'APPARTENANCE AU GROUPE, pas declare par instance : `auditd` vient avec
|
||||
# `serveur_durci`, donc la machine qui a l'un a l'autre. Ecrire la liste a la main serait
|
||||
# une liste de plus qui suit une autre — et qui prendrait du retard.
|
||||
client_journal_audit_actif: "{{ 'serveur_durci' in group_names }}"
|
||||
client_journal_audit_chemin: "/var/log/audit/audit.log"
|
||||
|
|
|
|||
|
|
@ -20,6 +20,31 @@ loki.source.journal "journal" {
|
|||
}
|
||||
}
|
||||
|
||||
{% if client_journal_audit_actif %}
|
||||
// --- LA PISTE D'AUDIT SORT DE LA MACHINE AUDITEE (2026-09-11) ---
|
||||
//
|
||||
// `auditd` ecrit dans `/var/log/audit/audit.log` et nulle part ailleurs. Tant que la
|
||||
// piste reste sur la machine qu'elle surveille, qui compromet la machine possede la
|
||||
// preuve de l'avoir fait — et le fichier est precisement ce qu'on efface en premier.
|
||||
//
|
||||
// POURQUOI PAS LE GREFFON `syslog.conf` D'AUDITD, qui ferait passer les evenements par
|
||||
// journald (deja collecte) : journald applique une LIMITE DE DEBIT. Une rafale
|
||||
// d'evenements d'audit — c'est-a-dire exactement le moment qui compte — serait tronquee
|
||||
// en silence. On lit donc le fichier directement.
|
||||
//
|
||||
// AUCUNE PERMISSION A POSER : `/var/log/audit` est `root:adm` en 0750, et l'utilisateur
|
||||
// `alloy` appartient DEJA au groupe `adm` (mesure le 2026-09-11). Si cela changeait,
|
||||
// Alloy se tairait sans erreur visible — la sonde `audit` reste le filet cote machine.
|
||||
loki.source.file "audit" {
|
||||
targets = [{
|
||||
__path__ = "{{ client_journal_audit_chemin }}",
|
||||
job = "audit",
|
||||
host = "{{ inventory_hostname }}",
|
||||
}]
|
||||
forward_to = [loki.write.loki.receiver]
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% if client_journal_syslog_ecoute %}
|
||||
// --- RECEPTEUR SYSLOG : CE QUI NE PEUT PAS PORTER D'AGENT (2026-09-10) ---
|
||||
//
|
||||
|
|
|
|||
41
roles/serveur_durci/README.md
Normal file
41
roles/serveur_durci/README.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# serveur_durci
|
||||
|
||||
**Rôle-catégorie** du durcissement : il ne porte **aucune tâche**. Son unique contenu est
|
||||
`meta/supervision.yml` — la déclaration de la sonde `audit`.
|
||||
|
||||
## Pourquoi un rôle sans tâches
|
||||
|
||||
La dérivation de supervision agrège les `roles/<rôle>/meta/supervision.yml` **par nom de
|
||||
groupe**. Déclarée dans `roles/auditd/`, qui est un rôle-tâche et non un groupe, la sonde
|
||||
serait restée invisible d'Icinga — et le ménage de `client_sante` l'aurait effacée au
|
||||
passage suivant. Même leçon que la sonde `correctifs`, déplacée de `common_packages` vers
|
||||
`serveur_debian` le 2026-09-10.
|
||||
|
||||
Le fichier est déposé par `roles/auditd/` ; il est **déclaré** ici. La preuve **P64** garde
|
||||
les deux moitiés ensemble.
|
||||
|
||||
## Le travail réel
|
||||
|
||||
Il est fait par le playbook du groupe, `playbooks/groupes/serveur_durci.yml`, qui applique
|
||||
dans l'ordre :
|
||||
|
||||
| Rôle | Apport |
|
||||
| --- | --- |
|
||||
| `hardening_packages` | Paquets de durcissement |
|
||||
| `sysctl_hardening` | Paramètres noyau |
|
||||
| `core_dumps` | Vidages mémoire désarmés |
|
||||
| `unattended_upgrades` | Mises à jour automatiques **masquées** (voir la sonde `correctifs`) |
|
||||
| `apparmor` | Confinement des services |
|
||||
| `auditd` | Piste d'audit : règles, rétention, sonde |
|
||||
| `fail2ban_ssh` | Bannissement des tentatives SSH |
|
||||
|
||||
## La sonde `audit`
|
||||
|
||||
Elle mesure la **collecte**, pas l'armement — et c'est tout son objet. Le 2026-08-30, sur
|
||||
les quinze machines de Chezlepro, `auditctl -l` affichait onze règles armées dans le noyau
|
||||
pendant qu'`auditd` était mort : un doublon dans `rules.d/` faisait échouer
|
||||
`audit-rules.service`, dont le démon dépend. Une sonde qui aurait compté les règles aurait
|
||||
dit « vert » pendant toute la panne.
|
||||
|
||||
Le nombre de règles part donc en **perfdata**, jamais en verdict — pour que le diagnostic
|
||||
distingue « rien d'armé » de « armé mais rien de collecté ».
|
||||
10
roles/serveur_durci/meta/authentification.yml
Normal file
10
roles/serveur_durci/meta/authentification.yml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
# Position de ce role dans la directive d'authentification (D-38..D-41).
|
||||
# Voir docs/authentification.md. Gardee par la preuve P29 : un role sans cette
|
||||
# declaration, ou dont la declaration contredit son code, fait echouer le harnais.
|
||||
authentification:
|
||||
portee: sans-auth-humaine
|
||||
raison: >-
|
||||
Role-categorie du durcissement : il ne porte aucune tache et n'expose aucune
|
||||
interface. Le travail est fait par les roles que son playbook applique, chacun
|
||||
avec sa propre declaration.
|
||||
25
roles/serveur_durci/meta/supervision.yml
Normal file
25
roles/serveur_durci/meta/supervision.yml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
# Supervision derivee du groupe. Voir docs/supervision-conception.md.
|
||||
#
|
||||
# POURQUOI CETTE SONDE EXISTE, ET CE QU'ELLE NE MESURE PAS.
|
||||
#
|
||||
# `auditd` est le seul service de securite du socle dont la panne soit SILENCIEUSE et
|
||||
# TROMPEUSE a la fois. Le 2026-08-30, sur les quinze machines de Chezlepro, un doublon
|
||||
# dans `rules.d/` faisait echouer `audit-rules.service` — dont le demon depend. Resultat :
|
||||
# onze regles armees dans le noyau, `auditctl -l` les affichant toutes, et personne pour
|
||||
# collecter. Pendant tout ce temps le deploiement rapportait `failed=0`.
|
||||
#
|
||||
# CE QU'ON NE MESURE PAS : le nombre de regles. C'est exactement le chiffre qui restait
|
||||
# bon pendant la panne ; en faire un verdict aurait donne du vert. Il part en perfdata,
|
||||
# pour que le diagnostic distingue « rien d'arme » de « arme mais rien de collecte ».
|
||||
#
|
||||
# CE QU'ON MESURE : le service tourne, ET le journal a bouge recemment. Les deux, parce
|
||||
# qu'un `auditd` vivant qui n'ecrit plus — disque plein, `disk_full_action = SUSPEND` —
|
||||
# laisse la meme trace qu'un audit en bonne sante pour qui ne regarde que `systemctl`.
|
||||
sondes:
|
||||
- nom: audit
|
||||
ttl: 5400
|
||||
raison: >-
|
||||
La piste d'audit s'ecrit-elle vraiment ? Des regles armees dans le noyau ne
|
||||
prouvent pas qu'un demon collecte : le 2026-08-30, quinze machines ont eu les
|
||||
deux apparences de la sante sans qu'une seule ligne soit ecrite.
|
||||
Loading…
Reference in a new issue