Linux hosts

Time sync and why security needs it, the secure way

The incident timeline says the attacker logged in four seconds before the password was guessed. Either you have a time traveler, or one of your hosts has been quietly running slow for months.

The short answer

Run chrony with at least three independent NTS servers (server ... iburst nts), set minsources 2 so one bad or lone source cannot move the clock, keep NTS cookies in ntsdumpdir, install CA certificates, and disable the NTP server port on clients. Check chronyc authdata, sources and tracking, and alert when a host is not synchronised.

Updated Houssam Hammoudi, CTOTested with chrony 4.3 (Debian 12)

On this page
  1. What goes wrong
  2. What the docs say
  3. The secure configuration
  4. Prove it
  5. Mistakes people make
  6. Checklist

What goes wrong

Security depends on clocks in more places than people expect:

  • TLS accepts a certificate only between its "not before" and "not after" dates. A clock that is days off rejects valid certificates, or accepts expired ones.
  • Kerberos refuses tickets when clocks differ by more than a few minutes (300 seconds by default).
  • One-time codes (TOTP) change every 30 seconds. A drifting server rejects correct codes, and people start asking for the check to be turned off.
  • Logs from different hosts only form a timeline if their clocks agree. During an incident, a few seconds of drift can put effect before cause.

Plain NTP has no authentication. Anyone who can answer a host's NTP packets first, on a shared network or in the path, can move its clock. Moving a clock back can make an expired certificate valid again, or replay an old signed DNS answer.

What the docs say

This memo specifies Network Time Security (NTS), a cryptographic security mechanism for network time synchronization.

Source: RFC 8915, Network Time Security for the Network Time Protocol

NTS has a Key Establishment (NTS-KE) protocol using the Transport Layer Security (TLS) protocol to get the keys and cookies required by NTS for authentication of NTP packets.

Source: chrony.conf(5), the nts option

The minsources directive sets the minimum number of sources that need to be considered as selectable in the source selection algorithm before the local clock is updated. The default value is 1.

Source: chrony.conf(5), minsources

The systemd-timesyncd.service service implements SNTP only.

Source: systemd-timesyncd.service(8)

The chrony docs explain each option, but not the chicken-and-egg problem: NTS uses TLS, TLS checks certificate dates, and a host with a very wrong clock cannot check them. The nocerttimecheck directive exists for that, and the docs call it a last resort. The timesyncd.conf(5) page lists no NTS option.

The secure configuration

bash
apt-get install -y chrony ca-certificates     # dnf install -y chrony on RHEL family
systemctl disable --now systemd-timesyncd 2>/dev/null || true   # one time daemon, not two
conf
# /etc/chrony/chrony.conf (/etc/chrony.conf on RHEL family)
# nts = Network Time Security (RFC 8915): the answers are authenticated.
server time.cloudflare.com iburst nts
server nts.netnod.se iburst nts
server ptbtime1.ptb.de iburst nts
server ntppool1.time.nl iburst nts
# Keep NTS cookies across restarts so a restart does not need a new key exchange.
ntsdumpdir /var/lib/chrony
# Refuse to act on fewer than two agreeing sources.
minsources 2
# Step the clock only in the first three updates after start; slew afterwards.
makestep 1.0 3
# Do not serve time to anyone; this host is a client only.
port 0
# No UDP command port; chronyc talks over the local Unix socket only.
cmdport 0
driftfile /var/lib/chrony/chrony.drift
rtcsync
leapsectz right/UTC
bash
systemctl restart chrony          # "chronyd" on RHEL family
chronyc -N authdata               # NTS column and cookies per server
chronyc -N sources                # '*' marks the source in use
chronyc tracking                  # Leap status must be Normal

NTS needs outbound TCP 4460 for the key exchange and UDP 123 for time. If a firewall blocks either, the source stays unreachable. Use servers run by different organizations, so one operator's mistake cannot move your clock. Inside a company network, point hosts at two or more internal NTS servers instead.

