Implementer le premier jalon DNS interne
This commit is contained in:
parent
18513a3bf0
commit
6fd0efd88d
19 changed files with 386 additions and 10 deletions
|
|
@ -7,6 +7,11 @@
|
|||
- Ajout de `scripts/inventory_rules.py` pour centraliser les règles partagées entre la gestion CLI et l'interface locale d'inventaire.
|
||||
- Ajout de `docs/dependances-groupes.yml` comme registre exploitable des dépendances causales entre groupes.
|
||||
- Ajout du contrat `serveurs_powerdns` afin de représenter la capacité DNS centrale requise par `clients_dns`.
|
||||
- Ajout du premier jalon DNS interne :
|
||||
- rôle `serveurs_powerdns` avec PowerDNS Authoritative et backend BIND ;
|
||||
- génération de la zone interne depuis l'inventaire actif ;
|
||||
- rôle `clients_dns` avec validation de zone et modification resolver protégée ;
|
||||
- variables de production DNS et runbook `docs/dns-interne.md`.
|
||||
|
||||
### Modifié
|
||||
- Renforcement de la validation d'inventaire :
|
||||
|
|
|
|||
|
|
@ -89,6 +89,8 @@ Le catalogue des services et intégrations prévus est dans `docs/catalogue-serv
|
|||
|
||||
Les dépendances causales entre groupes sont dans `docs/dependances-groupes.yml`.
|
||||
|
||||
Le runbook du DNS interne initial est dans `docs/dns-interne.md`.
|
||||
|
||||
La nomenclature des noms de VM et des VMID est dans `docs/nomenclature-vm.md`.
|
||||
|
||||
Créer un clone depuis le modèle Debian 13 via l'API Proxmox :
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ Un service central peut partager un hôte avec d'autres services du même domain
|
|||
| Forgejo | `serveurs_forgejo` | `playbooks/groupes/serveurs_forgejo.yml` | `forgejo` |
|
||||
| Sendmail MTA | `serveurs_sendmail` | `playbooks/groupes/serveurs_sendmail.yml` | `sendmail` |
|
||||
| step-ca | `serveurs_step_ca` | `playbooks/groupes/serveurs_step_ca.yml` | `step_ca` |
|
||||
| PowerDNS | `serveurs_powerdns` | `playbooks/groupes/serveurs_powerdns.yml` | `powerdns` |
|
||||
| PowerDNS | `serveurs_powerdns` | `playbooks/groupes/serveurs_powerdns.yml` | `serveurs_powerdns` |
|
||||
| Redis | `serveurs_redis` | `playbooks/groupes/serveurs_redis.yml` | `redis` |
|
||||
| NGINX WAF et reverse proxy | `serveurs_nginx` | `playbooks/groupes/serveurs_nginx.yml` | `nginx` |
|
||||
| Nextcloud | `serveurs_nextcloud` | `playbooks/groupes/serveurs_nextcloud.yml` | `nextcloud` |
|
||||
|
|
@ -53,7 +53,7 @@ Un service central peut partager un hôte avec d'autres services du même domain
|
|||
|
||||
| Intégration | Groupe | Playbook | Rôle futur |
|
||||
| --- | --- | --- | --- |
|
||||
| Résolution DNS interne | `clients_dns` | `playbooks/groupes/clients_dns.yml` | `client_dns` |
|
||||
| Résolution DNS interne | `clients_dns` | `playbooks/groupes/clients_dns.yml` | `clients_dns` |
|
||||
| Confiance PKI / ACME | `clients_pki` | `playbooks/groupes/clients_pki.yml` | `client_pki` |
|
||||
| Authentification LDAP | `clients_ldap` | `playbooks/groupes/clients_ldap.yml` | `client_ldap` |
|
||||
| Supervision Icinga | `clients_supervision` | `playbooks/groupes/clients_supervision.yml` | `client_supervision` |
|
||||
|
|
@ -166,6 +166,8 @@ Les groupes clients peuvent être ajoutés aux VM existantes quand le service ce
|
|||
|
||||
Les dépendances exécutables sont déclarées dans `docs/dependances-groupes.yml`.
|
||||
|
||||
Le runbook DNS initial est dans `docs/dns-interne.md`.
|
||||
|
||||
Ce fichier sert à deux usages :
|
||||
|
||||
- bloquer le déploiement d'un groupe tant que ses prérequis actifs ne sont pas présents ;
|
||||
|
|
|
|||
90
docs/dns-interne.md
Normal file
90
docs/dns-interne.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# DNS interne Chezlepro
|
||||
|
||||
Le service DNS interne est la premiere capacite de plateforme.
|
||||
|
||||
## Groupes
|
||||
|
||||
```text
|
||||
serveurs_powerdns -> service DNS central PowerDNS Authoritative
|
||||
clients_dns -> integration cliente DNS
|
||||
```
|
||||
|
||||
`clients_dns` depend de `serveurs_powerdns` dans `docs/dependances-groupes.yml`.
|
||||
|
||||
## Zone initiale
|
||||
|
||||
La zone initiale est :
|
||||
|
||||
```text
|
||||
chezlepro.internal
|
||||
```
|
||||
|
||||
Elle est definie dans :
|
||||
|
||||
```text
|
||||
inventories/production/group_vars/serveurs_powerdns.yml
|
||||
```
|
||||
|
||||
## Enregistrement automatique
|
||||
|
||||
Le role `serveurs_powerdns` genere la zone a partir de l'inventaire.
|
||||
|
||||
Les hotes qui remplissent ces conditions sont ajoutes automatiquement :
|
||||
|
||||
```text
|
||||
hote dans hotes_actifs
|
||||
ansible_host defini
|
||||
```
|
||||
|
||||
Exemple :
|
||||
|
||||
```text
|
||||
web-01 ansible_host=192.168.12.101
|
||||
-> web-01.chezlepro.internal A 192.168.12.101
|
||||
```
|
||||
|
||||
Les enregistrements additionnels explicites sont dans `serveurs_powerdns_records`.
|
||||
|
||||
## Backend PowerDNS
|
||||
|
||||
Le premier jalon utilise le backend BIND de PowerDNS.
|
||||
|
||||
Raison :
|
||||
|
||||
- pas de dependance prematuree a PostgreSQL ;
|
||||
- zone lisible et generee par Ansible ;
|
||||
- idempotence simple ;
|
||||
- bon point de depart pour la supervision.
|
||||
|
||||
Quand `serveurs_postgresql` sera stable, il sera possible de migrer vers un backend SQL si le besoin operationnel le justifie.
|
||||
|
||||
## Clients DNS
|
||||
|
||||
Le role `clients_dns` valide :
|
||||
|
||||
- qu'un serveur `serveurs_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 :
|
||||
|
||||
```yaml
|
||||
clients_dns_apply: true
|
||||
clients_dns_confirm: true
|
||||
```
|
||||
|
||||
Sans ces deux variables, le role valide les prerequis mais ne modifie pas `/etc/resolv.conf`.
|
||||
|
||||
Cette protection est volontaire : une mauvaise configuration DNS peut couper la resolution de noms.
|
||||
|
||||
## Surveillance a prevoir
|
||||
|
||||
Les premiers checks utiles :
|
||||
|
||||
- service `pdns` actif ;
|
||||
- port UDP/TCP 53 disponible ;
|
||||
- SOA de `chezlepro.internal` resoluble ;
|
||||
- enregistrement `ns1.chezlepro.internal` resoluble ;
|
||||
- enregistrements des hotes actifs presents ;
|
||||
- serial de zone attendu ;
|
||||
- latence de resolution.
|
||||
11
inventories/production/group_vars/clients_dns.yml
Normal file
11
inventories/production/group_vars/clients_dns.yml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
# Variables de l'intégration cliente DNS.
|
||||
|
||||
clients_dns_zone: "chezlepro.internal"
|
||||
clients_dns_search_domains:
|
||||
- "{{ clients_dns_zone }}"
|
||||
|
||||
# La modification du resolver est protegee. Activer ces deux variables seulement
|
||||
# lorsque le serveur DNS interne et la zone ont ete verifies.
|
||||
clients_dns_apply: false
|
||||
clients_dns_confirm: false
|
||||
13
inventories/production/group_vars/serveurs_powerdns.yml
Normal file
13
inventories/production/group_vars/serveurs_powerdns.yml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
# Variables du service DNS interne PowerDNS.
|
||||
|
||||
serveurs_powerdns_zone: "chezlepro.internal"
|
||||
serveurs_powerdns_nameserver: "ns1"
|
||||
serveurs_powerdns_contact: "hostmaster.chezlepro.internal"
|
||||
serveurs_powerdns_serial: 2026062201
|
||||
serveurs_powerdns_inventory_groups:
|
||||
- hotes_actifs
|
||||
serveurs_powerdns_records:
|
||||
- name: "dns"
|
||||
type: "CNAME"
|
||||
value: "ns1.{{ serveurs_powerdns_zone }}."
|
||||
|
|
@ -4,7 +4,12 @@
|
|||
become: true
|
||||
gather_facts: true
|
||||
|
||||
tasks:
|
||||
- name: Indiquer que l'intégration cliente DNS reste à définir
|
||||
ansible.builtin.debug:
|
||||
msg: "Aucun rôle n'est encore associé au groupe clients_dns."
|
||||
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:
|
||||
- clients_dns
|
||||
|
|
|
|||
|
|
@ -4,7 +4,12 @@
|
|||
become: true
|
||||
gather_facts: true
|
||||
|
||||
tasks:
|
||||
- name: Indiquer que le service PowerDNS reste à définir
|
||||
ansible.builtin.debug:
|
||||
msg: "Aucun rôle n'est encore associé au groupe serveurs_powerdns."
|
||||
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:
|
||||
- serveurs_powerdns
|
||||
|
|
|
|||
16
roles/clients_dns/README.md
Normal file
16
roles/clients_dns/README.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Role `clients_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
|
||||
clients_dns_apply: true
|
||||
clients_dns_confirm: true
|
||||
```
|
||||
|
||||
Le serveur DNS requis vient du groupe `serveurs_powerdns`.
|
||||
9
roles/clients_dns/defaults/main.yml
Normal file
9
roles/clients_dns/defaults/main.yml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
clients_dns_apply: false
|
||||
clients_dns_confirm: false
|
||||
clients_dns_zone: "chezlepro.internal"
|
||||
clients_dns_search_domains:
|
||||
- "{{ clients_dns_zone }}"
|
||||
clients_dns_nameservers: []
|
||||
clients_dns_resolv_conf_path: "/etc/resolv.conf"
|
||||
clients_dns_resolv_conf_header: "Gere par Ansible Set-OPS - clients_dns"
|
||||
61
roles/clients_dns/tasks/main.yml
Normal file
61
roles/clients_dns/tasks/main.yml
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
- name: Déterminer les serveurs DNS internes depuis l'inventaire
|
||||
ansible.builtin.set_fact:
|
||||
clients_dns_effective_nameservers: >-
|
||||
{{
|
||||
clients_dns_nameservers
|
||||
if (clients_dns_nameservers | length > 0)
|
||||
else (
|
||||
groups.get('serveurs_powerdns', [])
|
||||
| map('extract', hostvars, 'ansible_host')
|
||||
| select('defined')
|
||||
| list
|
||||
)
|
||||
}}
|
||||
|
||||
- name: Vérifier qu'au moins un serveur DNS interne est connu
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- clients_dns_effective_nameservers | length > 0
|
||||
fail_msg: "Aucun serveur DNS interne disponible pour clients_dns."
|
||||
|
||||
- name: Installer les outils de diagnostic DNS
|
||||
ansible.builtin.apt:
|
||||
name: dnsutils
|
||||
state: present
|
||||
update_cache: true
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Valider la zone DNS interne sur le serveur primaire
|
||||
ansible.builtin.command:
|
||||
cmd: "dig @{{ clients_dns_effective_nameservers[0] }} {{ clients_dns_zone }} SOA +short"
|
||||
register: clients_dns_soa_check
|
||||
changed_when: false
|
||||
failed_when: clients_dns_soa_check.stdout | trim == ""
|
||||
|
||||
- name: Refuser la modification DNS sans confirmation explicite
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- clients_dns_confirm | bool
|
||||
fail_msg: "Modification DNS refusee: definir clients_dns_confirm=true pour modifier le resolver."
|
||||
when: clients_dns_apply | bool
|
||||
|
||||
- name: Configurer le resolver client
|
||||
ansible.builtin.template:
|
||||
src: resolv.conf.j2
|
||||
dest: "{{ clients_dns_resolv_conf_path }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
backup: true
|
||||
when:
|
||||
- clients_dns_apply | bool
|
||||
- clients_dns_confirm | bool
|
||||
|
||||
- name: Valider la résolution du nom local dans la zone interne
|
||||
ansible.builtin.command:
|
||||
cmd: "dig @{{ clients_dns_effective_nameservers[0] }} {{ inventory_hostname }}.{{ clients_dns_zone }} A +short"
|
||||
register: clients_dns_host_check
|
||||
changed_when: false
|
||||
failed_when: clients_dns_host_check.stdout | trim == ""
|
||||
when: ansible_host is defined
|
||||
8
roles/clients_dns/templates/resolv.conf.j2
Normal file
8
roles/clients_dns/templates/resolv.conf.j2
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# {{ clients_dns_resolv_conf_header }}
|
||||
{% for nameserver in clients_dns_effective_nameservers %}
|
||||
nameserver {{ nameserver }}
|
||||
{% endfor %}
|
||||
{% if clients_dns_search_domains | length > 0 %}
|
||||
search {{ clients_dns_search_domains | join(' ') }}
|
||||
{% endif %}
|
||||
options timeout:2 attempts:2 rotate
|
||||
17
roles/serveurs_powerdns/README.md
Normal file
17
roles/serveurs_powerdns/README.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Role `serveurs_powerdns`
|
||||
|
||||
Installe et configure PowerDNS Authoritative comme service DNS interne initial.
|
||||
|
||||
Ce premier jalon utilise le backend BIND et une zone generee par Ansible depuis
|
||||
l'inventaire. Cela evite de rendre DNS dependant de PostgreSQL avant que le
|
||||
service `serveurs_postgresql` soit disponible.
|
||||
|
||||
Variables principales :
|
||||
|
||||
- `serveurs_powerdns_zone`
|
||||
- `serveurs_powerdns_nameserver`
|
||||
- `serveurs_powerdns_contact`
|
||||
- `serveurs_powerdns_records`
|
||||
|
||||
Les hotes actifs portant `ansible_host` sont ajoutes automatiquement dans la
|
||||
zone par le template.
|
||||
33
roles/serveurs_powerdns/defaults/main.yml
Normal file
33
roles/serveurs_powerdns/defaults/main.yml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
serveurs_powerdns_packages:
|
||||
- pdns-server
|
||||
- pdns-backend-bind
|
||||
- bind9-utils
|
||||
- dnsutils
|
||||
|
||||
serveurs_powerdns_service_name: "pdns"
|
||||
serveurs_powerdns_zone_directory: "/etc/powerdns/zones"
|
||||
serveurs_powerdns_bind_config: "/etc/powerdns/bindbackend.conf"
|
||||
serveurs_powerdns_zone: "chezlepro.internal"
|
||||
serveurs_powerdns_nameserver: "ns1"
|
||||
serveurs_powerdns_contact: "hostmaster.chezlepro.internal"
|
||||
serveurs_powerdns_ttl: 3600
|
||||
serveurs_powerdns_serial: 2026062201
|
||||
serveurs_powerdns_soa_refresh: 3600
|
||||
serveurs_powerdns_soa_retry: 900
|
||||
serveurs_powerdns_soa_expire: 1209600
|
||||
serveurs_powerdns_soa_minimum: 3600
|
||||
serveurs_powerdns_listen_addresses:
|
||||
- "0.0.0.0"
|
||||
- "::"
|
||||
serveurs_powerdns_allow_axfr_ips: []
|
||||
|
||||
# Enregistrements additionnels geres explicitement.
|
||||
serveurs_powerdns_records:
|
||||
- name: "dns"
|
||||
type: "CNAME"
|
||||
value: "ns1.{{ serveurs_powerdns_zone }}."
|
||||
|
||||
# Groupes dont les hotes actifs avec ansible_host seront ajoutes a la zone.
|
||||
serveurs_powerdns_inventory_groups:
|
||||
- hotes_actifs
|
||||
12
roles/serveurs_powerdns/handlers/main.yml
Normal file
12
roles/serveurs_powerdns/handlers/main.yml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
- name: Validate PowerDNS zone
|
||||
ansible.builtin.command:
|
||||
cmd: "named-checkzone {{ serveurs_powerdns_zone }} {{ serveurs_powerdns_zone_directory }}/{{ serveurs_powerdns_zone }}.zone"
|
||||
changed_when: false
|
||||
listen: Validate and reload PowerDNS
|
||||
|
||||
- name: Restart PowerDNS
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ serveurs_powerdns_service_name }}"
|
||||
state: restarted
|
||||
listen: Validate and reload PowerDNS
|
||||
48
roles/serveurs_powerdns/tasks/main.yml
Normal file
48
roles/serveurs_powerdns/tasks/main.yml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
- name: Installer PowerDNS Authoritative
|
||||
ansible.builtin.apt:
|
||||
name: "{{ serveurs_powerdns_packages }}"
|
||||
state: present
|
||||
update_cache: true
|
||||
cache_valid_time: 3600
|
||||
|
||||
- name: Créer le répertoire des zones PowerDNS
|
||||
ansible.builtin.file:
|
||||
path: "{{ serveurs_powerdns_zone_directory }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
|
||||
- name: Déployer la configuration du backend BIND
|
||||
ansible.builtin.template:
|
||||
src: chezlepro-bind.conf.j2
|
||||
dest: /etc/powerdns/pdns.d/chezlepro-bind.conf
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify: Validate and reload PowerDNS
|
||||
|
||||
- name: Déployer l'index des zones PowerDNS
|
||||
ansible.builtin.template:
|
||||
src: bindbackend.conf.j2
|
||||
dest: "{{ serveurs_powerdns_bind_config }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify: Validate and reload PowerDNS
|
||||
|
||||
- name: Générer la zone DNS interne depuis l'inventaire
|
||||
ansible.builtin.template:
|
||||
src: zone.db.j2
|
||||
dest: "{{ serveurs_powerdns_zone_directory }}/{{ serveurs_powerdns_zone }}.zone"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify: Validate and reload PowerDNS
|
||||
|
||||
- name: Activer et démarrer PowerDNS
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ serveurs_powerdns_service_name }}"
|
||||
enabled: true
|
||||
state: started
|
||||
4
roles/serveurs_powerdns/templates/bindbackend.conf.j2
Normal file
4
roles/serveurs_powerdns/templates/bindbackend.conf.j2
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
zone "{{ serveurs_powerdns_zone }}" {
|
||||
type master;
|
||||
file "{{ serveurs_powerdns_zone_directory }}/{{ serveurs_powerdns_zone }}.zone";
|
||||
};
|
||||
9
roles/serveurs_powerdns/templates/chezlepro-bind.conf.j2
Normal file
9
roles/serveurs_powerdns/templates/chezlepro-bind.conf.j2
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
launch+=bind
|
||||
bind-config={{ serveurs_powerdns_bind_config }}
|
||||
local-address={{ serveurs_powerdns_listen_addresses | join(',') }}
|
||||
{% if serveurs_powerdns_allow_axfr_ips | length > 0 %}
|
||||
allow-axfr-ips={{ serveurs_powerdns_allow_axfr_ips | join(',') }}
|
||||
disable-axfr=no
|
||||
{% else %}
|
||||
disable-axfr=yes
|
||||
{% endif %}
|
||||
26
roles/serveurs_powerdns/templates/zone.db.j2
Normal file
26
roles/serveurs_powerdns/templates/zone.db.j2
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
$ORIGIN {{ serveurs_powerdns_zone }}.
|
||||
$TTL {{ serveurs_powerdns_ttl }}
|
||||
@ IN SOA {{ serveurs_powerdns_nameserver }}.{{ serveurs_powerdns_zone }}. {{ serveurs_powerdns_contact }}. (
|
||||
{{ serveurs_powerdns_serial }}
|
||||
{{ serveurs_powerdns_soa_refresh }}
|
||||
{{ serveurs_powerdns_soa_retry }}
|
||||
{{ serveurs_powerdns_soa_expire }}
|
||||
{{ serveurs_powerdns_soa_minimum }}
|
||||
)
|
||||
|
||||
@ IN NS {{ serveurs_powerdns_nameserver }}.{{ serveurs_powerdns_zone }}.
|
||||
{{ serveurs_powerdns_nameserver }} IN A {{ hostvars[groups['serveurs_powerdns'][0]].ansible_host | default('127.0.0.1') }}
|
||||
|
||||
{% for record in serveurs_powerdns_records %}
|
||||
{{ record.name }} IN {{ record.type }} {{ record.value }}
|
||||
{% endfor %}
|
||||
|
||||
{% set emitted = [] %}
|
||||
{% for group_name in serveurs_powerdns_inventory_groups %}
|
||||
{% for host_name in groups.get(group_name, []) | sort %}
|
||||
{% if hostvars[host_name].ansible_host is defined and host_name not in emitted %}
|
||||
{{ host_name }} IN A {{ hostvars[host_name].ansible_host }}
|
||||
{% set _ = emitted.append(host_name) %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
Reference in a new issue