10 unités restantes + navigation complète (14 unités)

Daniel Allaire 2026-07-04 15:33:18 -04:00
parent 8583bc2634
commit dcfea61848
11 changed files with 714 additions and 14 deletions

71
Bases-de-données.md Normal file

@ -0,0 +1,71 @@
# Bases de données
> **Unité d'apprentissage.** Moule : ① concept → ② Set-OPS → ③ transférable → ④ à toi de jouer.
---
## ① Le concept *(générique)*
Une **base de données relationnelle** stocke des données en **tables** (lignes/colonnes) reliées.
Modèle **client-serveur** : le serveur (PostgreSQL) détient les données ; les applications s'y
**connectent** par le réseau, avec un **compte** et un **mot de passe**, sur une **base** donnée.
**Schéma** = la structure (tables, contraintes). **ACID** = les garanties de fiabilité des
transactions (Atomicité, Cohérence, Isolation, Durabilité). **Rôles/permissions** = qui peut lire/écrire.
Bonne pratique : **une base + un compte dédiés par application** (isolation) — pas un compte
tout-puissant partagé.
---
## ② Comment Set-OPS le fait
`serveur_postgresql` (nœud `data-sql`) est le serveur partagé. L'élégance : un **registre**
déclaratif des bases (`plan/bases-donnees.yml`). Chaque entrée dit *quelle base, quel compte, quel
secret, pour quel consommateur* :
```
Registre ──> PostgreSQL crée la base + le compte propriétaire
──> le rôle consommateur (Keycloak, Forgejo, Icinga…) LIT la même
entrée et bâtit sa connexion — via resoudre_base
```
Le **secret** vit dans la **voûte** (Ansible Vault), déréférencé **au déploiement**, jamais en clair
dans le plan. C'est une **liaison** *app → base*, de modalité **requise** (Keycloak sans sa base ne
démarre pas). Consommateurs prouvés : Keycloak, Forgejo, IcingaDB.
---
## ③ Pourquoi c'est transférable
| Set-OPS | Équivalents ailleurs |
|---|---|
| PostgreSQL | MySQL/MariaDB · SQLite · Oracle · SQL Server |
| une base/compte par app | pratique **universelle** d'isolation |
| secret en voûte | Vault · SOPS · secrets managers cloud |
Tu as appris **le modèle client-serveur, le schéma, l'isolation par app, les secrets** — pas
« PostgreSQL ».
---
## ④ À toi de jouer
1. **Liste les bases** (sur data-sql-01) :
```bash
sudo -u postgres psql -c '\l' # keycloak, forgejo, icingadb…
sudo -u postgres psql -c '\du' # les comptes propriétaires
```
2. **Vois l'isolation.** Chaque app a **sa** base et **son** compte — pas de compte partagé.
3. **Suis une liaison.** Ouvre `plan/bases-donnees.yml` : l'entrée `keycloak` (serveur, base,
propriétaire, secret) est *exactement* ce que le rôle `serveur_keycloak` va lire pour se connecter.
4. **Casse & répare.** Change le mot de passe d'un compte dans PostgreSQL (garde l'ancien !) sans
mettre à jour la voûte : l'app **ne se connecte plus**. Restaure : ça repart. Tu *sens* que la
connexion = *identité + secret cohérents des deux côtés*.
---
## Pour aller plus loin *(dépôt)*
- Rôle : `roles/serveur_postgresql` ; résolveur partagé : `roles/resoudre_base`.
- Le registre : `instance/plan/bases-donnees.yml` ; validation : `scripts/bases_donnees.py verifier`.
- Sauvegarde (Tier 1, `pg_dumpall`) : unité **Sauvegardes**.

64
Cache.md Normal file

