Description
systemd-timesyncd is a simple SNTP client. Its servers are set with NTP= in
/etc/systemd/timesyncd.conf or in a drop-in under /etc/systemd/timesyncd.conf.d/. Without
NTP=, it only uses the FallbackNTP= list compiled into the package. The service must be
enabled and running.
The check reads the merged configuration with systemd-analyze cat-config and keeps the last
NTP= line, which is the one systemd applies. Ubuntu ships no NTP= line (only the commented
FallbackNTP=ntp.ubuntu.com), so the control fails on a fresh install of 20.04 to 24.04. On
26.04, chrony replaces systemd-timesyncd and the control is not applicable. The fix writes /etc/systemd/timesyncd.conf.d/60-cirsec.conf.
Check and swap the default servers. time_servers defaults to ntp.ubuntu.com, the
server Ubuntu already falls back to, so that the fix works everywhere. It is not an approved source: replace it in the tailoring file
with your organization's own time servers (internal NTP, domain controllers, or a provider you
trust) before applying the fix in production.
Rationale
Explicit servers make the time source a documented choice: internal servers for isolated networks, or a public pool the organization trusts. A stopped client lets the clock drift, which breaks log correlation and time-based authentication.
Impact
The system contacts the configured servers on UDP port 123; the firewall must allow it. When
the default list is kept, the server is ntp.ubuntu.com, run by Canonical.
Applies when
Detected: when: systemd-timesyncd is installed A scanner reports the control not applicable when one is false.
Setting
| Location | /etc/systemd/timesyncd.conf.d/60-cirsec.conf |
| Default | No NTP= line (compiled-in fallback servers) |
| Recommended | NTP={{ time_servers }} |
Parameters
| Parameter | Core | Server | Server hardened | Desktop | Desktop hardened | Bounds |
|---|---|---|---|---|---|---|
time_serversstring. Space-separated list of approved NTP servers, written by the fix. | ntp.ubuntu.com | ntp.ubuntu.com | ntp.ubuntu.com | ntp.ubuntu.com | ntp.ubuntu.com |
The value used is your override (tailoring file), else the profile's, else the one of the profile it extends, else the default. Bounds limit what an override may set.
Audit
- Run
systemd-analyze cat-config systemd/timesyncd.conf. The lastNTP=line must list at least one approved server. systemctl is-enabled systemd-timesyncdmust printenabledandsystemctl is-active systemd-timesyncdmust printactive.
Automated: every check must pass. Scanners report each check by its id.
servers
Time servers set with NTP= in the merged configuration.
script: |
o=$(systemd-analyze cat-config systemd/timesyncd.conf 2>/dev/null | grep -E '^[[:space:]]*NTP=' | tail -n 1)
v=$(printf '%s' "$o" | sed 's/^[[:space:]]*NTP=[[:space:]]*//')
echo "NTP=${v:-<not set>}"
[ -n "$v" ]
enabled
systemd-timesyncd is enabled.
unit: systemd-timesyncd.service
state: enabled
active
systemd-timesyncd is running.
script: systemctl is-active systemd-timesyncd.service || exit 1
Remediation
Create /etc/systemd/timesyncd.conf.d/60-cirsec.conf containing:
[Time]
NTP={{ time_servers }}
then run systemctl enable systemd-timesyncd and systemctl restart systemd-timesyncd.
Check with timedatectl timesync-status.
| Restart | service: systemd-timesyncd |
| Disruption | none |
Rollback
Delete /etc/systemd/timesyncd.conf.d/60-cirsec.conf and restart systemd-timesyncd.
enabled
Generated from check enabled: the engine writes the fix for every output, it sets the expected value and the check runs again after.
servers
f=/etc/systemd/timesyncd.conf.d/60-cirsec.conf
want=$(printf '# Written by CIRSEC Baselines CB-UBU-SVC-015\n[Time]\nNTP=%s' "$CB_TIME_SERVERS")
if [ "$(cat "$f" 2>/dev/null)" != "$want" ]; then
cb_backup "$f"
mkdir -p /etc/systemd/timesyncd.conf.d
printf '%s\n' "$want" >"$f"
fi
systemctl is-active --quiet systemd-timesyncd.service || systemctl start systemd-timesyncd.service
Handwritten code reads parameters from CB_<NAME> environment variables. Each release turns these fixes into remediate.sh and an Ansible role per profile: dry run by default, a fix runs only when its check fails.
References
- timesyncd.conf(5), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- systemd-timesyncd.service(8), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- Ubuntu Server documentation - Synchronize time using timedatectl and timesyncd Canonical, vendor-doc, accessed 2026-10-19
Mappings
| Framework | ID | Relation |
|---|---|---|
| NIST SP 800-53 Rev. 55.1.1 | AU-8(1) | partial |
How this control relates to the other framework's: equivalent, stricter, looser, partial or related.
Threats mitigated
| Taxonomy | ID |
|---|---|
| MITRE ATT&CK | T1070.006 |
Related controls
- related
CB-UBU-SVC-014Run exactly one time synchronization daemon
People and lifecycle
| Authors |
|
| Verified | 2026-10-19 by Sn0wAlice on 20.04, Proxmox VM, Ubuntu 20.04 cloud image, kernel 5.4.0-216-generic. Stock image fails (no NTP=); fix writes timesyncd.conf.d/60-cirsec.conf with ntp.ubuntu.com, clock synchronized after reboot; not applicable once chrony replaced timesyncd. |
| Verified | 2026-10-19 by Sn0wAlice on 22.04, Proxmox VM, Ubuntu 22.04 cloud image, kernel 5.15.0-198-generic. Stock image fails (no NTP=); fix writes timesyncd.conf.d/60-cirsec.conf with ntp.ubuntu.com, clock synchronized after reboot; not applicable once chrony replaced timesyncd. |
| Verified | 2026-10-19 by Sn0wAlice on 24.04, Proxmox VM, Ubuntu 24.04 cloud image, kernel 6.8.0-147-generic. Stock image fails (no NTP=); fix writes timesyncd.conf.d/60-cirsec.conf with ntp.ubuntu.com, clock synchronized after reboot; not applicable once chrony replaced timesyncd. |
| Verified | 2026-10-19 by Sn0wAlice on 26.04, Proxmox VM, Ubuntu 26.04 cloud image, kernel 7.0.0-38-generic. Not applicable: chrony replaces systemd-timesyncd on 26.04. |
| Introduced in | v0.1.0 |
| Created, updated | 2026-10-19, 2026-10-19 |
| Translations | fr |