Retirer 3 rôles legacy (serveur_sendmail, client_dns, client_ldap) + nettoyage

Supprimés (supersédés / hors-conception) : serveur_sendmail (→ Postfix),
client_dns (→ plancher + client_unbound), client_ldap (login LDAP OS, hors
design). Rôles + playbooks de groupe retirés.

Nettoyage des références :
- dependances-groupes.yml : entrées client_dns/client_ldap retirées + entrées
  mortes des scaffoldings (nextcloud/collabora/client_supervision) ; deps
  périmées corrigées (client_smtp → serveur_postfix ; serveur_keycloak →
  serveur_postgresql, la raison parlait à tort de Nextcloud).
- 6 modèles d'exemple : app mail serveur_sendmail → serveur_postfix.
- README, AGENTS : listes/glossaire nettoyés.
- catalogue-services : listes, tables, roadmap ; note « rôles retirés ».
- nomenclature-vm : infra-mail-01 → serveur_dovecot (était faux).
- courriel-conception, dns-interne (re-ciblé client_unbound), pouvoirs,
  intrants, READMEs (client_smtp/forgejo/openldap/unbound).

ansible-lint : 0 échec (366 fichiers). instancier OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-07-04 12:14:04 -04:00
parent bcab586845
commit e006dee693
39 changed files with 56 additions and 532 deletions

View file

@ -333,7 +333,6 @@ Les concepts comme socle Debian ou durcissement commun doivent être représent
```text
serveur_debian -> socle commun Debian
serveur_durci -> durcissement commun
client_dns -> intégration cliente DNS
client_pki -> intégration cliente PKI / ACME
```
@ -377,14 +376,11 @@ serveur_debian
Les groupes spécialisés doivent s'ajouter selon les besoins réels, par exemple :
```text
client_dns
client_pki
client_ldap
client_supervision
client_metrique
serveur_web_frontal
serveur_postgresql
serveur_prometheus
serveur_keycloak
```
Ne pas cibler `all` par défaut pour un playbook qui ne s'applique pas réellement à tous les hôtes.

View file

@ -121,7 +121,7 @@ Chaque groupe opérationnel doit avoir son playbook homonyme dans `playbooks/gro
La conformité normale des VM passe par ces playbooks de groupes. Les rôles de socle et de durcissement sont appliqués par `serveur_debian` et `serveur_durci`, pas par des playbooks de couches séparés.
Les groupes opérationnels avec des hôtes, comme `serveur_web_frontal` ou `client_dns`, sont validés contre `playbooks/groupes/` par les commandes d'inventaire.
Les groupes opérationnels avec des hôtes, comme `serveur_keycloak` ou `client_pki`, sont validés contre `playbooks/groupes/` par les commandes d'inventaire.
Le catalogue des services et intégrations prévus est dans `docs/catalogue-services.md`.

View file

@ -24,9 +24,9 @@ Un service central peut partager un hôte avec d'autres services de la même fon
> de la colonne « Rôle » des tables.
**Implémentés** (`tasks` + `templates` + `handlers`, validés) : `serveur_step_ca`,
`client_pki`, `serveur_powerdns`, `client_dns`, `serveur_openldap`, `client_ldap`,
`client_pki`, `serveur_powerdns`, `serveur_openldap`,
`serveur_keycloak`, `serveur_postgresql`, `serveur_redis`, `serveur_nginx`,
`serveur_sendmail`, `client_smtp`, `serveur_prometheus`, `client_metrique`, `serveur_loki`,
`client_smtp`, `serveur_prometheus`, `client_metrique`, `serveur_loki`,
`client_journal`, `serveur_grafana`, `serveur_icinga`, `serveur_forgejo`. Plus le socle et
le durcissement, appliqués par `serveur_debian` / `serveur_durci`.
@ -48,7 +48,11 @@ icinga2 + icingadb + redis dédié, base PostgreSQL via registre — supervise,
via `serveur_oauth2_proxy``testmail` se connecte par le SSO, voit la supervision, et un processus
métier BPM rend un état). **Pile Icinga complète : moteur + Web 2 + BPM, au SSO.** Plus la passerelle
**`serveur_oauth2_proxy`** (oauth2-proxy) : SSO OIDC générique réutilisable pour toute app sans OIDC
natif. Restent « code non éprouvé » : `serveur_sendmail`.
natif. Plus les **agents de flotte** `client_metrique` / `client_journal` / `client_smtp` (éprouvés
sur 4 nœuds : Prometheus scrape la flotte, Loki collecte les logs, relais courrier système). **Tous
les rôles vivants sont éprouvés.** *Rôles retirés (2026-07-04, supersédés/hors-conception)* :
`serveur_sendmail` (→ Postfix), `client_dns` (→ plancher + `client_unbound`), `client_ldap` (login
LDAP OS, hors design).
> **Lacunes connues sur Keycloak** (déployé mais pas complet) : la **fédération LDAP** (Keycloak
> → OpenLDAP, modèle d'identité A) n'est **pas encore automatisée** dans le rôle ; l'**edge nginx**
@ -77,7 +81,6 @@ en rôles `serveur_*` normaux avec leur playbook de groupe.
| Prometheus | `serveur_prometheus` | `playbooks/groupes/serveur_prometheus.yml` | `prometheus` |
| Grafana | `serveur_grafana` | `playbooks/groupes/serveur_grafana.yml` | `grafana` |
| Forgejo | `serveur_forgejo` | `playbooks/groupes/serveur_forgejo.yml` | `forgejo` |
| Sendmail MTA | `serveur_sendmail` | `playbooks/groupes/serveur_sendmail.yml` | `sendmail` |
| step-ca | `serveur_step_ca` | `playbooks/groupes/serveur_step_ca.yml` | `step_ca` |
| PowerDNS | `serveur_powerdns` | `playbooks/groupes/serveur_powerdns.yml` | `serveur_powerdns` |
| Redis | `serveur_redis` | `playbooks/groupes/serveur_redis.yml` | `redis` |
@ -123,9 +126,7 @@ Dépendance d'intégration prévue : `serveur_web_frontal` devra publier via `se
| Intégration | Groupe | Playbook | Rôle |
| --- | --- | --- | --- |
| Résolution DNS interne | `client_dns` | `playbooks/groupes/client_dns.yml` | `client_dns` |
| Confiance PKI / ACME | `client_pki` | `playbooks/groupes/client_pki.yml` | `client_pki` |
| Authentification LDAP | `client_ldap` | `playbooks/groupes/client_ldap.yml` | `client_ldap` |
| Supervision Icinga | `client_supervision` | `playbooks/groupes/client_supervision.yml` | `client_supervision` |
| Métriques Prometheus | `client_metrique` | `playbooks/groupes/client_metrique.yml` | `client_metriques` |
| Journaux vers Loki | `client_journal` | `playbooks/groupes/client_journal.yml` | `client_journaux` |
@ -139,7 +140,6 @@ L'ordre ci-dessous privilégie les dépendances structurantes avant les applicat
1. `serveur_powerdns`
- Service central : DNS interne autoritaire et/ou résolution interne selon le design retenu.
- Intégration à prévoir : `client_dns`.
- Raison : les autres intégrations auront besoin de noms stables plutôt que d'adresses IP.
2. `serveur_step_ca`
@ -152,8 +152,8 @@ L'ordre ci-dessous privilégie les dépendances structurantes avant les applicat
- Intégration à prévoir : publication des services HTTP derrière le proxy.
- Raison : plusieurs services seront consommés par navigateur ou API et doivent passer par un point d'entrée cohérent.
4. `serveur_sendmail`
- Service central : relais SMTP sortant.
4. `serveur_postfix`
- Service central : MTA (courriel entrant + sortant interne) + relais SMTP.
- Intégration à prévoir : `client_smtp`.
- Raison : les notifications, réinitialisations de mot de passe et alertes doivent fonctionner tôt.
@ -165,9 +165,9 @@ L'ordre ci-dessous privilégie les dépendances structurantes avant les applicat
- Raison : Keycloak, Grafana, Icinga Web 2, Forgejo et Nextcloud peuvent dépendre de PostgreSQL.
6. `serveur_openldap`
- Service central : annuaire interne.
- Intégration à prévoir : `client_ldap`.
- Raison : l'identité Unix et l'annuaire doivent exister avant les intégrations d'authentification avancées.
- Service central : annuaire interne (source de vérité des identités).
- Consommateurs : Keycloak (fédération/SSO), courriel (Postfix/Dovecot), apps.
- Raison : l'annuaire doit exister avant l'identité fédérée et le courriel.
7. `serveur_keycloak`
- Service central : SSO/OIDC/SAML.