@ -0,0 +1,64 @@
# Cache
> **Unité d'apprentissage.** Moule : ① concept → ② Set-OPS → ③ transférable → ④ à toi de jouer.
---
## ① Le concept *(générique)*
Un **cache** garde en **mémoire** (rapide) des données coûteuses à recalculer ou à relire (disque,
base, réseau). Modèle **clé-valeur** : `SET clé valeur`, `GET clé`.
Comme la mémoire est limitée :
- **éviction** — quand c'est plein, on jette (souvent **LRU** : *Least Recently Used*) ;
- **TTL** — une valeur peut **expirer** après un délai.
Règle d'or : **le cache n'est PAS la source de vérité**. Il est **éphémère** — on doit pouvoir le
**perdre sans drame** (la vraie donnée est ailleurs). Le vider = plus lent un instant, jamais faux.
---
## ② Comment Set-OPS le fait
`serveur_redis` (nœud `data-sql`) fournit un cache réseau. Points notables :
- **authentification obligatoire** (`requirepass`, secret en voûte) — il est exposé sur le réseau
interne, donc on ne laisse jamais un cache ouvert ;
- **`maxmemory` + politique `allkeys-lru`** — borne la mémoire, évince en LRU ;
- Icinga a son **propre** Redis dédié (`icingadb-redis`) — un cache par besoin, pas un fourre-tout.
Conséquence directe : Redis est **Tier 3** (éphémère) — **on ne le sauvegarde pas**. C'est le
pendant parfait de l'unité *Sauvegardes* : on protège la donnée d'état, **pas** le cache.
---
## ③ Pourquoi c'est transférable
| Set-OPS | Équivalents ailleurs |
|---|---|
| Redis | Memcached · Valkey · KeyDB · caches cloud (ElastiCache…) |
| LRU + TTL | mécanismes **universels** d'éviction/expiration |
| cache éphémère ≠ source de vérité | principe valable partout |
Tu as appris **le cache clé-valeur, l'éviction LRU, le TTL, l'éphémère** — pas « Redis ».
---
## ④ À toi de jouer
1. **Écris/lis avec authentification** (sur data-sql-01) :
```bash
redis-cli -a "<mot de passe vault_redis>" SET essai:1 bonjour
redis-cli -a "<mot de passe vault_redis>" GET essai:1
```
2. **Teste le TTL** : `redis-cli -a … SET court 1 EX 5` puis `GET court` avant/après 5 s — il **expire**.
3. **Vois la borne** : `redis-cli -a … CONFIG GET maxmemory` et `… maxmemory-policy` (LRU).
4. **Casse & répare.** Interroge **sans** mot de passe : `redis-cli GET essai:1`**`NOAUTH`**
(refusé). Puis vide le cache (`FLUSHALL`) : rien ne casse dans l'écosystème — la vraie donnée est
en base. Tu *sens* qu'un cache est **jetable**.
---
## Pour aller plus loin *(dépôt)*
- Rôle : `roles/serveur_redis`.
- Redis dédié d'Icinga : `roles/serveur_icinga` (`icingadb-redis`).
- Tiers de sauvegarde (Redis = Tier 3, non sauvegardé) : unité **Sauvegardes**.

72
Courriel.md Normal file