Prove it

The key exchange worked with all four servers. NTS in the mode column and cookies (Cook) mean the NTP packets from these servers are authenticated:

bash
chronyc -N authdata
text
Name/IP address             Mode KeyID Type KLen Last Atmp  NAK Cook CLen
=========================================================================
time.cloudflare.com          NTS     1   15  256   37    1    0    1   96
nts.netnod.se                NTS     1   15  256   37    0    0    8  100
ptbtime1.ptb.de              NTS     1   15  256   36    1    0    1  100
ntppool1.time.nl             NTS     1   15  256   37    1    0    1   96

From the test network, only one server answered on UDP 123. With minsources 2, chrony does not trust a lone source, and the host reports that it is not synchronised:

bash
chronyc -N sources
chronyc tracking | grep -E "^(Reference ID|Stratum|Leap status)"
text
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
^? time.cloudflare.com           0   7     0     -     +0ns[   +0ns] +/-    0ns
^- nts.netnod.se                 1   6    17    30  -4277ms[-4277ms] +/-   82ms
^? ptbtime1.ptb.de               0   7     0     -     +0ns[   +0ns] +/-    0ns
^? ntppool1.time.nl              0   7     0     -     +0ns[   +0ns] +/-    0ns
Reference ID    : 00000000 ()
Stratum         : 0
Leap status     : Not synchronised

The same host with minsources 1 accepts the single source (^*):

text
MS Name/IP address         Stratum Poll Reach LastRx Last sample               
===============================================================================
^? time.cloudflare.com           0   7     0     -     +0ns[   +0ns] +/-    0ns
^* nts.netnod.se                 1   6    27    28  -4265ms[-4265ms] +/-   86ms
^? ptbtime1.ptb.de               0   7     0     -     +0ns[   +0ns] +/-    0ns
^? ntppool1.time.nl              0   7     0     -     +0ns[   +0ns] +/-    0ns
Reference ID    : C23ACCC5 (mmo2-ts.nts.netnod.se)
Stratum         : 2
Leap status     : Normal

The Last sample column also shows something real: the test machine's clock was about 4.3 seconds behind. The container ran chronyd with -x, so it measured the error without changing the clock. A host in that state would log every event 4.3 seconds early. The test script is secure-tests/time-sync-security/run.sh.

Mistakes people make

One time server

A single source cannot be checked against anything. If it is wrong, or spoofed, the host follows it. Use at least three, and minsources 2.

Assuming SNTP is enough

systemd-timesyncd is fine for a laptop. It does not authenticate time. For servers, run chrony with NTS.

Forgetting CA certificates

NTS uses TLS. A minimal image without ca-certificates fails the key exchange with "The certificate issuer is unknown", and falls back to nothing.

Serving time by accident

A client that also answers NTP queries can be used in reflection attacks. port 0 turns the server side off.

Not alerting on "Not synchronised"

A host can run for months without a working source. Alert when chronyc tracking shows Leap status : Not synchronised, or when the offset passes a limit you choose, for example 100 ms.

Checklist

  • chrony is the only time daemon on the host.
  • At least three server ... iburst nts lines point at different operators.
  • minsources 2 is set.
  • ntsdumpdir is set and the directory exists.
  • ca-certificates is installed.
  • port 0 is set on hosts that do not serve time.
  • chronyc -N authdata shows NTS for every server.
  • chronyc tracking shows Leap status : Normal.
  • An alert fires when a host is not synchronised.

Every log line you will ever use in an investigation starts with a timestamp. Make sure the clock that wrote it was telling the truth.

FND

Learn it on a live range

Linux 2: the kernel, storage, networks and the services a host runs, in Foundation: a real host in your browser, and every objective checked on the machine.

Start free

The Secure Way

More on linux hosts

SSH, sudo, firewalls, mount options, updates and the host basics every engineer should get right.

All linux hosts guides