NTP

Rôle

Service de synchronisation horaire interne pour l'ensemble de l'infrastructure Indio, en remplacement des pools NTP publics pour toute la flotte. Le paquet indio-baseline-config (RPM déployé fleet-wide, voir Baseline config) configure chaque VM pour utiliser exclusivement ces 3 serveurs internes comme sources de temps.

Architecture

  • 3 nœuds chrony indépendants, sans VIP ni réplication entre eux (contrairement à PostgreSQL) : INDSERV005 (10.100.2.134), INDSERV006 (10.100.2.135), INDSERV007 (10.100.2.136), segment seg-service (10.100.2.128/26).
  • Chaque serveur se synchronise sur le pool public {0,1,2}.rocky.pool.ntp.org (3 sources amont, iburst) et sert le temps aux réseaux internes 10.100.0.0/16 et 10.15.0.0/16.
  • local stratum 10 configuré : chaque serveur continue à servir l'heure à ses clients même si les sources amont publiques deviennent injoignables.
  • makestep 1.0 3 (correction brutale de l'horloge autorisée sur les 3 premières mesures si l'écart dépasse 1s — utile juste après un boot) et rtcsync (synchronise l'horloge matérielle depuis le système, pas l'inverse).
  • Consommateurs : toute la flotte, via le drop-in /etc/chrony.d/indio-ntp.conf livré par le RPM indio-baseline-config (3 directives server ... iburst codées en dur sur les IP .134/.135/.136), qui vient s'ajouter à/remplacer la configuration chrony par défaut du template.

Structure du dépôt

Fichier Contenu
main.tf 3 VM (for_each), clone du template, IP via NetBox
variables.tf vsphere_network = "seg-service", nodes = [INDSERV005, INDSERV006, INDSERV007], vm_cpu = 1, vm_ram = 1024
versions.tf Providers hashicorp/vsphere (>= 2.6.0), e-breuninger/netbox (>= 5.0.0, < 6.0.0)
ansible/site.yml Play unique, rôle chrony_server, groupe ntp
ansible/group_vars/ntp.yml ntp_upstreams (pool public), ntp_allow_networks (réseaux internes) — aucun secret
ansible/roles/chrony_server/ Installation chrony, template chrony.conf, ouverture du service ntp (123/udp) dans firewalld
flowchart LR
    subgraph UPSTREAM["Pool public"]
        U0["0.rocky.pool.ntp.org"]
        U1["1.rocky.pool.ntp.org"]
        U2["2.rocky.pool.ntp.org"]
    end
    subgraph SEGSERVICE["seg-service — 10.100.2.128/26"]
        N1["INDSERV005<br/>10.100.2.134<br/>chronyd"]
        N2["INDSERV006<br/>10.100.2.135<br/>chronyd"]
        N3["INDSERV007<br/>10.100.2.136<br/>chronyd"]
    end
    U0 & U1 & U2 -. "3 sources amont, iburst" .-> N1
    U0 & U1 & U2 -. "3 sources amont, iburst" .-> N2
    U0 & U1 & U2 -. "3 sources amont, iburst" .-> N3
    N1 & N2 & N3 --> FLEET["Toute la flotte<br/>indio-ntp.conf (RPM indio-baseline-config)<br/>3 IP en dur, pas de VIP/round-robin"]

Provisioning Terraform

  • /root/ntp/main.tf clone 3 VM (for_each sur var.nodes) depuis tmpl-rocky96-hardened, IP assignées par NetBox (data.netbox_ip_addresses, filtre dns_name en minuscules).
  • Variables (variables.tf) : vsphere_network = "seg-service", vm_gateway = "10.100.2.190", vm_netmask = 26, nodes = [INDSERV005, INDSERV006, INDSERV007], vm_cpu = 1, vm_ram = 1024 — le plus petit gabarit de l'infra, cohérent avec un simple relais chrony.
  • lifecycle.ignore_changes sur annotation, clone[0].template_uuid, clone[0].customize, disk[0].io_share_count (pattern identique à tous les projets vSphere de l'infra).
  • Providers : hashicorp/vsphere (>= 2.6.0), e-breuninger/netbox (>= 5.0.0, < 6.0.0).
  • Identifiants vCenter/NetBox via terraform.tfvars (non versionné) ; modèle dans terraform.tfvars.example.

Configuration Ansible

Playbook /root/ntp/ansible/site.yml, rôle unique chrony_server appliqué au groupe ntp (les 3 nœuds) :

  • Installe le paquet chrony.
  • Déploie /etc/chrony.conf depuis chrony.conf.j2 : boucle pool {{ u }} iburst sur ntp_upstreams, boucle allow {{ n }} sur ntp_allow_networks, driftfile, makestep 1.0 3, rtcsync, local stratum 10, logdir /var/log/chrony.
  • Ouvre le service ntp (123/udp) dans firewalld (zone drop).
  • Active et démarre chronyd.

Aucun secret dans ce dépôt : ni group_vars/ntp.yml (upstreams et réseaux autorisés uniquement, en clair) ni ansible.cfg ne référencent de vault.

Procédure de déploiement

  1. terraform apply (dans /root/ntp) : clone les 3 VM et attribue leurs IP via NetBox.
  2. ansible-playbook site.yml (dans /root/ntp/ansible) : installe et configure chrony sur les 3 nœuds — rôle idempotent, pas d'ordre particulier entre les nœuds (contrairement à PostgreSQL, aucune dépendance primaire/standby ici).

Contrôle de santé / Vérification

  • chronyc tracking sur un nœud : Reference ID/Stratum doivent refléter une synchronisation active sur le pool public (stratum bas, typiquement 2-3) plutôt que le stratum local de secours (10).
  • chronyc sources -v : les 3 sources pool doivent apparaître avec un état ^*/^+ (synchronisée / candidate), pas ? (injoignable).
  • Côté client fleet-wide : chronyc sources doit lister les 3 IP 10.100.2.134/135/136 (pas le pool public par défaut) — confirme que indio-ntp.conf a bien pris effet.
  • firewall-cmd --list-services sur un des 3 nœuds doit inclure ntp.

Points d'attention

  • Pas de haute disponibilité au sens VIP/failover : les 3 serveurs sont indépendants ; c'est aux clients de configurer les 3 IP comme sources (ce que fait le RPM indio-baseline-config), pas un mécanisme de bascule automatique côté serveur — à la différence de PostgreSQL (VIP keepalived) ou de Zabbix (HA natif).
  • Round-robin DNS envisagé : un enregistrement DNS ntp.infra.indio en round-robin sur les 3 IP est prévu côté AD pour simplifier la configuration client, mais n'est pas encore en place à ce jour.
  • Dépendance de toute la flotte : une panne simultanée des 3 nœuds dégraderait la synchronisation horaire de l'ensemble de l'infrastructure (chaque hôte reste toutefois capable de tenir l'heure localement un moment via son horloge système, rtcsync gardant l'horloge matérielle à jour).
  • Couplage avec le socle : le remplacement du pool public par les 3 IP internes est réalisé par le RPM indio-baseline-config (hors de ce dépôt), pas par ce rôle Ansible — un hôte qui n'aurait pas ce RPM (VM hors baseline) continuerait à interroger le pool public par défaut.