Debian GNU/Linux · Services

Configure chrony with time sources, run it unprivileged and keep it running

When it fails: chrony has no time source, runs as root or is not running. The clock is not synchronized, or the NTP daemon parses network traffic with full privileges.

CB-DEB-SVC-016lowactiveautomatedautomated fixprofile core

Description

chrony reads its sources (server, pool or peer lines) from /etc/chrony/chrony.conf and the files included by Debian's default configuration: /etc/chrony/conf.d/*.conf and /etc/chrony/sources.d/*.sources. After start-up, chronyd drops root privileges to the _chrony user unless the user directive or the -u option says otherwise. The service chrony.service must be enabled and running.

The sources are site-specific, so the fix only enables and starts the service; adding sources and removing a user root setting are manual.

Rationale

Without a source the clock drifts. chronyd parses packets from the network; running it as an unprivileged user limits what a flaw in that code can reach. A stopped daemon leaves the clock unsynchronized.

Impact

None known with the Debian defaults, which use the Debian NTP pool and the _chrony user.

Applies when

Detected: when: chrony is installed A scanner reports the control not applicable when one is false.

Audit

  1. grep -E '^[[:space:]]*(server|pool|peer)[[:space:]]' /etc/chrony/chrony.conf /etc/chrony/conf.d/*.conf /etc/chrony/sources.d/*.sources must list approved sources.
  2. ps -C chronyd -o user= must print _chrony.
  3. systemctl is-enabled chrony must print enabled and systemctl is-active chrony active.

Automated: every check must pass. Scanners report each check by its id.

sources

chrony has at least one server, pool or peer source.

script: |
  o=$(grep -hEs '^[[:space:]]*(server|pool|peer)[[:space:]]' /etc/chrony/chrony.conf \
    /etc/chrony/conf.d/*.conf /etc/chrony/sources.d/*.sources | head -n 5)
  if [ -z "$o" ]; then echo "no server, pool or peer directive"; exit 1; fi
  printf '%s\n' "$o"

user

chronyd runs as _chrony.

script: |
  u=$(ps -C chronyd -o user= 2>/dev/null | sort -u | tr -d ' ' | tr '\n' ' ')
  echo "chronyd user: ${u:-not running}"
  [ "$u" = "_chrony " ]

enabled

chrony is enabled.

unit: chrony.service
state: enabled

active

chrony is running.

script: systemctl is-active chrony.service || exit 1

Remediation

  1. Add approved sources in /etc/chrony/sources.d/local.sources, one per line, for example server ntp1.example.org iburst, then run chronyc reload sources.
  2. Remove any user directive other than user _chrony from the chrony configuration and any -u option from DAEMON_OPTS in /etc/default/chrony.
  3. Run systemctl enable --now chrony.
Restartnone
Disruptionnone

Rollback

Run systemctl disable --now chrony.

enabled

Generated from check enabled: the engine writes the fix for every output, it sets the expected value and the check runs again after.

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

Mappings

FrameworkIDRelation
NIST SP 800-53 Rev. 55.1.1AU-8(1)partial
NIST SP 800-53 Rev. 55.1.1AC-6related

How this control relates to the other framework's: equivalent, stricter, looser, partial or related.

Threats mitigated

People and lifecycle

Authors
Verified2026-10-18 by Sn0wAlice on 12, Proxmox VM, Debian 12 genericcloud image, kernel 6.1.0-54-cloud-amd64. Not applicable without chrony; with chrony installed and disabled the enabled, active and user checks fail, fix enables and starts it, audit passes after reboot.
Verified2026-10-18 by Sn0wAlice on 13, Proxmox VM, Debian 13 genericcloud image, kernel 6.12.113+deb13-cloud-amd64. Not applicable without chrony; with chrony installed and disabled the enabled, active and user checks fail, fix enables and starts it, audit passes after reboot.
Introduced inv0.1.0
Created, updated2026-10-18, 2026-10-18
Translationsfr