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.
On this page
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
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# /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/UTCsystemctl 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 NormalNTS 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:
chronyc -N authdataName/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 96From 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:
chronyc -N sources
chronyc tracking | grep -E "^(Reference ID|Stratum|Leap status)"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 synchronisedThe same host with minsources 1 accepts the single source (^*):
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 : NormalThe 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 ntslines point at different operators. minsources 2is set.ntsdumpdiris set and the directory exists.ca-certificatesis installed.port 0is set on hosts that do not serve time.chronyc -N authdatashowsNTSfor every server.chronyc trackingshowsLeap 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 freeThe 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