View file

@ -15,9 +15,10 @@
| PKI | **Deux CA distinctes** (voir §6) : Let's Encrypt pour les faces publiques, **step_ca** pour l'interne. |
| Démarche | **Deux étapes** (voir §11) : **(A) fonctionnement INTERNE** d'abord (step_ca, LDAP, SMTP/IMAP internes, zéro dépendance publique) ; **(B) fonctionnement EXTERNE** ensuite (Namespro, Let's Encrypt, reprise du MX `.53`). |
Le rôle existant `serveur_sendmail` (relais sortant Postfix, sans boîtes) **reste** pour le
courrier de notification système (via `client_smtp`/msmtp). Il ne fait pas partie de ce
service et ne le remplace pas.
Le courrier de **notification système** des nœuds (cron, alertes) est relayé vers le MTA
`serveur_postfix` (edge-mta) via `client_smtp`/msmtp. C'est distinct de ce service de boîtes
et ne le remplace pas. *(Note : l'ancien rôle `serveur_sendmail` a été retiré — supersédé par
Postfix.)*
> **Historique — pivot depuis Stalwart (2026-07-02).** On avait d'abord choisi Stalwart
> (binaire unique, moderne). Le prototypage a révélé un projet **jeune et volatil** :
@ -170,8 +171,9 @@ _dmarc TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@chezlepro.
la soumission Postfix), backend **LDAP**, TLS step_ca.
- `serveur_rspamd` — anti-spam, **signature DKIM**, greylisting ; branché à Postfix par milter.
- `serveur_postfix` en **mode relais** (paramètre) pour le MX de secours.
- **Intégrations** des nœuds mail : `client_ldap` (auth/annuaire), `client_pki` (certs
internes), `client_dns`.
- **Intégrations** des nœuds mail : `client_pki` (certs internes), `client_backup`,
`client_metrique` / `client_journal` (observabilité). L'annuaire est résolu par
`resoudre_annuaire` (côté rôle), pas une intégration OS.
- **Secrets (voûte)** : bind LDAP, **clé privée DKIM**, éventuel secret ACME (Étape B) —
via `vault_*`, câblés aux rôles.

View file

