diff --git a/CHANGELOG.md b/CHANGELOG.md index 86b2ec2..6ab0c02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # CHANGELOG — Set-OPS +## 2026-08-02 — les interfaces se nomment par leur identifiant + +`opt1`, `igb1` et `TENANTS` désignent le même port dans OPNsense : l'identifiant interne, le +périphérique FreeBSD et le libellé affiché. L'API REST ne parle que du **premier**, et c'est +lui que veulent `opnsense_if_wan` et `opnsense_if_transit`. Le libellé de ces deux intrants ne +le disait pas — la question s'est posée en pratique. + +Les libellés le disent maintenant explicitement, et `docs/frontiere-opnsense.md` §6 explique +les trois couches ainsi que le motif du choix : `opt1` est le plus stable des trois, il +survit à un changement de carte réseau comme à un renommage. + +La note « `opnsense_prochain_saut` dérive de l'underlay » est repliée dans l'en-tête que le +panneau régénère : une sauvegarde l'effaçait, puisque le fichier est réécrit depuis le YAML +analysé. Vérifié qu'une sauvegarde préserve valeurs **et** références de voûte. + +### Corrigé — la doc portait encore l'ancien plan du `/29` +Après le renumérotage (`bifrost-1/-2` en `.1`/`.2`, SVI en `.6`), deux passages de +`docs/frontiere-opnsense.md` annonçaient toujours `10.0.4.2` comme prochain saut. La doc +contredisait le devis généré ; les `ip route` des deux coïncident désormais. + ## 2026-08-01 (suite 14) — l'empreinte du root CA n'est pas un secret de voûte `client_pki` **dérive l'empreinte à chaud** depuis l'autorité (`step certificate diff --git a/docs/audit/preuve-2026-08-02.md b/docs/audit/preuve-2026-08-02.md new file mode 100644 index 0000000..2b09180 --- /dev/null +++ b/docs/audit/preuve-2026-08-02.md @@ -0,0 +1,60 @@ +# Preuve de conformite — Set-OPS — 2026-08-02 + +> Genere par `make prouver` (`scripts/prouver.py`). **Rejouable** : relancer +> reproduit ce rapport. Chaque preuve rejoue l'outillage existant du depot ; +> aucune validation n'est reimplementee ici. Voir le mode d'emploi : +> [`docs/audit/README.md`](README.md), et le registre trace : +> [`docs/audit/affirmations.md`](affirmations.md). + +- **Instance** : `instance` — inventaire `instance/inventories/principal/hosts.yml` +- **Verdict** : ✅ CONFORME (24 OK · 0 echec · 0 saute) + +## Preuves + +| # | Preuve | Affirmations | Statut | Detail | +|---|---|---|---|---| +| P01 | Lint (ansible-lint) | AFF-006 | ✅ OK | | +| P02 | Tests unitaires (inventory_host) | — | ✅ OK | 4 tests passes. | +| P03 | Diff-vide du plan (inventaire genere) | AFF-001, AFF-004, AFF-030, AFF-031, AFF-032 | ✅ OK | DIFF VIDE : le plan reproduit exactement l'inventaire actuel. Bascule possible. | +| P04 | Groupes <-> playbooks homonymes | AFF-008 | ✅ OK | | +| P05 | Dependances causales de groupes | AFF-009, AFF-084 | ✅ OK | | +| P06 | Validateurs de registres (serveurs/apps/bases/domaines) | AFF-003 | ✅ OK | Registre des domaines valide. | +| P07 | GUI (node --check) | AFF-033 | ✅ OK | JS du GUI : syntaxe valide (node --check). | +| P08 | Orchestration (couches + graphe) | AFF-070 | ✅ OK | Orchestration coherente : 30 groupes classes, aucun cycle, aucune arete en arriere. | +| P09 | Flux reseau (schema + matrice) | AFF-071 | ✅ OK | Flux coherents : 29 rôles, 63 flux, schéma + matrice OK. | +| P10 | Handlers <-> notify | AFF-034, AFF-035 | ✅ OK | Tout notify pointe vers un handler du meme role (49 roles). | +| P11 | Syntaxe des playbooks (--syntax-check) | AFF-083 | ✅ OK | playbook: playbooks/proxmox/cloner_vm_debian.yml | +| P12 | Existence des runbooks cites | AFF-010, AFF-011, AFF-012, AFF-083 | ✅ OK | 17/17 runbooks/registres cites presents. | +| P13 | Invariants structurels/doctrinaux | AFF-015, AFF-022, AFF-037, AFF-038, AFF-062 | ✅ OK | LICENSE, socle dossier, pas de couches paralleles, SSH clef-only, nftables off : OK. | +| P14 | Pas de chemin lab/ code en dur | AFF-097 | ✅ OK | Aucun chemin instance/inventories/lab/group_vars code en dur. | +| P15 | Modele public socle valide | AFF-022, AFF-099 | ✅ OK | Modele public socle : domaines/serveurs/applications/bases valides. | +| P16 | Inventaire Ansible complet (--list) | AFF-030 | ✅ OK | 14 hotes, 32 groupes (inventaire dechiffre et parse). | +| P17 | Tous les modeles d'instance valident | AFF-022, AFF-099 | ✅ OK | Les 1 modele(s) decouvert(s) valident. | +| P18 | Gabarit de voute complet | AFF-026 | ✅ OK | Gabarit de voute complet : 24 secret(s) exige(s), tous presents. | +| P19 | Le GUI couvre le schema du plan | AFF-002, AFF-095 | ✅ OK | GUI : les 28 champ(s) des plans reels sont editables (2 plan(s) inspecte(s)), registres toleres : nomenclature. | +| P20 | Adressage 100% derive du seed (aucun stocke) | AFF-001, AFF-003 | ✅ OK | 2 nomenclature(s) : adressage 100% derive du seed index. | +| P21 | Federation : aucun index en collision | AFF-001 | ✅ OK | Federation coherente : 2 instance(s) federee(s), aucun index en collision. | +| P22 | Plan de recette a jour (genere du wiki) | AFF-002 | ✅ OK | Plan de recette à jour (19 sections). | +| P23 | Underlay sans collision avec la plage tenant | AFF-001 | ✅ OK | Underlay conforme : 5 reseau(x), aucune collision avec la plage tenant. | +| P24 | Frontiere nord/sud : acces d'administration declare | AFF-001 | ✅ OK | CONFORME : frontiere nord/sud, 6 regles, 2 routes, admin=192.168.255.0/24. | + +## Couverture des affirmations ✅ du registre + +Chaque affirmation ✅ automatisable est couverte par la preuve indiquee ci-dessus. +Les ✅ **structurelles/doctrinales** non rejouables par une commande (ex. AFF-005 +`make`=aide, AFF-014 ciblage groupe, AFF-024 `instancier-appliquer`, AFF-051 autorite +d'AGENTS.md, AFF-073/075 gardes `make`, AFF-090 wiki) ont ete verifiees a l'audit ; +elles restent hors du harnais recurrent (rien d'executable a rejouer). + +## Declarations d'intention (⚪ invérifiables localement — assumees) + +Ces affirmations ne sont pas rejouables hors production ; elles sont **assumees** +comme declarations d'intention, non comme preuves : + +- **AFF-036** — « testables avec `--check` autant que possible » : verifiable seulement + contre une flotte vivante. +- **AFF-091** — contenu pedagogique du wiki : affirmations conceptuelles. +- **AFF-096** — « GUI 100 % francais » : revue exhaustive des libelles rendus, non automatisee. +- **AFF-007** — hote d'exemple `web-frontal-01` : placeholder assume. + +_Rapport genere le 2026-08-02._ diff --git a/docs/frontiere-opnsense.md b/docs/frontiere-opnsense.md index 1d320d7..4fcd59d 100644 --- a/docs/frontiere-opnsense.md +++ b/docs/frontiere-opnsense.md @@ -113,9 +113,9 @@ Un `/29` plutôt qu'un `/30` : pendant une transition, deux pare-feux cohabitent et un `/30` n'offre que deux adresses. `make underlay` (**preuve P23**) refuse une sortie hors du lien, confondue avec le SVI, sans SVI, ou déclarée deux fois. -Ce seul bloc alimente **les deux devis** : le `passerelle` (`10.0.4.1`) devient le SVI côté +Ce seul bloc alimente **les deux devis** : le `passerelle` (`10.0.4.6`) devient le SVI côté switch *et* le prochain saut des routes tenants côté frontière ; le `passerelle_sortie` -(`10.0.4.2`) devient la route par défaut du switch. Le prochain saut n'est donc **pas** un +(`10.0.4.1`) devient la route par défaut du switch. Le prochain saut n'est donc **pas** un intrant du panneau — le saisir en doublon rouvrirait la possibilité de deux valeurs contradictoires pour un seul et même lien. @@ -124,8 +124,8 @@ contradictoires pour un seul et même lien. `make devis-reseau` émet alors, en section 5 : ``` -ip route 0.0.0.0 0.0.0.0 10.0.4.2 # aller -ip route 192.168.255.0 255.255.255.0 10.0.4.2 # retour (nftables_admin_ssh) +ip route 0.0.0.0 0.0.0.0 10.0.4.1 # aller +ip route 192.168.255.0 255.255.255.0 10.0.4.1 # retour (nftables_admin_ssh) ``` **L'aller** est la sortie générale : sans elle, aucun hôte de la flotte n'atteint quoi que ce @@ -209,9 +209,13 @@ ansible-vault edit instance/inventories/principal/group_vars/all/vault.yml - **Le câblage** — le lien de transit est *décidé* (VLAN 40, `10.0.4.0/29`) et le devis switch émet déjà son SVI et ses routes. Reste à figer, une fois le boîtier raccordé, un - seul intrant : `opnsense_if_transit`, le nom de l'interface qui porte le VLAN 40 sur le - boîtier — la seule valeur que rien ne peut deviner. Le prochain saut, lui, **dérive** du - transit (voir §4). + seul intrant : `opnsense_if_transit`, l'interface qui porte le VLAN 40 sur le boîtier — la + seule valeur que rien ne peut deviner. Le prochain saut, lui, **dérive** du transit (§4). + + **Trois noms désignent le même port dans OPNsense**, et l'intrant en veut un seul : + `igb1` est le périphérique FreeBSD, `TENANTS` (ou tout autre libellé) est la description + affichée, et `opt1` est l'**identifiant interne** — le seul que parle l'API REST, et le + plus stable des trois : il survit à un changement de carte réseau comme à un renommage. - **Le second VPN** — pendant la transition, le VPN d'administration actuel (pfSense) reste en service et OPNsense en montera un second. Son sous-réseau devra être **ajouté à `nftables_admin_ssh`**, sans quoi il sera muet de la même façon. diff --git a/scripts/inventory_gui.py b/scripts/inventory_gui.py index f4b3710..30321ae 100644 --- a/scripts/inventory_gui.py +++ b/scripts/inventory_gui.py @@ -128,8 +128,8 @@ INTRANTS_SCHEMA = [ ("proxmox_ponts", "proxmox", "catalogue", "Proxmox", "Ponts réseau disponibles (liste)", "liste"), ("opnsense_api_url", "frontiere", "constante", "Frontière", "URL de gestion de la frontière OPNsense (API REST)", "str"), ("opnsense_api_verifier_certs", "frontiere", "defaut", "Frontière", "Valider le certificat TLS de la frontière", "bool"), - ("opnsense_if_wan", "frontiere", "defaut", "Frontière", "Interface WAN", "str"), - ("opnsense_if_transit", "frontiere", "defaut", "Frontière", "Interface/trunk vers les switches (transit)", "str"), + ("opnsense_if_wan", "frontiere", "defaut", "Frontière", "Interface WAN — IDENTIFIANT OPNsense (wan), pas le libellé ni le périphérique", "str"), + ("opnsense_if_transit", "frontiere", "defaut", "Frontière", "Interface de transit — IDENTIFIANT OPNsense (opt1, opt2…), pas « igb1 » ni le libellé affiché", "str"), ("underlay_routeur", "fabric", "constante", "Fabric", "Switch qui porte le routage (SVI, ACL, routes) — les autres restent en L2 pur", "str"), ("underlay_dialecte", "fabric", "constante", "Fabric", "Dialecte de CLI du commutateur (cisco | binardat)", "str"), ("underlay_stp_mode", "fabric", "defaut", "Fabric", "Mode de spanning-tree (rstp | mstp | pvst)", "str"), @@ -585,7 +585,12 @@ def ecrire_intrants(payload: dict) -> None: "# API keys > « + ». Le secret n'est affiche qu'a la creation.\n" "#\n" "# Le boitier est HORS FLOTTE Ansible : on ne fait que piloter son API REST\n" - "# depuis le controleur. Cf. docs/frontiere-opnsense.md.\n---\n") + "# depuis le controleur. Cf. docs/frontiere-opnsense.md.\n" + "#\n" + "# Les interfaces se nomment par leur IDENTIFIANT OPNsense (wan, opt1...), celui\n" + "# que parle l'API REST — ni le peripherique FreeBSD (igb1), ni le libelle affiche.\n" + "# `opnsense_prochain_saut` n'est pas ici : il DERIVE du reseau de transit de\n" + "# l'underlay (underlay.yml, cle `passerelle_sortie`). Source unique.\n---\n") if "fabric" in par_fichier: _ecrire_intrants_fabric(par_fichier["fabric"]) if "reseau" in par_fichier and "index" in par_fichier["reseau"]: