Handbook sections▾
Foundations
Understanding the threats to a Linux hostWhy we hardenThe defense principles behind every ruleEffective configuration: the truth no file holdsThe standards Pavois maps toSOCLE control ID modelEvidence & exportsHow the A-E grade is computedWhat a PASS proves: the qualified verdictTrust model for the evidence bundleIs SOCLE just your own norm? (governance & the circularity question)What Pavois covers, and what it doesn'tDomains
Hardening SSHHardening PAMMandatory Access Control (SELinux / AppArmor)Hardening the host firewallHardening sudoFile Permissions & OwnershipMount & filesystem hardeningHardening kernel modulesHardening the kernel & network with sysctlAudit logging with auditdHardening logging with journald and rsyslogHardening systemd servicesPackage hygieneHardening the bootloader (GRUB)Synchronizing timeLogin banners and MOTDControlling cron and at accessHardening the GNOME desktop (dconf)Tooling
Undo a hardening run: restore pointsOperating Pavois: privileges, air-gap, timing, exceptionsRun Pavois in CI (GitHub Actions)Feature status: delivered, partial, roadmapGovernance: licence, versioning, provenance, securitySynchronizing time
Last reviewed
An accurate clock is invisible plumbing for security: logs, certificates and Kerberos all break when it drifts. Keep one trustworthy, authenticated NTP source disciplining the system clock.
The threat: every control silently assumes the clock is correct
Time is not a security control in itself, but almost every security control silently assumes the clock is correct. Left unsynchronized, a system clock drifts: quartz oscillators alone lose or gain seconds per day, and virtual machines drift far worse after migrations or host pauses. The consequences are exactly where an incident hurts most:
- Forensics become unreliable. When you stitch together logs from a dozen hosts to reconstruct an attack, skewed timestamps scramble the order of events. A few minutes of drift can hide the true entry point or make a response look like it happened before the breach.
- Authentication breaks. Kerberos rejects tickets when the clock is off by more than its tolerance (typically 5 minutes), and TLS validates certificates against
notBefore/notAfterwindows: a wrong clock either accepts an expired certificate or rejects a valid one. - An attacker can weaponize it. Tampering with the clock can push expired certificates back into validity, replay time-bounded tokens, or smear an intrusion across log timelines to defeat correlation. A rogue or spoofed NTP source is a real attack vector, which is why authenticated time matters.
Why harden it
Correct time is a prerequisite for trusting everything else. Your audit trail, certificate chain, scheduled renewals and authentication all rest on every host agreeing on now. PCI-DSS (requirement 10) and ANSSI BP-028 explicitly require a common, trusted time reference so that audit logs are admissible and correlatable. Hardening time synchronization is cheap insurance that keeps the rest of your hardening honest.
Defense principles applied
- A single source of truth: exactly one daemon should discipline the clock.
chrony,ntp/ntpsecandsystemd-timesyncdfight over the system clock if more than one runs; pick one and mask the others. - An authenticated source: point at a controlled internal server or a reputable pool, and prefer NTS (Network Time Security, RFC 8915) so a spoofed source can't slew your clock. NTS wraps NTP in TLS-backed authentication.
- Reject implausible jumps:
maxchangerejects a server that suddenly claims a huge offset (an anti-spoofing guard); prefer slewing over stepping on sensitive hosts so a large offset doesn't disrupt databases or TLS, withmakestepbounded to early boot. - Don't become an NTP server: a host that answers NTP queries can be abused for amplification DDoS. chrony does not serve by default; keep it that way (no
allow), and bind the control socket to localhost. - Audit the effective state, not the package: a time daemon can be installed and configured yet
masked,failedor stopped; only the running unit actually keeps time.
How do you set it up?
# /etc/chrony/chrony.conf -- authenticated, single source, safe stepping
server time.cloudflare.com iburst nts # NTS-authenticated upstream
ntsdumpdir /var/lib/chrony
makestep 1.0 3 # step only during the first 3 updates (boot), then slew
maxchange 1000 1 2 # reject a source that jumps the clock implausibly
rtcsync
# no 'allow' line: do not serve time to the networkThen systemctl enable --now chronyd and systemctl mask systemd-timesyncd ntp so only one daemon disciplines the clock.
What Pavois audits: the live unit state
Pavois asks systemd for the live unit state rather than checking a config file or an installed package. The time-sync-present rule runs systemctl is-active across every known time daemon (chrony, chronyd, systemd-timesyncd, ntp, ntpsec) and passes as soon as any one is running. This is the effective-configuration angle: a daemon can be present and fully configured yet masked or failed, in which case the clock is not disciplined and a file-based scan would wrongly report success. To remediate, pavois harden apply uses a choose resource that installs and enables chrony by default (with systemd-timesyncd as the lightweight alternative). The rule maps to ANSSI BP-028 R71, CIS 2.3.x, PCI-DSS 10.6.1, NIST 3.3.7 and the Ubuntu STIG time controls.
Verify
timedatectl # 'System clock synchronized: yes', 'NTP service: active'
chronyc tracking # offset, stratum, leap status, last update
chronyc sources -v # which servers, reachability, selected source (*)
chronyc authdata # NTS cookies present => the source is authenticated
chronyc ntpdata # per-source detail incl. auth statePitfalls
- Two time daemons fight: chrony and
systemd-timesyncdboth active will slew against each other. Mask all but one. - A firewall blocking UDP/123 (or NTS-KE TCP/4460) silently kills sync: the daemon runs but never reaches a source. Check
chronyc sources. makestepleft permanent re-steps the clock at runtime: bound it to early boot (makestep 1.0 3) so production never jumps mid-session.- Containers usually share the host clock: run the time daemon on the host/VM, not inside every container.
FAQ
How do I stop an attacker spoofing my time source? Use NTS (server ... nts) so the upstream is cryptographically authenticated, and set maxchange to reject implausible jumps. Verify with chronyc authdata.
Why does Pavois check is-active instead of the config? Because a configured daemon that is masked/failed keeps no time; only the running unit disciplines the clock, so the live state is the truth.
chrony or systemd-timesyncd? chrony for servers (NTS, better accuracy, handles intermittent networks); systemd-timesyncd is a lightweight SNTP client fine for minimal or container-adjacent hosts. Run exactly one.