@ -1,30 +1,11 @@
---
groupes:
client_dns:
requiert_groupes_actifs: []
raison: "Dependance molle : la resolution interne repose d'abord sur le plancher
/etc/hosts (role hosts_statiques du socle). client_dns ne configure un resolver
que si un DNS interne existe ; sinon il est inerte. Aucun prerequis bloquant."
surveillance: "Verifier /etc/hosts a jour ; DNS interne optionnel (externe/dynamique)."
client_pki:
requiert_groupes_actifs:
- serveur_step_ca
raison: "La confiance CA et ACME client dependent de l'autorite interne."
surveillance: "Verifier validite CA, emission ACME et expiration des certificats."
client_ldap:
requiert_groupes_actifs:
- serveur_openldap
raison: "La configuration NSS/PAM/SSSD depend de l'annuaire LDAP."
surveillance: "Verifier bind LDAP, latence et expiration des certificats LDAP."
client_supervision:
requiert_groupes_actifs:
- serveur_icinga
raison: "Les agents ou checks clients doivent se rattacher a une plateforme Icinga active."
surveillance: "Verifier enregistrement des hotes, fraicheur des checks et notifications."
client_metrique:
requiert_groupes_actifs:
- serveur_prometheus
@ -39,8 +20,8 @@ groupes:
client_smtp:
requiert_groupes_actifs:
- serveur_sendmail
raison: "Les notifications locales doivent relayer vers un MTA actif."
- serveur_postfix
raison: "Les notifications locales doivent relayer vers un MTA actif (Postfix)."
surveillance: "Verifier file d'attente, relais SMTP et echecs de livraison."
serveur_keycloak:
@ -70,18 +51,3 @@ groupes:
raison: "Forgejo depend d'une base, d'une publication HTTP(S) et d'un relais courriel (MTA Postfix)."
surveillance: "Verifier HTTP(S), base, files Git et envoi courriel."
serveur_nextcloud:
requiert_groupes_actifs:
- serveur_postgresql
- serveur_redis
- serveur_nginx
- serveur_sendmail
raison: "Nextcloud depend d'une base, d'un cache, d'un frontal web et du courriel."
surveillance: "Verifier jobs, base, Redis, HTTP(S), stockage et courriel."
serveur_collabora:
requiert_groupes_actifs:
- serveur_nextcloud
- serveur_nginx
raison: "Collabora est expose via le frontal web et integre a Nextcloud."
surveillance: "Verifier connectivite Nextcloud, websocket et disponibilite HTTP(S)."

View file

@ -69,7 +69,6 @@ la somme. Le socle (`serveur_debian`/`serveur_durci`) et les groupes d'état son
| --- | --- | --- | --- |
| serveur_step_ca | 1 | 256 | 2 |
| serveur_powerdns | 1 | 512 | 2 |
| serveur_sendmail | 1 | 512 | 5 |
| serveur_nginx | 1 | 512 | 3 |
| serveur_openldap | 1 | 512 | 3 |
| serveur_keycloak | 2 | 1536 | 5 |

View file

@ -6,17 +6,17 @@ Le service DNS interne est la premiere capacite de plateforme.
> `serveur_debian`) genere `/etc/hosts` sur **chaque** VM depuis l'inventaire : tout
> l'ecosysteme se resout par nom **meme serveur DNS eteint** (et au bootstrap, avant
> que PowerDNS ne soit la). PowerDNS devient une **commodite** (zone, externe,
> dynamique), plus un point de defaillance : la dependance `client_dns -> powerdns`
> est **molle** (client_dns est inerte si aucun DNS interne n'existe).
> dynamique), plus un point de defaillance. Le resolveur local `client_unbound` est
> **optionnel** (opt-in, avec bascule validee) : sans lui, le plancher `/etc/hosts` suffit.
## Groupes
```text
serveur_powerdns -> service DNS central PowerDNS Authoritative
client_dns -> integration cliente DNS
client_unbound -> resolveur local optionnel (opt-in, bascule validee)
```
`client_dns` depend de `serveur_powerdns` dans `docs/dependances-groupes.yml`.
`client_unbound` (résolveur local optionnel) peut viser PowerDNS en stub-zone + récursion.
## Zone initiale
@ -65,22 +65,20 @@ Raison :
Quand `serveur_postgresql` sera stable, il sera possible de migrer vers un backend SQL si le besoin operationnel le justifie.
## Clients DNS
## Résolveur local (optionnel)
Le role `client_dns` valide :
Le role `client_unbound` (opt-in) installe un résolveur récursif local qui, en stub-zone,
délègue les noms internes à PowerDNS et récurse le reste.
- qu'un serveur `serveur_powerdns` actif existe ;
- que la zone repond a une requete SOA ;
- que le nom de l'hote existe dans la zone.
La modification du resolver local est protegee :
La bascule du resolver local est **protegee** (le role valide qu'Unbound répond AVANT de
basculer `/etc/resolv.conf`) :
```yaml
client_dns_apply: true
client_dns_confirm: true
client_unbound_apply: true
client_unbound_confirm: true
```
Sans ces deux variables, le role valide les prerequis mais ne modifie pas `/etc/resolv.conf`.
Sans ces deux variables, le role prépare Unbound mais ne modifie pas `/etc/resolv.conf`.
Cette protection est volontaire : une mauvaise configuration DNS peut couper la resolution de noms.

View file

