diff --git a/CHANGELOG.md b/CHANGELOG.md index 65dabc3..17cf8d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,14 @@ ## 2026-07-02 ### Ajouté +- **`serveur_openldap` durci pour la prod : TLS via step_ca + organisation en intrant.** + - **TLS (LDAPS + STARTTLS)** : le certificat d'hôte step_ca (déposé par `client_pki`, + `root:root 600`) est synchronisé vers un emplacement lisible par `openldap` (`/etc/ldap/tls`) + par un script + une unité `path` systemd qui **re-synchronise et recharge slapd à chaque + renouvellement** ; `olcTLS*` configuré dans `cn=config`, `SLAPD_SERVICES` expose `ldaps://`. + Dégrade proprement (slapd en clair local) si `client_pki` n'a pas encore posé le cert. + - **Organisation** : nouvel intrant `chezlepro_organisation` (remplace le « Exemple Inc » codé). + - *Écrit en code de prod, éprouvé statiquement ; validation par déploiement réel à suivre.* - **`docs/courriel-conception.md`** — cadrage du futur service de courriel souverain : full self-host, suite **Stalwart** (adoptée, enveloppée par un rôle mince), topologie MX primaire + MX secours, intégration identité (LDAP) / DNS / PKI (Let's Encrypt public diff --git a/roles/serveur_openldap/defaults/main.yml b/roles/serveur_openldap/defaults/main.yml index 9007d39..8fbbefd 100644 --- a/roles/serveur_openldap/defaults/main.yml +++ b/roles/serveur_openldap/defaults/main.yml @@ -8,7 +8,7 @@ serveur_openldap_service: "slapd" # Identite de l'annuaire. serveur_openldap_domaine: "{{ domaine_interne }}" -serveur_openldap_organisation: "Exemple Inc" +serveur_openldap_organisation: "{{ chezlepro_organisation | default('Organisation') }}" # Base DN derivee du domaine interne (ex. acme.local -> dc=acme,dc=local). serveur_openldap_base_dn: "dc={{ serveur_openldap_domaine.split('.') | join(',dc=') }}" serveur_openldap_admin_dn: "cn=admin,{{ serveur_openldap_base_dn }}" @@ -20,3 +20,15 @@ serveur_openldap_admin_password: "{{ vault_openldap_admin | default('') }}" # r serveur_openldap_ou: - people - groups + +# --- TLS (LDAPS + STARTTLS) via le certificat d'hote step_ca --- +# Requiert l'integration client_pki sur le noeud (fournit le cert + le renouvellement). +serveur_openldap_tls_actif: true +# Certificat SOURCE depose par client_pki (root:root 600, illisible par openldap). +serveur_openldap_tls_source_cert: "/etc/step/certs/{{ ansible_fqdn | default(ansible_hostname) }}.crt" +serveur_openldap_tls_source_cle: "/etc/step/certs/{{ ansible_fqdn | default(ansible_hostname) }}.key" +serveur_openldap_tls_source_ca: "/etc/step/certs/root_ca.crt" +# Emplacement PONT, lisible par openldap ; resynchronise a chaque renouvellement. +serveur_openldap_tls_dir: "/etc/ldap/tls" +# Services slapd exposes (ldaps ajoute pour le TLS ; ldapi pour l'admin local). +serveur_openldap_services: "ldap:/// ldaps:/// ldapi:///" diff --git a/roles/serveur_openldap/handlers/main.yml b/roles/serveur_openldap/handlers/main.yml new file mode 100644 index 0000000..dc9d1b7 --- /dev/null +++ b/roles/serveur_openldap/handlers/main.yml @@ -0,0 +1,7 @@ +--- +- name: Redemarrer slapd + ansible.builtin.systemd: + name: "{{ serveur_openldap_service }}" + state: restarted + daemon_reload: true + when: not ansible_check_mode diff --git a/roles/serveur_openldap/tasks/main.yml b/roles/serveur_openldap/tasks/main.yml index ffa1e37..c924508 100644 --- a/roles/serveur_openldap/tasks/main.yml +++ b/roles/serveur_openldap/tasks/main.yml @@ -58,3 +58,95 @@ loop_control: label: "ou={{ item }}" no_log: true + +# --- TLS (LDAPS + STARTTLS) via le certificat step_ca depose par client_pki --- +- name: TLS — creer le repertoire pont lisible par openldap + ansible.builtin.file: + path: "{{ serveur_openldap_tls_dir }}" + state: directory + owner: openldap + group: openldap + mode: "0750" + when: serveur_openldap_tls_actif | bool + +- name: TLS — deployer le script de synchronisation du certificat + ansible.builtin.template: + src: setops-slapd-cert-sync.sh.j2 + dest: /usr/local/sbin/setops-slapd-cert-sync + owner: root + group: root + mode: "0755" + when: serveur_openldap_tls_actif | bool + +- name: TLS — deployer les unites de synchronisation (service + path) + ansible.builtin.template: + src: "{{ item.s }}" + dest: "{{ item.d }}" + owner: root + group: root + mode: "0644" + loop: + - { s: "setops-slapd-cert-sync.service.j2", d: "/etc/systemd/system/setops-slapd-cert-sync.service" } + - { s: "setops-slapd-cert-sync.path.j2", d: "/etc/systemd/system/setops-slapd-cert-sync.path" } + loop_control: + label: "{{ item.d | basename }}" + when: serveur_openldap_tls_actif | bool + +- name: TLS — synchroniser le certificat maintenant (si client_pki l'a depose) + ansible.builtin.command: /usr/local/sbin/setops-slapd-cert-sync + changed_when: false + when: + - serveur_openldap_tls_actif | bool + - not ansible_check_mode + +- name: TLS — activer la surveillance du certificat (renouvellement) + ansible.builtin.systemd: + name: setops-slapd-cert-sync.path + enabled: true + state: started + daemon_reload: true + when: + - serveur_openldap_tls_actif | bool + - not ansible_check_mode + +- name: TLS — verifier que le certificat pont est en place + ansible.builtin.stat: + path: "{{ serveur_openldap_tls_dir }}/cert.pem" + register: serveur_openldap_cert_pont + when: serveur_openldap_tls_actif | bool + +- name: TLS — avertir si le certificat n'est pas encore disponible + ansible.builtin.debug: + msg: >- + client_pki n'a pas encore depose de certificat sur ce noeud + ({{ serveur_openldap_tls_source_cert }}). TLS slapd NON configure : deploie + l'integration client_pki sur ce noeud, puis relance le deploiement. + when: + - serveur_openldap_tls_actif | bool + - not ansible_check_mode + - not (serveur_openldap_cert_pont.stat.exists | default(false)) + +- name: TLS — configurer slapd (olcTLS* dans cn=config) + community.general.ldap_attrs: + dn: cn=config + server_uri: ldapi:/// + attributes: + olcTLSCACertificateFile: "{{ serveur_openldap_tls_dir }}/ca.pem" + olcTLSCertificateFile: "{{ serveur_openldap_tls_dir }}/cert.pem" + olcTLSCertificateKeyFile: "{{ serveur_openldap_tls_dir }}/key.pem" + state: exact + when: + - serveur_openldap_tls_actif | bool + - not ansible_check_mode + - serveur_openldap_cert_pont.stat.exists | default(false) + notify: Redemarrer slapd + +- name: TLS — exposer LDAPS (SLAPD_SERVICES) + ansible.builtin.lineinfile: + path: /etc/default/slapd + regexp: '^SLAPD_SERVICES=' + line: 'SLAPD_SERVICES="{{ serveur_openldap_services }}"' + when: + - serveur_openldap_tls_actif | bool + - serveur_openldap_cert_pont.stat.exists | default(false) + notify: Redemarrer slapd diff --git a/roles/serveur_openldap/templates/setops-slapd-cert-sync.path.j2 b/roles/serveur_openldap/templates/setops-slapd-cert-sync.path.j2 new file mode 100644 index 0000000..7e940ab --- /dev/null +++ b/roles/serveur_openldap/templates/setops-slapd-cert-sync.path.j2 @@ -0,0 +1,12 @@ +# Gere par Set-OPS (role serveur_openldap). Ne pas editer a la main. +# Surveille le certificat step_ca : au renouvellement (client_pki), resynchronise +# vers slapd et le recharge. +[Unit] +Description=Set-OPS — surveille le certificat step_ca de slapd + +[Path] +PathChanged={{ serveur_openldap_tls_source_cert }} +Unit=setops-slapd-cert-sync.service + +[Install] +WantedBy=multi-user.target diff --git a/roles/serveur_openldap/templates/setops-slapd-cert-sync.service.j2 b/roles/serveur_openldap/templates/setops-slapd-cert-sync.service.j2 new file mode 100644 index 0000000..15c134b --- /dev/null +++ b/roles/serveur_openldap/templates/setops-slapd-cert-sync.service.j2 @@ -0,0 +1,8 @@ +# Gere par Set-OPS (role serveur_openldap). Ne pas editer a la main. +[Unit] +Description=Set-OPS — synchronise le certificat step_ca vers slapd +After=slapd.service + +[Service] +Type=oneshot +ExecStart=/usr/local/sbin/setops-slapd-cert-sync diff --git a/roles/serveur_openldap/templates/setops-slapd-cert-sync.sh.j2 b/roles/serveur_openldap/templates/setops-slapd-cert-sync.sh.j2 new file mode 100644 index 0000000..0915279 --- /dev/null +++ b/roles/serveur_openldap/templates/setops-slapd-cert-sync.sh.j2 @@ -0,0 +1,23 @@ +#!/bin/sh +# Gere par Set-OPS (role serveur_openldap). Ne pas editer a la main. +# Synchronise le certificat step_ca (depose par client_pki, root:root 600) vers un +# emplacement lisible par openldap, puis recharge slapd. Idempotent ; appele au +# deploiement ET a chaque renouvellement (unite path). +set -eu + +SRC_CERT="{{ serveur_openldap_tls_source_cert }}" +SRC_KEY="{{ serveur_openldap_tls_source_cle }}" +SRC_CA="{{ serveur_openldap_tls_source_ca }}" +DST="{{ serveur_openldap_tls_dir }}" + +# Rien a faire tant que client_pki n'a pas depose le certificat d'hote. +[ -f "$SRC_CERT" ] && [ -f "$SRC_KEY" ] || exit 0 + +install -o openldap -g openldap -m 0644 "$SRC_CERT" "$DST/cert.pem" +install -o openldap -g openldap -m 0640 "$SRC_KEY" "$DST/key.pem" +[ -f "$SRC_CA" ] && install -o openldap -g openldap -m 0644 "$SRC_CA" "$DST/ca.pem" + +# Recharge slapd s'il tourne (sans echouer s'il est absent/arrete). +if systemctl --quiet is-active slapd 2>/dev/null; then + systemctl reload slapd 2>/dev/null || systemctl restart slapd +fi diff --git a/scripts/inventory_gui.py b/scripts/inventory_gui.py index d131c76..b7d5170 100644 --- a/scripts/inventory_gui.py +++ b/scripts/inventory_gui.py @@ -79,6 +79,7 @@ FICHIERS_INTRANTS = {"identite": INTRANTS_IDENTITE, "proxmox": INTRANTS_PROXMOX} INTRANTS_SCHEMA = [ ("domaine_interne", "identite", "constante", "Identité", "Domaine DNS interne", "str"), ("chezlepro_timezone", "identite", "defaut", "Identité", "Fuseau horaire", "str"), + ("chezlepro_organisation", "identite", "defaut", "Identité", "Organisation (annuaire LDAP, certificats)", "str"), ("proxmox_api_host", "proxmox", "constante", "Proxmox", "Hôte API Proxmox", "str"), ("proxmox_api_user", "proxmox", "constante", "Proxmox", "Utilisateur API", "str"), ("proxmox_api_port", "proxmox", "constante", "Proxmox", "Port API", "str"),