chore: replace ntpd by chrony

This commit is contained in:
Clément Désiles 2025-12-13 23:49:39 +01:00
parent 93fa850f8e
commit 80093037a6
No known key found for this signature in database
12 changed files with 330 additions and 104 deletions

View File

@ -0,0 +1,92 @@
# Chrony NTP Client/Server
Modern NTP implementation for time synchronization. Chrony is designed for systems with intermittent network connectivity and is the default NTP client on modern Linux distributions.
## Features
- Fast initial time synchronization
- Client mode: sync time from NTP pools/servers
- Server mode: serve time to local network clients
- Automatic conflict resolution with systemd-timesyncd and ntpd
- Firewall integration for server mode
## Usage
### Client-only mode (default)
Sync time from public NTP pools, don't serve time to others:
```yaml
# host_vars/example.yml
ntp_timezone: "Europe/Paris"
ntp_pools:
- "0.fr.pool.ntp.org"
- "1.fr.pool.ntp.org"
- "2.fr.pool.ntp.org"
- "3.fr.pool.ntp.org"
```
### Server mode
Serve time to local network:
```yaml
# host_vars/ntp-server.yml
ntp_timezone: "UTC"
ntp_server_enabled: true
ntp_allowed_networks:
- 192.168.1.0/24 # Configures both chrony and firewall
- 192.168.27.0/27
```
### Client syncing from local server
```yaml
# host_vars/client.yml
ntp_pools: [] # Don't use public pools
ntp_servers:
- server: ntp.local.lan
options: iburst prefer
- server: 192.168.1.1
options: iburst
```
## Logging
**Default: journald** - Logs to systemd journal (recommended)
```bash
# View chrony logs
journalctl -u chronyd -f
```
**Optional: File-based logging** with automatic rotation
```yaml
ntp_log_backend: file
ntp_log_measurements: true
ntp_log_statistics: true
ntp_log_tracking: true
```
## Variables
See [defaults/main.yml](defaults/main.yml) for all configuration options.
## Verification
```bash
# Check chrony status
chronyc tracking
# Show current time sources
chronyc sources
# Show detailed source stats
chronyc sourcestats
```
## Resources
- [Arch Wiki: Chrony](https://wiki.archlinux.org/title/Chrony)
- [Chrony Documentation](https://chrony.tuxfamily.org/documentation.html)

View File

@ -0,0 +1,58 @@
---
# NTP pools/servers to sync from
ntp_pools:
- "0.arch.pool.ntp.org"
- "1.arch.pool.ntp.org"
- "2.arch.pool.ntp.org"
- "3.arch.pool.ntp.org"
# NTP servers (use pools instead for most cases)
ntp_servers: []
# Example:
# ntp_servers:
# - server: time.example.com
# options: iburst
# System timezone
ntp_timezone: "UTC"
# Enable NTP server functionality (allow others to sync from this server)
ntp_server_enabled: false
# NTP server port (standard is 123)
ntp_port: 123
# Networks allowed to query this NTP server (when server mode is enabled)
# Used for both chrony config and firewall rules
ntp_allowed_networks: []
# Example:
# ntp_allowed_networks:
# - 192.168.1.0/24
# - 192.168.27.0/27
# Maximum clock step allowed (0 = allow any step)
ntp_makestep_threshold: 1.0
ntp_makestep_limit: 3
# Enable hardware timestamping for better accuracy
ntp_hwtimestamp: false
# Drift file location
ntp_driftfile: /var/lib/chrony/drift
# RTC (hardware clock) sync
ntp_rtcsync: true
# Logging backend: 'journald' (systemd journal) or 'file' (traditional log files)
ntp_log_backend: journald
# File backend settings (only used when ntp_log_backend: file)
ntp_logdir: /var/log/chrony
ntp_log_measurements: false
ntp_log_statistics: false
ntp_log_tracking: false
# Logrotate configuration (only used when ntp_log_backend: file)
ntp_logrotate_rotate: 14 # Keep 14 days of logs
ntp_logrotate_frequency: daily # daily|weekly|monthly
ntp_logrotate_compress: true # Compress rotated logs

View File

@ -0,0 +1,5 @@
---
- name: Restart chrony
ansible.builtin.systemd:
name: "{{ ntp_service }}"
state: restarted

View File

@ -0,0 +1,92 @@
---
- name: Load OS-specific variables
ansible.builtin.include_vars: "{{ item }}"
with_first_found:
- "{{ ansible_facts['os_family'] }}.yml"
- "debian.yml"
- name: Install chrony
ansible.builtin.package:
name: chrony
state: present
- name: Set system timezone
community.general.timezone:
name: "{{ ntp_timezone }}"
notify: Restart chrony
- name: Ensure chrony drift file directory exists
ansible.builtin.file:
path: "{{ ntp_driftfile | dirname }}"
state: directory
owner: "{{ ntp_user }}"
group: "{{ ntp_group }}"
mode: "0755"
- name: Ensure chrony log directory exists
ansible.builtin.file:
path: "{{ ntp_logdir }}"
state: directory
owner: root
group: root
mode: "0755"
when: ntp_log_backend == 'file'
- name: Disable conflicting systemd-timesyncd service
ansible.builtin.systemd:
name: systemd-timesyncd
enabled: false
state: stopped
failed_when: false
- name: Disable conflicting ntpd service
ansible.builtin.systemd:
name: ntpd
enabled: false
state: stopped
failed_when: false
- name: Deploy chrony configuration
ansible.builtin.template:
src: chrony.conf.j2
dest: "{{ ntp_config_path }}"
owner: root
group: root
mode: "0644"
notify: Restart chrony
- name: Deploy logrotate configuration for chrony
ansible.builtin.template:
src: logrotate.conf.j2
dest: /etc/logrotate.d/chrony
owner: root
group: root
mode: "0644"
when: ntp_log_backend == 'file'
- name: Remove logrotate configuration when using journald
ansible.builtin.file:
path: /etc/logrotate.d/chrony
state: absent
when: ntp_log_backend == 'journald'
- name: Enable and start chrony service
ansible.builtin.systemd:
name: "{{ ntp_service }}"
enabled: true
state: started
- name: Setup firewall rules for NTP server
community.general.ufw:
rule: allow
port: "{{ ntp_port }}"
proto: udp
src: "{{ item }}"
direction: in
comment: "NTP server (chrony)"
loop: "{{ ntp_allowed_networks }}"
when: ntp_server_enabled and ntp_allowed_networks | length > 0
retries: 5
delay: 2
register: ufw_result
until: ufw_result is succeeded

View File

@ -0,0 +1,54 @@
# {{ ansible_managed }}
# Chrony configuration file
# NTP pools - use multiple pools for redundancy
{% for pool in ntp_pools %}
pool {{ pool }} iburst
{% endfor %}
# NTP servers (if configured)
{% for server in ntp_servers %}
server {{ server.server }} {{ server.options | default('iburst') }}
{% endfor %}
# Record the rate at which the system clock gains/loses time
driftfile {{ ntp_driftfile }}
# Allow the system clock to be stepped in the first few updates if offset is large
makestep {{ ntp_makestep_threshold }} {{ ntp_makestep_limit }}
{% if ntp_rtcsync %}
# Enable kernel synchronization of the real-time clock (RTC)
rtcsync
{% endif %}
{% if ntp_hwtimestamp %}
# Enable hardware timestamping on all interfaces that support it
hwtimestamp *
{% endif %}
# Serve time to clients (when server mode is enabled)
{% if ntp_server_enabled %}
# Listen on all interfaces for NTP requests
port {{ ntp_port }}
# Allow NTP client access from configured networks
{% for network in ntp_allowed_networks %}
allow {{ network }}
{% endfor %}
{% else %}
# Client-only mode: don't listen on NTP port
port 0
# Deny all client access (client-only mode)
deny all
{% endif %}
{% if ntp_log_backend == 'file' %}
# File-based logging (managed with logrotate)
logdir {{ ntp_logdir }}
log {{ [ntp_log_measurements and 'measurements', ntp_log_statistics and 'statistics', ntp_log_tracking and 'tracking'] | select | join(' ') }}
{% else %}
# Using journald/syslog for logging (default on systemd systems)
# View logs with: journalctl -u chronyd
{% endif %}

View File

@ -0,0 +1,17 @@
# {{ ansible_managed }}
# Logrotate configuration for chrony logs
{{ ntp_logdir }}/*.log {
{{ ntp_logrotate_frequency }}
rotate {{ ntp_logrotate_rotate }}
missingok
notifempty
{% if ntp_logrotate_compress %}
compress
delaycompress
{% endif %}
sharedscripts
postrotate
/usr/bin/killall -HUP chronyd 2>/dev/null || true
endscript
}

View File

@ -0,0 +1,6 @@
---
# Arch Linux specific variables
ntp_user: chrony
ntp_group: chrony
ntp_service: chronyd
ntp_config_path: /etc/chrony.conf

View File

@ -0,0 +1,6 @@
---
# Debian/Ubuntu specific variables
ntp_user: _chrony
ntp_group: _chrony
ntp_service: chrony
ntp_config_path: /etc/chrony/chrony.conf

View File

@ -1,24 +0,0 @@
---
# NTP configuration file
ntp_config_file: "/etc/ntp.conf"
# NTP servers to use.
ntp_pools: -" 0.uk.pool.ntp.org" -" 1.uk.pool.ntp.org" -" 2.uk.pool.ntp.org" -" 3.uk.pool.ntp.org"
# System timezone
ntp_timezone: "Europe/London"
# NTP drift file location
# (keeps track of your clock's time deviation)
ntp_drift_file: "/var/lib/ntp/ntp.drift"
# NTP security restrictions
ntp_restrict: "kod nomodify notrap nopeer noquery limited"
# Networks allowed to query this ntpd server
ntp_allowed_networks:
- "127.0.0.1"
- "::1"
# - "192.168.1.0 mask 255.255.255.0"
ntp_port: 123

View File

@ -1,6 +0,0 @@
---
- name: "Restart ntpd service"
ansible.builtin.systemd:
name: ntpd
state: restarted
daemon_reload: true

View File

@ -1,53 +0,0 @@
---
- name: Install NTP package
ansible.builtin.package:
name: "ntp"
state: present
update_cache: true
- name: Set system timezone to {{ ntp_timezone }}"
community.general.timezone:
name: "{{ ntp_timezone }}"
notify: "Restart ntpd service"
- name: Ensure NTP drift file directory exists
ansible.builtin.file:
path: "{{ ntp_drift_file | dirname }}"
state: directory
owner: "ntp"
group: "ntp"
mode: "0750"
- name: Setup systems timezone
community.general.timezone:
name: "{{ ntp_timezone }}"
notify: Restart chronyd # Redémarrer chrony peut être utile après un changement de TZ pour qu'il la prenne bien en compte dans ses logs/opérations
- name: "Configure {{ ntp_config_file }}"
ansible.builtin.template:
src: "ntp.conf.j2"
dest: "{{ ntp_config_file }}"
owner: root
group: root
mode: "0644"
notify: "Restart ntpd service"
- name: "Ensure ntpd service is started and enabled"
ansible.builtin.systemd:
name: "ntpd"
state: started
enabled: true
- name: "Configure ufw firewall"
community.general.ufw:
rule: allow
port: "{{ ntp_port }}"
proto: udp
src: "{{ item }}"
direction: in
comment: "NTP traffic"
loop: "{{ ntp_firewall_allowed_sources | default([]) }}"
retries: 5
delay: 2
register: ufw_result
until: ufw_result is succeeded

View File

@ -1,21 +0,0 @@
# {{ ansible_managed }}
#
# NTP configuration file for ntpd
restrict default {{ ntp_restrict }}
{% for network in ntp_allowed_networks %}
restrict {{ network }}
{% endfor %}
# Use servers from the NTP Pool Project. 'iburst' speeds up initial synchronization.
{% for pool_host in ntp_pools %}
pool {{ pool_host }} iburst
{% endfor %}
# Frequency drift file
driftfile {{ ntp_drift_file }}
# Disable the monitoring facility (monlist) to prevent ntpq -c monlist DDOS attacks.
# @see CVE-2013-5211
disable monitor