@ -36,10 +36,10 @@ nftables baseline · fail2ban SSH · auditd · AppArmor · sysctl · unattended-
journald (rétention) · core_dumps · systemd_ssh_auto.
### F. Endpoints des services centraux (les rôles `client_*` en dérivent)
- DNS interne (`client_dns_nameservers`, zone = `domaine_interne`).
- DNS interne : plancher `/etc/hosts` (`hosts_statiques`) + PowerDNS + `client_unbound` (opt-in).
- AC/PKI (`client_pki_ca_url` → infra-pki, provisioner).
- IdM/LDAP (`client_ldap_uri` → idm, base DN dérivé).
- Relais courriel (`client_smtp_relais` → infra-mail, port 25).
- IdM/LDAP : annuaire résolu par `resoudre_annuaire` (hôte + base DN dérivés du domaine).
- Relais courriel (`client_smtp_relais` → edge-mta, MTA Postfix, port 25).
- Métriques (node_exporter `:9100`).
- Journaux (`client_journal_loki_url` → obs).
- Temps (NTP) : **implicite** (pool Debian par défaut — aucun intrant configuré).
@ -78,7 +78,7 @@ domaines publics, `edge`, autorité DNS, FQDN exposés.
| Secrets Vault | **Constante** 🔒 | — (gérés à part, jamais en clair) |
| `chezlepro_timezone` | Défaut | par hôte (rare) |
| `proxmox_clone_noeud` / `stockage` / `pont` | Défaut | par hôte (`serveurs.yml`) |
| DNS internes (`client_dns_nameservers`) | Défaut | par hôte / groupe |
| DNS internes (plancher `/etc/hosts` + PowerDNS + `client_unbound`) | Défaut | par hôte / groupe |
| Politiques durcissement (SSH, nftables, fail2ban, journald…) | Défaut | par hôte / groupe |
| Relais SMTP, TLS internes | Défaut | par hôte / groupe |
| `ciuser`, compte `ansible` | Défaut | rarement surchargé |

View file

@ -45,7 +45,7 @@ Les anciens noms de test `web-01` et `web-02` sont retirés. Ils ne doivent pas
| --- | --- |
| `infra-pki-01` | `serveur_step_ca` |
| `infra-edge-01` | `serveur_nginx` |
| `infra-mail-01` | `serveur_sendmail` |
| `infra-mail-01` | `serveur_dovecot` (mail-store) |
| `infra-dns-01` | `serveur_powerdns` |
| `idm-01` | `serveur_openldap`, `serveur_keycloak` |
| `data-01` | `serveur_postgresql`, `serveur_redis` |

View file

@ -92,7 +92,7 @@ prouvés.
- **Forge logicielle** : `serveur_forgejo`.
- **Observabilité** : `serveur_prometheus`, `serveur_grafana`, `serveur_loki`, `serveur_icinga`,
avec les clients `client_metrique`, `client_journal`, `client_supervision`.
- **Intégrations transverses** : `client_ldap`, `client_dns`, `client_smtp`.
- **Intégrations transverses** : `client_pki`, `client_backup`, `client_smtp`, `client_metrique`, `client_journal`, `client_unbound`.
- **Méta-rôles d'agrégation** : `identity`, `applications`, `database`, `web`, `monitoring`,
`backup`, `storage`.

View file

@ -7,7 +7,7 @@ applications:
groupe: serveur_nginx
hote: infra-edge-01
sendmail:
groupe: serveur_sendmail
groupe: serveur_postfix
hote: infra-mail-01
powerdns:
groupe: serveur_powerdns

View file

@ -7,7 +7,7 @@ applications:
groupe: serveur_nginx
hote: infra-edge-01
sendmail:
groupe: serveur_sendmail
groupe: serveur_postfix
hote: infra-mail-01
powerdns:
groupe: serveur_powerdns

View file

@ -7,7 +7,7 @@ applications:
groupe: serveur_nginx
hote: infra-edge-01
sendmail:
groupe: serveur_sendmail
groupe: serveur_postfix
hote: infra-mail-01
powerdns:
groupe: serveur_powerdns

View file

@ -7,7 +7,7 @@ applications:
groupe: serveur_nginx
hote: infra-edge-01
sendmail:
groupe: serveur_sendmail
groupe: serveur_postfix
hote: infra-mail-01
powerdns:
groupe: serveur_powerdns

View file

@ -2,7 +2,7 @@
applications:
pki: { groupe: serveur_step_ca, hote: infra-pki-01 }
edge: { groupe: serveur_nginx, hote: infra-edge-01 }
mail: { groupe: serveur_sendmail, hote: infra-mail-01 }
mail: { groupe: serveur_postfix, hote: infra-mail-01 }
dns: { groupe: serveur_powerdns, hote: infra-dns-01 }
bdd: { groupe: serveur_postgresql, hote: data-01, port: 5432 }
cache: { groupe: serveur_redis, hote: data-01 }

View file

@ -7,7 +7,7 @@ applications:
groupe: serveur_nginx
hote: infra-edge-01
sendmail:
groupe: serveur_sendmail
groupe: serveur_postfix
hote: infra-mail-01
powerdns:
groupe: serveur_powerdns

View file

@ -1,15 +0,0 @@
---
- name: Appliquer le groupe client_dns
hosts: client_dns
become: true
gather_facts: true
pre_tasks:
- name: Vérifier que la cible est Debian
ansible.builtin.assert:
that:
- ansible_facts.distribution == "Debian"
fail_msg: "Ce playbook est prévu pour Debian."
roles:
- client_dns

View file