@ -0,0 +1,72 @@
# Courriel (SMTP / IMAP)
> **Unité d'apprentissage.** Moule : ① concept → ② Set-OPS → ③ transférable → ④ à toi de jouer.
---
## ① Le concept *(générique)*
Le courriel, c'est **trois rôles** distincts (souvent confondus) :
- **MTA** (*Mail Transfer Agent*) : transporte le courrier entre serveurs — protocole **SMTP** (`:25`).
- **MDA** (*Mail Delivery Agent*) : dépose le courrier dans la **boîte** et la sert — **IMAP** (`:993`).
- **MUA** (*Mail User Agent*) : ton client (Thunderbird, l'appli).
Deux SMTP différents :
- **`:25`** = relais **serveur↔serveur** (pas d'authentification par mot de passe).
- **`:587` (soumission)** = un **client authentifié** *envoie* son courrier (**SMTP AUTH + STARTTLS**).
**LMTP** = remise **locale** du MTA vers le magasin. **Déliverabilité** (vers l'externe) = un tout
autre problème : **DKIM** (signer), **SPF**, **DMARC**, réputation IP.
---
## ② Comment Set-OPS le fait
| Pièce | Rôle |
|---|---|
| **Postfix** (`serveur_postfix`, edge-mta) | le **MTA** : reçoit `:25`, valide le destinataire **contre LDAP**, remet en **LMTP**. |
| **Dovecot** (`serveur_dovecot`, infra-mail) | le **MDA/magasin** : boîtes `/var/vmail`, **IMAP** `:993`. |
| **rspamd** (`serveur_rspamd`) | antispam + **signature DKIM**. |
La **boucle souveraine**, prouvée de bout en bout :
```
Reçevoir : … ──> Postfix :25 ──> validation LDAP ──> LMTP ──> Dovecot ──> IMAP
Envoyer : client ──> :587 (AUTH+STARTTLS) ──> SASL Dovecot/LDAP ──> Postfix ──> remise
```
Une **identité** (`testmail`, le mot de passe LDAP) sert IMAP *et* la soumission. Le tout **interne,
chiffré, sans jamais toucher Internet** (l'envoi vers l'externe = Étape B, déliverabilité).
---
## ③ Pourquoi c'est transférable
| Set-OPS | Équivalents ailleurs |
|---|---|
| Postfix / Dovecot | Exim · Sendmail · Exchange · tout serveur SMTP/IMAP |
| SMTP/IMAP/LMTP, `:587` | **protocoles standards** — identiques partout |
| DKIM/SPF/DMARC | universels pour la déliverabilité |
Tu as appris **MTA/MDA/MUA, SMTP vs soumission, IMAP, la déliverabilité** — pas « Postfix ».
---
## ④ À toi de jouer
1. **Envoie via la soumission `:587`** (client authentifié) :
```bash
swaks --server edge-mta-01.lab.chezlepro.internal:587 --tls \
--auth LOGIN --auth-user testmail@lab.chezlepro.internal --auth-password MotDePasseTest123 \
--from testmail@lab.chezlepro.internal --to testmail@lab.chezlepro.internal --header 'Subject: essai'
```
`235 Authentication successful` puis `250 queued` = ① en action.
2. **Lis la boîte** (le MDA) : `doveadm search -u testmail mailbox INBOX all | wc -l` sur infra-mail-01.
3. **Casse & répare.** Coupe l'annuaire (arrête OpenLDAP), renvoie un courriel : Postfix **rejette le
destinataire** (il ne peut plus valider en LDAP). Rallume OpenLDAP : ça repart. Tu *sens* la
dépendance **requise** MTA → annuaire.
---
## Pour aller plus loin *(dépôt)*
- Rôles : `roles/serveur_postfix`, `roles/serveur_dovecot`, `roles/serveur_rspamd`.
- Conception + Étape B (déliverabilité publique) : `docs/courriel-conception.md`.
- Notifications système des nœuds : `client_smtp` (relais vers le MTA).

@ -0,0 +1,68 @@
# Infra as Code & idempotence
> **Unité d'apprentissage.** Moule : ① concept → ② Set-OPS → ③ transférable → ④ à toi de jouer.
---
## ① Le concept *(générique)*
**Infra as Code (IaC)** : décrire l'infrastructure **dans du code** (versionné, revu, reproductible)
plutôt qu'à la main. Le serveur devient le **résultat d'un fichier**, pas d'une suite de clics oubliés.
**Déclaratif vs impératif** :
- *impératif* = « fais ceci, puis cela » (une recette d'étapes) ;
- *déclaratif* = « voici l'**état voulu** » (le moteur trouve comment y arriver).
**Idempotence** : appliquer la **même** description **N fois** donne le **même** résultat. La 1ʳᵉ
exécution change des choses ; les suivantes ne changent **rien** (`changed=0`). C'est ce qui rend
l'IaC **sûre à rejouer**.
**Modèle plan → apply** : on décrit (plan), on **prévisualise** (dry-run), on **applique**. Tout est
en **contrôle de version** (git), donc auditable et réversible.
---
## ② Comment Set-OPS le fait
- **Ansible** = le moteur **déclaratif** (des *rôles* décrivant l'état voulu, idempotents).
- Le **plan** (`serveurs.yml`, `applications.yml`, `bases-donnees.yml`) décrit *quoi* déployer.
- `make instancier` **génère** l'inventaire statique depuis le plan.
- `make deployer` applique les rôles ; le `Vérifier` (dry-run) **prévisualise** d'abord.
- Tout vit dans **git** (ce dépôt) — reproductible, revu, réversible.
Preuve d'idempotence, vue partout cette session : redéployer un rôle déjà en place →
**`changed=0`**. Et un refactor « neutre » (ex. le binding annuaire) → `changed=0` aussi : *même
état voulu = aucune modification*.
---
## ③ Pourquoi c'est transférable
| Set-OPS | Équivalents ailleurs |
|---|---|
| Ansible | Terraform · Puppet · Chef · SaltStack · OpenTofu |
| plan → dry-run → apply | `terraform plan/apply`, tout workflow IaC |
| idempotence | **propriété fondamentale** de toute IaC sérieuse |
Tu as appris **le déclaratif, l'idempotence, plan→apply, l'infra versionnée** — pas « Ansible ».
---
## ④ À toi de jouer
1. **Sens l'idempotence.** Redéploie un rôle déjà en place (ex. via la GUI ou
`make deployer HOTE=…`) : la 2ᵉ fois, **`changed=0`**. Rien à faire = rien n'est touché.
2. **Le flux déclaratif.** Édite le plan (un serveur dans la GUI), `⚙ Appliquer le plan`
(instancier), puis `Vérifier` (dry-run) : tu **prévisualises** avant d'appliquer.
3. **La réversibilité.** `git diff` / `git checkout` sur le plan : l'état est **du code**, donc
annulable.
4. **Casse & répare.** Modifie à la main un fichier géré par un rôle (ex. un `.conf`), puis
redéploie : Ansible **rétablit l'état voulu** (le code gagne sur la dérive manuelle). Tu *sens*
que la source de vérité, c'est **le code**.
---
## Pour aller plus loin *(dépôt)*
- Le flux : `make instancier``make instancier-appliquer``make deployer` (ou la GUI).
- Le plan : `instance/plan/` ; les rôles : `roles/` ; l'autorité : `AGENTS.md`.
- Relations déclaratives entre entités : unité **Liaisons (bindings)**.

79
Liaisons-bindings.md Normal file

@ -0,0 +1,79 @@
# Liaisons (bindings)
> **Unité d'apprentissage.** Moule : ① concept → ② Set-OPS → ③ transférable → ④ à toi de jouer.
---
## ① Le concept *(générique)*
Un système réel n'est pas fait de pièces isolées, mais de **relations** : cette app *utilise* cette
base, ce serveur *fait confiance* à cette AC, ce nœud *envoie ses logs* à ce collecteur.
Deux façons de câbler ces relations :
- **En dur** — recopier l'adresse/le nom dans chaque config. Fragile : déplacer une pièce oblige à
éditer partout, et ça casse la portabilité.
- **En liaisons déclaratives** — on **déclare** « A est lié à B », et le **moteur résout** l'adresse
concrète au bon moment. Déplacer B ? On ne touche qu'un endroit.
> **Analogie NetScaler (Citrix ADC)** : tu *bind* un *service* à un *vserver*, une *policy* à un
> *vserver*, un *monitor* à un *service*. Tu ne codes pas des IP en dur — tu **relies des entités**,
> et l'appareil fait le reste. Les liaisons de Set-OPS, c'est exactement ce modèle.
Deux **axes** pour classer une liaison (indépendants) :
- **Niveau** : *app→app/base/domaine* (`liens`) ou *nœud→service de flotte* (`intégrations`).
- **Modalité** : **requise** (constitutive — sans elle, ça ne s'instancie pas) ou **optionnelle**
(élective — un choix, l'absence est légitime).
---
## ② Comment Set-OPS le fait
| Type | Où | Résolu en | Exemple |
|---|---|---|---|
| **`liens`** | `applications.yml` | **config** (host_vars, lookups) | Forgejo → sa base ; app → domaine exposé |
| **`intégrations`** | `serveurs.yml` | **groupe + agent client** | nœud → PKI, sauvegarde, métriques… |
Les **résolveurs partagés** font le pont : `resoudre_base` (app→base) et `resoudre_annuaire`
(app→annuaire) lisent un **registre** et bâtissent la connexion — le secret restant déréférencé
**dans le rôle**, jamais en clair.
La **modalité** structure la robustesse : une liaison **requise** absente → le moteur **refuse
d'instancier** (ex. une base sans serveur SQL). Une **optionnelle** absente → silence (ex. un nœud
sans `client_journal` marche très bien).
C'est **le** concept de Set-OPS : *tu déclares les liaisons, le moteur câble.*
---
## ③ Pourquoi c'est transférable
| Set-OPS | Équivalents ailleurs |
|---|---|
| liens/intégrations déclaratifs | **NetScaler bindings** · références de ressources Terraform |
| service ↔ backend | Kubernetes : Service↔Pods, Ingress↔Service |
| requis vs optionnel | dépendances *hard* vs *soft* (partout) |
Tu as appris **la relation déclarative, la résolution par un moteur, requis vs optionnel** — pas un
produit. C'est un **modèle mental** qui vaut de NetScaler à Kubernetes.
---
## ④ À toi de jouer
1. **Lis une liaison.** Ouvre `instance/plan/applications.yml` : une app avec `expose:` (liaison
*app→domaine*), et `serveurs.yml` : un nœud avec `integrations:` (liaison *nœud→service*).
2. **Vois-la se résoudre.** Après `make instancier`, regarde l'inventaire généré : la cible est
devenue une **valeur concrète** (FQDN, groupe) — le moteur a câblé.
3. **Requise vs optionnelle.** Compare : retirer `client_journal` d'un nœud → aucun problème
(optionnelle). Déclarer une base **sans** serveur → `make instancier`/la validation **échoue**
(requise). Tu *sens* la différence de modalité.
4. **Casse & répare.** Casse une liaison requise (ex. réfère une base à un serveur inexistant),
relance l'instanciation : **échec clair** *avant* tout déploiement. Corrige : ça passe. Le moteur
attrape le câblage manquant à ta place.
---
## Pour aller plus loin *(dépôt)*
- Conception + **taxonomie (niveau × modalité)** : `docs/bindings-conception.md` (§11).
- Résolveurs : `roles/resoudre_base`, `roles/resoudre_annuaire` ; registres : `instance/plan/`.
- Toutes les autres unités sont, au fond, des liaisons en action.

68
Métriques-et-journaux.md Normal file

@ -0,0 +1,68 @@
# Métriques & journaux
> **Unité d'apprentissage.** Moule : ① concept → ② Set-OPS → ③ transférable → ④ à toi de jouer.
---
## ① Le concept *(générique)*
**Observer** un système, c'est trois familles de données :
- **Métriques** : des **nombres dans le temps** (CPU, mémoire, requêtes/s) — des *séries temporelles*.
- **Journaux (logs)** : des **événements textuels** datés (« service démarré », « erreur X »).
- *(Traces : le parcours d'une requête — hors périmètre ici.)*
Deux **modèles de collecte** opposés, à bien distinguer :
- **Pull / scrape** : le collecteur **va chercher** les métriques chez chaque nœud (qui les *expose*).
- **Push / ship** : chaque nœud **envoie** ses journaux vers un collecteur central.
Le motif **agent/exporter** : sur chaque machine, un petit agent expose des métriques (*exporter*)
ou expédie des logs (*shipper*). Le serveur central agrège ; un tableau de bord **visualise**.
---
## ② Comment Set-OPS le fait
| Pièce | Modèle | Rôle |
|---|---|---|
| **Prometheus** (`serveur_prometheus`) | **PULL** | scrape `node_exporter` (installé par `client_metrique`) sur chaque nœud, port `:9100`. |
| **Loki** (`serveur_loki`) | **PUSH** | reçoit les journaux `journald` expédiés par `client_journal`. |
| **Grafana** (`serveur_grafana`) | — | tableaux de bord au-dessus des **deux** (au SSO). |
Le point-clé prouvé cette session : un serveur d'observabilité **sans agents** ne voit que
lui-même. En déployant `client_metrique`/`client_journal` (des **liaisons nœud, optionnelles**),
Grafana voit **toute la flotte**. *Serveur ≠ agent* : les deux sont nécessaires.
---
## ③ Pourquoi c'est transférable
| Set-OPS | Équivalents ailleurs |
|---|---|
| Prometheus (pull) | tout Prometheus, VictoriaMetrics, la logique **scrape** |
| Loki (push) | ELK/Elasticsearch, Graylog, la logique **ship** |
| Grafana | Kibana, Datadog, Grafana Cloud |
| exporter/shipper | motif **universel** (node_exporter, Fluent Bit, Vector…) |
Tu as appris **métriques vs logs, pull vs push, le motif agent** — pas « Prometheus ».
---
## ④ À toi de jouer
1. **Interroge les métriques** (sur obs-01) — combien de nœuds scrapés, tous **UP** ?
```bash
curl -s 'http://localhost:9090/api/v1/query?query=up{job="node"}' | python3 -m json.tool | grep -E 'instance|"1"'
```
2. **Vois les journaux** : `curl -s http://localhost:3100/loki/api/v1/label/host/values` → les nœuds
qui expédient leurs logs.
3. **Ouvre Grafana** (`https://grafana.lab.chezlepro.internal`) — métriques *et* logs au même endroit.
4. **Casse & répare.** Arrête `prometheus-node-exporter` sur un nœud : dans Prometheus, sa cible passe
**`up=0`** (DOWN). Redémarre : elle repasse UP. Tu *sens* que c'est **l'agent** qui nourrit le
serveur (modèle pull).
---
## Pour aller plus loin *(dépôt)*
- Rôles : `roles/serveur_prometheus`, `roles/serveur_loki`, `roles/serveur_grafana`.
- Agents : `roles/client_metrique` (node_exporter), `roles/client_journal` (→ Loki).
- Ces agents sont des **liaisons optionnelles** : unité **Liaisons**.

69
Reverse-proxy-et-TLS.md Normal file

@ -0,0 +1,69 @@
# Reverse-proxy & TLS
> **Unité d'apprentissage.** Moule : ① concept → ② Set-OPS → ③ transférable → ④ à toi de jouer.
---
## ① Le concept *(générique)*
Un **reverse-proxy** est un **point d'entrée unique** devant plusieurs services. Il :
- **route par nom** (`grafana.…` → tel backend, `forge.…` → tel autre) — via l'en-tête `Host` / **SNI** ;
- **termine le TLS** : il porte les certificats, parle HTTPS au client et (souvent) HTTP en interne ;
- centralise journaux, limites de débit, en-têtes de sécurité (et un **WAF** éventuel).
**Terminaison TLS** = le chiffrement s'arrête au proxy ; derrière, le réseau interne est de confiance.
Un seul endroit gère les certificats → simple et cohérent.
---
## ② Comment Set-OPS le fait
`serveur_nginx` déployé sur l'**edge** (`infra-edge`) est le reverse-proxy. Le point élégant :
l'**exposition est auto-dérivée**. Déclarer `expose: [icinga.lab.chezlepro.internal]` sur une app
génère **tout** :
```
expose ──> vhost nginx (route par nom)
──> SAN ajouté au certificat de l'edge (step-ca)
──> enregistrement A dans PowerDNS
──> alias plancher /etc/hosts
```
Le client parle **HTTPS vérifié** à l'edge ; l'edge relaie en **HTTP** au backend interne (Grafana,
Forgejo, Keycloak…). Une seule ligne déclarative, toute la chaîne câblée. C'est une **liaison**
(*app → domaine*) — voir l'unité *Liaisons*.
---
## ③ Pourquoi c'est transférable
| Set-OPS | Équivalents ailleurs |
|---|---|
| nginx reverse-proxy | HAProxy · Traefik · Caddy · Apache · Envoy |
| edge + terminaison TLS | tout load-balancer / ingress cloud, un NetScaler ADC |
| routage par SNI/Host | mécanisme **standard** de tout proxy HTTP |
Tu as appris **le reverse-proxy, le routage par nom, la terminaison TLS** — pas « nginx ».
---
## ④ À toi de jouer
1. **Route par nom.** Deux noms, un seul edge (`192.168.15.21`) :
```bash
curl -sI --resolve grafana.lab.chezlepro.internal:443:192.168.15.21 \
--cacert /etc/step/certs/root_ca.crt https://grafana.lab.chezlepro.internal/ | head -1
```
Change `grafana` en `forge` : même IP, **backend différent**. C'est le routage par SNI.
2. **Vois la terminaison TLS.** Le certificat présenté est celui de l'**edge** (avec les SAN des
exposés) : `openssl s_client -connect 192.168.15.21:443 -servername grafana.lab… | openssl x509 -noout -text | grep -A1 'Subject Alternative'`.
3. **Casse & répare.** Arrête le backend (ex. `systemctl stop grafana-server` sur obs-01) et rouvre
Grafana : l'edge répond **502 Bad Gateway** (le proxy est là, le service non). Redémarre : ça
remarche. Tu distingues **le proxy** de **ce qu'il sert**.
---
## Pour aller plus loin *(dépôt)*
- Rôle : `roles/serveur_nginx` ; les sites se déclarent côté nginx (`serveur_nginx_sites`).
- Machinerie d'exposition : `expositions_des_applications` (dérive vhost + SAN + A + plancher).
- Frontière **publique** (au-delà de l'edge interne) : `docs/` + Étape B (OPNsense).

65
Supervision-et-impact.md Normal file

@ -0,0 +1,65 @@
# Supervision & impact
> **Unité d'apprentissage.** Moule : ① concept → ② Set-OPS → ③ transférable → ④ à toi de jouer.
---
## ① Le concept *(générique)*
**Observabilité** (métriques/logs) = **passive** : on regarde des données. **Supervision** =
**active** : le système **fait des tests** (« le port 443 répond-il ? le disque est-il plein ? »),
tient un **état** (OK / WARNING / CRITICAL) et **alerte** quand ça se dégrade.
Distinction utile : Grafana te *montre* des tendances ; un moteur de supervision *décide* qu'un
service est en panne et *prévient*. Complémentaires, pas interchangeables.
**Modélisation d'impact métier** (BPM) : agréger des checks techniques en **services de haut
niveau**. « Le service *Courriel* est-il sain ? » = (Postfix **ET** Dovecot **ET** l'annuaire).
On raisonne en **impact**, pas en cases isolées.
---
## ② Comment Set-OPS le fait
La pile Icinga, en trois étages :
| Étage | Pièce | Rôle |
|---|---|---|
| **Moteur** | `serveur_icinga` (icinga2 + IcingaDB) | exécute les **checks**, tient l'**état**, alerte. |
| **UI** | `serveur_icingaweb2` | l'interface (états, acquittements, downtimes), **au SSO**. |
| **Impact** | module **BPM** | des **processus métier** qui roulent la santé de plusieurs checks en un état. |
Ce que Grafana ne fait **pas** : le BPM. « Grafana peut-il remplacer le BPM ? » → **non** : l'un
*visualise des mesures*, l'autre *modélise l'impact métier*. On veut **les deux**.
---
## ③ Pourquoi c'est transférable
| Set-OPS | Équivalents ailleurs |
|---|---|
| Icinga | Nagios · Zabbix · Checkmk · Sensu |
| checks actifs + alerting | modèle **universel** de la supervision |
| BPM / impact | *business service monitoring* (concept répandu) |
Tu as appris **supervision active vs observabilité passive, l'état, l'alerting, l'impact** — pas
« Icinga ».
---
## ④ À toi de jouer
1. **Ouvre Icinga Web 2** (`https://icinga.lab.chezlepro.internal`, via le SSO) : la liste des hôtes
et services **supervisés**, avec leur **état** (vert/jaune/rouge).
2. **Vois l'impact.** Menu *Business Processes* → « **Supervision Chezlepro** » : un processus qui
**agrège** des checks (load, procs, ping…) en un état roulé. C'est l'impact, pas une case.
3. **Casse & répare.** Provoque l'échec d'un check (ex. arrête un service surveillé) : l'état passe
**CRITICAL**, et le **processus BPM** qui en dépend **rougit** (l'impact remonte). Répare : tout
reverdit. Tu *sens* la différence entre *mesurer* et *superviser/alerter*.
---
## Pour aller plus loin *(dépôt)*
- Rôles : `roles/serveur_icinga` (moteur), `roles/serveur_icingaweb2` (UI + module BPM).
- SSO devant Icinga Web : `roles/serveur_oauth2_proxy` (passerelle) — unité **Identité & SSO**.
- Complément visuel : unité **Métriques & journaux** (Grafana).

@ -0,0 +1,75 @@
# Sécurité & durcissement
> **Unité d'apprentissage.** Moule : ① concept → ② Set-OPS → ③ transférable → ④ à toi de jouer.
---
## ① Le concept *(générique)*
Sécuriser un système, ce sont quelques principes qui se combinent :
- **Défense en profondeur** : plusieurs couches — si l'une cède, les autres tiennent.
- **Moindre privilège** : chacun (compte, service) n'a **que** les droits nécessaires.
- **Réduction de la surface d'attaque** : moins de services exposés = moins de portes.
- **Contrôle d'accès obligatoire (MAC)** : le noyau confine chaque programme (AppArmor/SELinux).
- **Audit** : tracer les événements sensibles pour pouvoir enquêter.
- **Anti-force-brute** : bloquer les tentatives répétées (fail2ban).
- **Pare-feu** : filtrer le trafic réseau.
- **Mises à jour** : combler les failles connues, automatiquement.
Aucune de ces couches ne suffit seule. Ensemble, elles rendent l'intrusion **coûteuse**.
---
## ② Comment Set-OPS le fait
Le **durcissement fait partie du socle** — il tourne sur **chaque** nœud (via `serveur_durci`),
pas en option :
| Couche | Rôle Set-OPS |
|---|---|
| MAC | `apparmor` |
| Audit | `auditd` |
| Anti-force-brute SSH | `fail2ban_ssh` |
| Durcissement noyau | `sysctl_hardening` |
| Pare-feu | `nftables_baseline` (*installé et préparé, désactivé par défaut*) |
| Mises à jour | `unattended_upgrades` |
| SSH | `ssh_baseline` + `ssh_hardening` (clé d'abord, `PermitRootLogin no`…) |
| Moindre privilège | compte technique `ansible` + `sudo_ansible` (pas de root direct) |
Nuance importante : le **pare-feu** est *préparé mais pas activé* dans le template — on l'active sur
un **clone/serveur final** avec des règles adaptées à son rôle (couper l'accès à l'aveugle = un
risque). Prudence par conception.
---
## ③ Pourquoi c'est transférable
| Set-OPS | Équivalents ailleurs |
|---|---|
| AppArmor | SELinux · les *security modules* Linux |
| fail2ban / auditd / sysctl | outils **standards** de tout durcissement Linux |
| démarche par couches | **CIS Benchmarks**, ANSSI, guides d'OS — mêmes principes |
Tu as appris **la défense en profondeur, le moindre privilège, MAC, l'audit** — pas « AppArmor ».
---
## ④ À toi de jouer
1. **Constate les couches** (sur n'importe quel nœud) :
```bash
aa-status | head # AppArmor : profils chargés
systemctl is-active auditd fail2ban
sysctl net.ipv4.conf.all.rp_filter # un durcissement noyau parmi d'autres
```
2. **Moindre privilège** : `PermitRootLogin` est à `no`, l'accès se fait par le compte `ansible` +
clé SSH. Vérifie : `sshd -T | grep -E 'permitrootlogin|passwordauthentication'`.
3. **Casse & répare (avec prudence, en lab).** Assouplis **un** réglage sysctl, observe, puis
**remets-le**. Tu *sens* que chaque ligne de durcissement ferme une porte précise.
---
## Pour aller plus loin *(dépôt)*
- Rôles du socle durci : `roles/apparmor`, `auditd`, `fail2ban_ssh`, `sysctl_hardening`,
`nftables_baseline`, `ssh_hardening`, `unattended_upgrades`
- Actions destructives (SSH, pare-feu) exigent une **confirmation explicite** : voir `CLAUDE.md`/`AGENTS.md`.

@ -0,0 +1,69 @@
# Virtualisation & clonage
> **Unité d'apprentissage.** Moule : ① concept → ② Set-OPS → ③ transférable → ④ à toi de jouer.
---
## ① Le concept *(générique)*
La **virtualisation** fait tourner plusieurs **machines virtuelles (VM)** — chacune avec son OS —
sur un seul serveur physique (l'**hyperviseur**). Isolation, densité, souplesse.
**Image / golden template** : au lieu de réinstaller chaque VM, on prépare **une** image de
référence, propre et durcie, puis on la **clone**. Rapide et **reproductible**.
**cloud-init** : au premier démarrage d'un clone, il lui donne son **identité initiale** (nom d'hôte,
IP, clé SSH, agrandissement du disque). C'est *l'amorçage*, pas la configuration complète.
Idée-force : la VM devient **jetable/reconstructible**. Ce qui est précieux, c'est la **donnée**
(voir *Sauvegardes*), pas la machine.
---
## ② Comment Set-OPS le fait
- **Proxmox** = l'hyperviseur (cluster).
- Un **golden template** (`basiqueChezlepro`) : Debian minimal, durci, avec le compte technique
`ansible`, qemu-guest-agent, cloud-init… — préparé **une fois**.
- Chaque nœud = un **clone** du template. `cloud-init` pose l'identité (hostname, IP dérivée de la
nomenclature, clé SSH).
- **Puis** Set-OPS/Ansible fait la **vraie** configuration (les rôles).
Séparation nette, à retenir :
```
Proxmox + cloud-init ──> identité initiale de la VM
Set-OPS + Ansible ──> configuration réelle du serveur
```
C'est *pour ça* que l'infra est reconstructible : cloner + reconfigurer = quelques minutes.
---
## ③ Pourquoi c'est transférable
| Set-OPS | Équivalents ailleurs |
|---|---|
| Proxmox (KVM) | VMware · Hyper-V · KVM/libvirt · nuage (EC2, GCE…) |
| golden template | AMI, image cloud, **Packer** |
| cloud-init | **standard** de toutes les images cloud |
Tu as appris **VM/hyperviseur, image de référence, cloud-init, l'infra jetable** — pas « Proxmox ».
---
## ④ À toi de jouer
1. **Regarde un clone.** Dans la GUI (`make inventaire-ui`), un serveur *actif* a été **cloné** du
template (bouton « 🖥 Créer la VM »). Son VMID/IP sont **dérivés** de la nomenclature.
2. **Vois l'identité cloud-init.** Sur un nœud : `cloud-init query hostname`, `hostname -f`, et
l'agrandissement du disque racine (`df -h /`).
3. **Sépare les deux couches.** cloud-init a posé *l'identité* ; tout le reste (paquets, services,
durcissement) vient d'**Ansible**. Le template, lui, ne contient **aucune** donnée de clone.
4. **Casse & répare (mentalement + lab).** Supprime un nœud non critique et **reclone-le** depuis le
template, puis redéploie : il revient à l'identique. Tu *sens* que la machine est **reconstructible**.
---
## Pour aller plus loin *(dépôt)*
- Playbooks Proxmox : `playbooks/proxmox/` ; rôle `cloud_init` ; préparation du modèle : `playbooks/modeles_vm/`.
- Golden template = actif central (jamais jetable, cloné pour chaque VM).
- Ce qui est précieux = la **donnée** : unité **Sauvegardes**.

@ -4,28 +4,28 @@
**Unités d'apprentissage**
*Fondations*
- [Identité & SSO](Identité-et-SSO)
- [PKI & confiance](PKI-et-confiance)
- [DNS & résolution de noms](DNS-et-résolution)
- [Identité & SSO](Identité-et-SSO)
- [PKI & confiance](PKI-et-confiance)
- [DNS & résolution de noms](DNS-et-résolution)
*Communication*
- Reverse-proxy & TLS *(à venir)*
- Courriel (SMTP/IMAP) *(à venir)*
- [Reverse-proxy & TLS](Reverse-proxy-et-TLS)
- [Courriel (SMTP/IMAP)](Courriel)
*Données*
- Bases de données *(à venir)*
- Cache *(à venir)*
- [Sauvegardes (3-2-1)](Sauvegardes)
- [Bases de données](Bases-de-données)
- [Cache](Cache)
- [Sauvegardes (3-2-1)](Sauvegardes)
*Observabilité*
- Métriques & journaux *(à venir)*
- Supervision & impact *(à venir)*
- [Métriques & journaux](Métriques-et-journaux)
- [Supervision & impact](Supervision-et-impact)
*Socle & méthode*
- Virtualisation & clonage *(à venir)*
- Sécurité & durcissement *(à venir)*
- Infra as Code & idempotence *(à venir)*
- Liaisons (bindings) *(à venir)*
- [Virtualisation & clonage](Virtualisation-et-clonage)
- [Sécurité & durcissement](Sécurité-et-durcissement)
- [Infra as Code & idempotence](Infra-as-Code-et-idempotence)
- [Liaisons (bindings)](Liaisons-bindings)
**Opérations**
- Runbooks *(à venir)*