@ -1,15 +0,0 @@
---
- name: Appliquer le groupe client_ldap
hosts: client_ldap
become: true
gather_facts: true
pre_tasks:
- name: Vérifier que la cible est Debian
ansible.builtin.assert:
that:
- ansible_facts.distribution == "Debian"
fail_msg: "Ce playbook est prévu pour Debian."
roles:
- client_ldap

View file

@ -1,15 +0,0 @@
---
- name: Appliquer le groupe serveur_sendmail
hosts: serveur_sendmail
become: true
gather_facts: true
pre_tasks:
- name: Vérifier que la cible est Debian
ansible.builtin.assert:
that:
- ansible_facts.distribution == "Debian"
fail_msg: "Ce playbook est prévu pour Debian."
roles:
- serveur_sendmail

View file

@ -1,16 +0,0 @@
# Role `client_dns`
Valide et configure l'integration DNS cliente vers le service PowerDNS interne.
Par defaut, le role valide les prerequis mais ne modifie pas le resolver local.
La modification DNS est volontairement protegee, car une mauvaise configuration
peut couper la resolution de noms.
Pour appliquer la configuration resolver :
```yaml
client_dns_apply: true
client_dns_confirm: true
```
Le serveur DNS requis vient du groupe `serveur_powerdns`.

View file

@ -1,9 +0,0 @@
---
client_dns_apply: false
client_dns_confirm: false
client_dns_zone: "{{ domaine_interne }}"
client_dns_search_domains:
- "{{ client_dns_zone }}"
client_dns_nameservers: []
client_dns_resolv_conf_path: "/etc/resolv.conf"
client_dns_resolv_conf_header: "Gere par Ansible Set-OPS - client_dns"

View file

@ -1,70 +0,0 @@
---
- name: Déterminer les serveurs DNS internes depuis l'inventaire
ansible.builtin.set_fact:
client_dns_effective_nameservers: >-
{{
client_dns_nameservers
if (client_dns_nameservers | length > 0)
else (
groups.get('serveur_powerdns', [])
| map('extract', hostvars, 'ansible_host')
| select('defined')
| list
)
}}
- name: Sans DNS interne, s'appuyer sur le plancher /etc/hosts (résolution garantie)
ansible.builtin.debug:
msg: >-
Aucun serveur DNS interne déclaré : la résolution interne repose sur le
plancher /etc/hosts (rôle hosts_statiques). Configuration du resolver ignorée.
when: client_dns_effective_nameservers | length == 0
- name: Installer les outils de diagnostic DNS
ansible.builtin.apt:
name: dnsutils
state: present
update_cache: true
cache_valid_time: 3600
# Les tâches ci-dessous ne s'exécutent que si un DNS interne existe.
# Sinon /etc/hosts (socle) assure déjà la résolution interne : dépendance molle.
- name: Valider la zone DNS interne sur le serveur primaire
ansible.builtin.command:
cmd: "dig @{{ client_dns_effective_nameservers[0] }} {{ client_dns_zone }} SOA +short"
register: client_dns_soa_check
changed_when: false
failed_when: client_dns_soa_check.stdout | trim == ""
when: client_dns_effective_nameservers | length > 0
- name: Refuser la modification DNS sans confirmation explicite
ansible.builtin.assert:
that:
- client_dns_confirm | bool
fail_msg: "Modification DNS refusee: definir client_dns_confirm=true pour modifier le resolver."
when:
- client_dns_apply | bool
- client_dns_effective_nameservers | length > 0
- name: Configurer le resolver client
ansible.builtin.template:
src: resolv.conf.j2
dest: "{{ client_dns_resolv_conf_path }}"
owner: root
group: root
mode: "0644"
backup: true
when:
- client_dns_apply | bool
- client_dns_confirm | bool
- client_dns_effective_nameservers | length > 0
- name: Valider la résolution du nom local dans la zone interne
ansible.builtin.command:
cmd: "dig @{{ client_dns_effective_nameservers[0] }} {{ inventory_hostname }}.{{ client_dns_zone }} A +short"
register: client_dns_host_check
changed_when: false
failed_when: client_dns_host_check.stdout | trim == ""
when:
- ansible_host is defined
- client_dns_effective_nameservers | length > 0

View file

@ -1,8 +0,0 @@
# {{ client_dns_resolv_conf_header }}
{% for nameserver in client_dns_effective_nameservers %}
nameserver {{ nameserver }}
{% endfor %}
{% if client_dns_search_domains | length > 0 %}
search {{ client_dns_search_domains | join(' ') }}
{% endif %}
options timeout:2 attempts:2 rotate

View file

@ -1,35 +0,0 @@
# client_ldap
Intégration cliente **identité utilisateur** : l'hôte authentifie les utilisateurs
via l'annuaire central `serveur_openldap`, grâce à **SSSD** (NSS + PAM).
## Rôle
- Installe `sssd`, `sssd-ldap`, `libnss-sss`, `libpam-sss`.
- Déploie `/etc/sssd/sssd.conf` (`0600`) pointant vers OpenLDAP (`id_provider`/`auth_provider = ldap`).
- Active `sss` dans `/etc/nsswitch.conf` (passwd, group, shadow).
- Active la **création automatique du répertoire personnel** (`pam-auth-update --enable mkhomedir`).
- `libpam-sss` active automatiquement le module PAM `sss`.
## Effet
Après ce rôle, les comptes de l'annuaire interne peuvent se connecter à l'hôte
(SSH, console) et leur home est créé à la première connexion. Couplé à `client_pki`
(identité machine), l'écosystème a une authentification **machines + utilisateurs** centralisée.
## Variables principales
| Variable | Défaut | Rôle |
| --- | --- | --- |
| `client_ldap_uri` | `ldap://idm-01.exemple.internal` | URI de l'annuaire |
| `client_ldap_base_dn` | `dc=exemple,dc=internal` | Base de recherche |
| `client_ldap_bind_dn` | `""` (anonyme) | Compte de lecture (optionnel, mdp via Vault) |
| `client_ldap_tls_reqcert` | `never` | Validation TLS (→ `demand` avec LDAPS) |
## Notes / limites
- **Bind anonyme** par défaut : suppose une lecture publique de l'annuaire. Pour un
bind dédié, définir `client_ldap_bind_dn` + `client_ldap_bind_password` (Vault) et
créer le compte de service dans l'annuaire.
- **LDAP en clair** sur le réseau interne pour l'instant ; basculer en **LDAPS** quand
OpenLDAP exposera un certificat (step_ca), avec `client_ldap_tls_reqcert: demand`.
- Les entrées utilisateurs/groupes (POSIX) doivent exister dans l'annuaire (gestion d'identité).
## Prérequis
- Dépendance `client_ldap requiert serveur_openldap actif` (déjà dans `docs/dependances-groupes.yml`).

View file

@ -1,25 +0,0 @@
---
client_ldap_paquets:
- sssd
- sssd-ldap
- libnss-sss
- libpam-sss
- ldap-utils
client_ldap_service: "sssd"
client_ldap_domaine: "{{ domaine_interne.split('.') | first }}"
# uri + base_dn : fournis par le rôle partagé resoudre_annuaire (tasks « Adopter »).
# Rôle DORMANT (login LDAP niveau OS via SSSD, non câblé). L'activer requiert client_pki
# (confiance step_ca pour LDAPS) et client_ldap_tls_reqcert: "demand".
# Bind de lecture. Vide => bind anonyme (lecture publique de l'annuaire).
client_ldap_bind_dn: ""
client_ldap_bind_password: "{{ vault_ldap_sssd | default('') }}" # rempli depuis la voute (vault_ldap_sssd)
# TLS : "never" tant que OpenLDAP n'expose pas LDAPS ; passer a "demand"
# avec LDAPS + confiance step_ca (client_pki).
client_ldap_tls_reqcert: "never"
# Creation automatique du repertoire personnel a la premiere connexion.
client_ldap_mkhomedir: true

View file

@ -1,6 +0,0 @@
---
- name: Redemarrer sssd
ansible.builtin.systemd:
name: "{{ client_ldap_service }}"
state: restarted
listen: Redemarrer sssd

View file

@ -1,49 +0,0 @@
---
- name: Résoudre l'annuaire (rôle partagé)
ansible.builtin.include_role:
name: resoudre_annuaire
- name: Adopter la connexion annuaire pour SSSD
ansible.builtin.set_fact:
client_ldap_uri: "{{ resoudre_annuaire_uri }}"
client_ldap_base_dn: "{{ resoudre_annuaire_base_dn }}"
- name: Installer SSSD et les modules LDAP
ansible.builtin.apt:
name: "{{ client_ldap_paquets }}"
state: present
update_cache: true
cache_valid_time: 3600
- name: Deployer la configuration SSSD
ansible.builtin.template:
src: sssd.conf.j2
dest: /etc/sssd/sssd.conf
owner: root
group: root
mode: "0600"
no_log: true
notify: Redemarrer sssd
- name: Activer SSS dans nsswitch
ansible.builtin.lineinfile:
path: /etc/nsswitch.conf
regexp: '^({{ item }}:\s+)(?!.*\bsss\b)(.*)$'
line: '\1\2 sss'
backrefs: true
loop:
- passwd
- group
- shadow
- name: Activer la creation automatique des repertoires personnels
ansible.builtin.command:
cmd: pam-auth-update --enable mkhomedir
changed_when: false
when: client_ldap_mkhomedir | bool
- name: Activer et demarrer SSSD
ansible.builtin.systemd:
name: "{{ client_ldap_service }}"
enabled: true
state: started

View file

@ -1,18 +0,0 @@
# Gere par Set-OPS (role client_ldap). Ne pas editer a la main.
[sssd]
config_file_version = 2
services = nss, pam
domains = {{ client_ldap_domaine }}
[domain/{{ client_ldap_domaine }}]
id_provider = ldap
auth_provider = ldap
ldap_uri = {{ client_ldap_uri }}
ldap_search_base = {{ client_ldap_base_dn }}
{% if client_ldap_bind_dn | length > 0 %}
ldap_default_bind_dn = {{ client_ldap_bind_dn }}
ldap_default_authtok = {{ client_ldap_bind_password }}
{% endif %}
ldap_tls_reqcert = {{ client_ldap_tls_reqcert }}
cache_credentials = true
enumerate = false

View file

@ -1,7 +1,7 @@
# client_smtp
Intégration cliente **relais mail** : l'hôte relaie son courrier sortant (notifications,
cron, alertes) vers `serveur_sendmail`, via **msmtp**.
cron, alertes) vers `serveur_postfix`, via **msmtp**.
## Rôle
- Installe `msmtp` et `msmtp-mta` (`msmtp-mta` fournit `/usr/sbin/sendmail`, donc le
@ -10,7 +10,7 @@ cron, alertes) vers `serveur_sendmail`, via **msmtp**.
fait confiance au réseau interne).
## Effet
Tout courrier émis localement (`mail`, cron, scripts) est relayé vers `serveur_sendmail`
Tout courrier émis localement (`mail`, cron, scripts) est relayé vers `serveur_postfix`
(infra-mail-01), qui assure la remise. Léger, sans daemon.
## Variables
@ -26,4 +26,4 @@ Tout courrier émis localement (`mail`, cron, scripts) est relayé vers `serveur
- TLS interne désactivé pour l'instant ; activable avec la confiance step_ca (`client_pki`).
## Prérequis
- Dépendance `client_smtp requiert serveur_sendmail actif` (déjà dans `docs/dependances-groupes.yml`).
- Dépendance `client_smtp requiert serveur_postfix actif` (déjà dans `docs/dependances-groupes.yml`).

View file

@ -1,5 +1,5 @@
---
# Relais mail local leger (msmtp) vers serveur_sendmail.
# Relais mail local leger (msmtp) vers le MTA (serveur_postfix).
client_smtp_paquets:
- msmtp
- msmtp-mta # fournit /usr/sbin/sendmail

View file

@ -2,7 +2,7 @@
# Résolveur local Unbound par nœud : cache + récursion (ou forward), avec une
# stub-zone vers l'autoritatif interne (PowerDNS). Rend la résolution dynamique
# (au lieu du plancher /etc/hosts statique) sans casser Internet. La bascule de
# /etc/resolv.conf est PROTÉGÉE (apply + confirm), comme client_dns.
# /etc/resolv.conf est PROTÉGÉE (apply + confirm) — bascule du résolveur validée avant application.
client_unbound_paquets:
- unbound
- bind9-dnsutils # dig, pour valider avant de basculer le resolver

View file

@ -6,7 +6,7 @@ Forge Git **Forgejo** (binaire officiel) — dépôts Git, CI, revue de code.
- Installe le binaire Forgejo (version épinglée, lien symbolique courant), utilisateur `git`.
- Crée l'arborescence (`/var/lib/forgejo`, `/etc/forgejo`).
- **Base PostgreSQL via le registre** (`instance/plan/bases-donnees.yml`, entrée `forgejo`).
- `app.ini` : serveur derrière nginx (`HTTP_ADDR=127.0.0.1`, `ROOT_URL` https), DB, secrets, mailer vers `serveur_sendmail`, inscription désactivée, `INSTALL_LOCK` (pas d'assistant web).
- `app.ini` : serveur derrière nginx (`HTTP_ADDR=127.0.0.1`, `ROOT_URL` https), DB, secrets, mailer vers `serveur_postfix`, inscription désactivée, `INSTALL_LOCK` (pas d'assistant web).
- Service systemd + création du **compte administrateur** initial (une fois).
## Secrets requis (Vault)
@ -31,4 +31,4 @@ vault_bd_forgejo: "..." # mot de passe BD (partage avec serveur_postgresql)
- Non testé live (forge-01 planifié).
## Prérequis
- Dépendances `serveur_postgresql`, `serveur_nginx`, `serveur_sendmail` (cf. `docs/dependances-groupes.yml`).
- Dépendances `serveur_postgresql`, `serveur_nginx`, `serveur_postfix` (cf. `docs/dependances-groupes.yml`).

View file

@ -1,6 +1,6 @@
# serveur_openldap
Annuaire interne OpenLDAP (slapd Debian), socle d'identité pour `client_ldap`
Annuaire interne OpenLDAP (slapd Debian), socle d'identité pour le SSO (Keycloak), le courriel
et fédération applicative (Keycloak).
## Rôle
@ -32,7 +32,7 @@ refuse de s'exécuter (assertion explicite).
slapd déjà installé (changer domaine/mot de passe) nécessite `dpkg-reconfigure slapd`
manuel (non automatisé ici pour éviter une purge accidentelle de la base).
- TLS (LDAPS) : hors périmètre du socle — viendra avec les certificats de `serveur_step_ca`.
- Entrées utilisateurs/groupes : gérées ailleurs (identité / `client_ldap`).
- Entrées utilisateurs/groupes : gérées ailleurs (provisioning de l'annuaire).
## Prérequis
- Collection `community.general` (`ldap_entry`) + `python3-ldap` sur la cible.

View file

@ -1,37 +0,0 @@
# serveur_sendmail
Relais SMTP sortant interne. **Implémenté avec Postfix** (fournit l'interface
`sendmail`-compatible `/usr/sbin/sendmail` qu'utilisent les clients).
## Rôle
- Préconfigure Postfix via debconf (installation non interactive, « Internet Site »).
- Installe `postfix` et `ssl-cert`.
- Déploie `/etc/postfix/main.cf` : relais sortant uniquement, **n'accepte de relayer que pour `mynetworks`** (réseaux internes).
- **Valide la configuration (`postfix check`) avant de recharger** (handler `Valider et recharger postfix`).
## Sécurité
- `smtpd_relay_restrictions = permit_mynetworks, reject_unauth_destination` → pas de relais ouvert.
- `mynetworks` par défaut : boucle locale + `10.0.0.0/16`.
- N'héberge pas de boîtes (`mydestination` ne contient pas le domaine) : remise relayée.
- TLS opportuniste (`may`), certificat snakeoil par défaut.
## Variables principales
| Variable | Défaut | Rôle |
| --- | --- | --- |
| `serveur_sendmail_domaine` | `exemple.internal` | `mydomain` / mailname |
| `serveur_sendmail_reseaux_autorises` | boucle + `10.0.0.0/16` | `mynetworks` (qui peut relayer) |
| `serveur_sendmail_smarthost` | `""` | Relais amont (vide = remise directe MX) |
| `serveur_sendmail_inet_interfaces` | `all` | Interfaces d'écoute |
| `serveur_sendmail_tls_cert` / `_cle` | snakeoil | Certificat TLS |
## Smarthost amont
```yaml
serveur_sendmail_smarthost: "[smtp.exemple.com]:587"
```
(L'authentification SASL vers un smarthost externe, si requise, viendra avec ses
identifiants depuis Ansible Vault — hors périmètre du socle actuel.)
## Hors périmètre
- Réception/hébergement de courrier (boîtes, IMAP).
- Authentification SASL sortante vers smarthost (à ajouter avec Vault si besoin).
- DKIM/SPF/DMARC signature (phase dédiée).

View file

@ -1,31 +0,0 @@
---
# Relais SMTP sortant base sur Postfix (fournit l'interface sendmail-compatible).
serveur_sendmail_packages:
- postfix
- ssl-cert
serveur_sendmail_service_name: "postfix"
# Identite.
serveur_sendmail_domaine: "{{ domaine_interne }}"
serveur_sendmail_origine: "$mydomain"
serveur_sendmail_nom_hote: "{{ ansible_fqdn | default(ansible_hostname) }}"
# Reseaux internes autorises a relayer (client_smtp).
serveur_sendmail_reseaux_autorises:
- "127.0.0.0/8"
- "[::1]/128"
- "10.0.0.0/16"
# Smarthost amont optionnel. Vide => remise directe (MX).
serveur_sendmail_smarthost: "" # ex. "[smtp.exemple.com]:587"
# Relais uniquement : ne pas heberger de boites pour le domaine.
serveur_sendmail_destinations_locales: "$myhostname, localhost.$mydomain, localhost"
# Interfaces d'ecoute.
serveur_sendmail_inet_interfaces: "all"
# TLS (snakeoil par defaut ; bascule vers l'AC interne plus tard).
serveur_sendmail_tls_cert: "/etc/ssl/certs/ssl-cert-snakeoil.pem"
serveur_sendmail_tls_cle: "/etc/ssl/private/ssl-cert-snakeoil.key"

View file

@ -1,14 +0,0 @@
---
- name: Verifier la configuration Postfix
when: not ansible_check_mode
ansible.builtin.command:
cmd: postfix check
changed_when: false
listen: Valider et recharger postfix
- name: Recharger postfix
when: not ansible_check_mode
ansible.builtin.systemd:
name: "{{ serveur_sendmail_service_name }}"
state: reloaded
listen: Valider et recharger postfix

View file

@ -1,8 +0,0 @@
---
# Empreinte ressources du logiciel — dimensionnement VM derive (scripts/instancier.py).
# Sommee au socle SE + marge pour estimer coeurs/RAM/disque de la VM hote.
# Override possible par hote dans le plan (serveurs.yml: coeurs/memoire/disque).
setops_empreinte:
coeurs: 1
memoire_mo: 512
disque_go: 5

View file

@ -1,35 +0,0 @@
---
- name: Preconfigurer Postfix (debconf, installation non interactive)
ansible.builtin.debconf:
name: postfix
question: "{{ item.question }}"
vtype: "{{ item.vtype }}"
value: "{{ item.value }}"
loop:
- { question: "postfix/main_mailer_type", vtype: "select", value: "Internet Site" }
- { question: "postfix/mailname", vtype: "string", value: "{{ serveur_sendmail_domaine }}" }
loop_control:
label: "{{ item.question }}"
- name: Installer Postfix
ansible.builtin.apt:
name: "{{ serveur_sendmail_packages }}"
state: present
update_cache: true
cache_valid_time: 3600
- name: Deployer la configuration Postfix
ansible.builtin.template:
src: main.cf.j2
dest: /etc/postfix/main.cf
owner: root
group: root
mode: "0644"
notify: Valider et recharger postfix
- name: Activer et demarrer Postfix
when: not ansible_check_mode
ansible.builtin.systemd:
name: "{{ serveur_sendmail_service_name }}"
enabled: true
state: started

View file

@ -1,31 +0,0 @@
# Gere par Set-OPS (role serveur_sendmail, base Postfix). Ne pas editer a la main.
smtpd_banner = $myhostname ESMTP
biff = no
append_dot_mydomain = no
readme_directory = no
compatibility_level = 3.6
myhostname = {{ serveur_sendmail_nom_hote }}
mydomain = {{ serveur_sendmail_domaine }}
myorigin = {{ serveur_sendmail_origine }}
mydestination = {{ serveur_sendmail_destinations_locales }}
mynetworks = {{ serveur_sendmail_reseaux_autorises | join(', ') }}
relayhost = {{ serveur_sendmail_smarthost }}
inet_interfaces = {{ serveur_sendmail_inet_interfaces }}
inet_protocols = all
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mailbox_size_limit = 0
recipient_delimiter = +
# Relais limite aux reseaux internes.
smtpd_relay_restrictions = permit_mynetworks, reject_unauth_destination
# TLS opportuniste.
smtpd_tls_cert_file = {{ serveur_sendmail_tls_cert }}
smtpd_tls_key_file = {{ serveur_sendmail_tls_cle }}
smtpd_tls_security_level = may
smtp_tls_security_level = may
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache