Updated May 2025
Instructions for setting up an NTP server
(with AES-128-CMAC authentication support)
Follow these instructions to set up an NTP server in a Linux environment using
the package and using AES-CMAC 128 bits
as the hash algorithm for the authentication mechanism in client-server communication.
Chrony must be built from Source for AES CMAC support
To use chrony with support for AES-CMAC 128, version 4.0 or above has to be installed in your system. As
mentioned in the release notes, chrony 4.0 provided support
for AES CMAC functions with Nettle dependency. Neither Ubuntu 18.04 nor Ubuntu 20.04 provide a chrony package
version with AES-CMAC support in their LTS releases.
Instructions
1. Install dependencies of chrony before building it from source
The list of dependencies can be viewed here: https://chrony.tuxfamily.org/doc/4.1/installation.html. Download all the dependencies.
1sudo apt-get install libcap2 libseccomp2 pkg-config nettle-dev
nettle is the required package for enabling CMAC support in chrony. If
nettle-dev
nettle/cmac.h
hogweed.so
nettle.so
/usr/
For AL2 EC2 instances,
1sudo yum install libcap libseccomp pkg-config nettle-dev
pkg-config and nettle-dev might not be found. Go to step 2.
2. (Optional) Install Nettle from Source
The build and install instructions for Nettle are here: https://www.linuxfromscratch.org/blfs/view/svn/postlfs/nettle.html.
Follow these instructions to install the package.
2.1 Download source and unzip
1wget https://ftp.gnu.org/gnu/nettle/nettle-3.9.1.tar.gz2tar -xvf tar -xvf nettle-3.9.1.tar.gz
2.2 Build and install from source
1./configure --prefix=/usr --disable-static && make -j82sudo make install3sudo chmod -v 755 /usr/lib/lib{hogweed,nettle}.so
Verify the installation of Nettle by looking for the
cmac.h
/usr/include/nettle
libogweed.so
libnettle.so
/usr/lib
3. Build chrony from source
As mentioned earlier, chrony >= 4.0 is required for AES-CMAC authentication support (with Nettle). Thus, here are the instructions for building and installing it from source.
3.1 Clone the respository and checkout the latest release tag
Replace
4.1
1git clone https://git.tuxfamily.org/chrony/chrony.git2git checkout tags/4.1
3.2 Configure the build with system information of Nettle installation (and desired chrony.conf location)
The
./configure --help
configure
For my environment, I had to specify the folder path for the Nettle package's include and shared library files by setting the
CPPFLAGS
LDFLAGS
chrony.conf
chrony.keys
---sysconfdir=<DIR>
In addition, I configured the installation to be in the
/usr/sbin/
usr/bin
--prefix=/usr
1export CPPFlAGS='-I/usr/include'2export LDFLAGS='-L/usr/lib'3./configure --prefix=/usr --sysconfdir=/etc/chrony4
Ensure that the build configuration logs show that
nettle
SECHASH
chrony
SECHASH
This is how the tail end of the logs should look:
1Checking for nettle : Yes2Checking for CMAC in nettle : Yes3Checking for gnutls : No4Features : +CMDMON +NTP +REFCLOCK +RTC -PRIVDROP -SCFILTER -SIGND +ASYNCDNS -NTS -READLINE +SECHASH +IPV6 -DEBUG5Creating Makefile6Creating doc/Makefile7Creating test/unit/Makefile8
3.3 Build and Install chrony!
Build and install the chrony package in your system.
1make -j 82sudo make install
The above instructions will install chronyc and chronyd binaries in your system. (chronyd is the actual daemon that performs NTP client/server operations whereas chronyc is the user-facing client utility to query the status of the daemon.)
You will see something like the following installation log. Note: Errors about documentation output installation can be ignored as the required dependencies of chrony for documentation were not installed.
1─> sudo make install23[ -d /etc/chrony ] || mkdir -p /etc/chrony4[ -d /usr/sbin ] || mkdir -p /usr/sbin5[ -d /usr/bin ] || mkdir -p /usr/bin6[ -d /var/lib/chrony ] || mkdir -p /var/lib/chrony7if [ -f /usr/sbin/chronyd ]; then rm -f /usr/sbin/chronyd ; fi8if [ -f /usr/bin/chronyc ]; then rm -f /usr/bin/chronyc ; fi9cp chronyd /usr/sbin/chronyd10chmod 755 /usr/sbin/chronyd11cp chronyc /usr/bin/chronyc12chmod 755 /usr/bin/chronyc13make -C doc install14make[1]: Entering directory '/home/ubuntu/Experiments/chrony/doc'15asciidoctor -b manpage -o chrony.conf.man.in chrony.conf.adoc16make[1]: asciidoctor: Command not found17Makefile:44: recipe for target 'chrony.conf.man.in' failed18make[1]: *** [chrony.conf.man.in] Error 12719make[1]: Leaving directory '/home/ubuntu/Experiments/chrony/doc'20Makefile:88: recipe for target 'install' failed21make: *** [install] Error 2
3.4 Verify the installation
Verify that the chronyc and chronyd files have been installed in the system.
1─> chronyc --version2chronyc (chrony) version DEVELOPMENT (-READLINE +SECHASH +IPV6 -DEBUG)
1ls -la /usr/sbin/chronyd
Also, verify with the
keygen
1─> chronyc keygen 1 AES128 12821 AES128 HEX:6CD5CA79D68B815093BA1DEC9DBD691C
4. Configure reference NTP servers for chrony (before configuring it as a server)
Before you run
chrony
4.1 Setup the chrony.conf file
The
chrony.conf
/etc/chrony/chrony.conf
169.254.169.123
1# Welcome to the chrony configuration file. See chrony.conf(5) for more2# information about usuable directives.34pool ntp.ubuntu.com iburst maxsources 45pool 0.ubuntu.pool.ntp.org iburst maxsources 16pool 1.ubuntu.pool.ntp.org iburst maxsources 17pool 2.ubuntu.pool.ntp.org iburst maxsources 28server 169.254.169.123 prefer iburst minpoll 4 maxpoll 4910# This directive specify the location of the file containing ID/key pairs for11# NTP authentication.12keyfile /etc/chrony/chrony.keys1314# This directive specify the file into which chronyd will store the rate15# information.16driftfile /var/lib/chrony/chrony.drift1718# Uncomment the following line to turn logging on.19log tracking measurements statistics2021# Log files location.22logdir /var/log/chrony2324# Stop bad estimates upsetting machine clock.25maxupdateskew 100.02627# This directive enables kernel synchronisation (every 11 minutes) of the28# real-time clock. Note that it can’t be used along with the 'rtcfile' directive.29rtcsync3031# Step the system clock instead of slewing it if the adjustment is larger than32# one second, but only in the first three clock updates.33makestep 1 3
4.2 Create chronyd.service file
The
chronyd.service
/etc/systemd/system/
1─> sudo cat /etc/systemd/system/chronyd.service2[Unit]3Description=chrony, an NTP client/server4Documentation=man:chronyd(8) man:chronyc(1) man:chrony.conf(5)5Conflicts=systemd-timesyncd.service openntpd.service6After=network.target78[Service]9Type=forking10PIDFile=/run/chrony/chronyd.pid11EnvironmentFile=-/etc/default/chrony12ExecStart=/usr/sbin/chronyd $OPTIONS13PrivateTmp=yes14ProtectHome=yes15ProtectSystem=full1617[Install]18Alias=chronyd.service19WantedBy=multi-user.target
4.3 Run chronyd as an NTP client and verify
Start the chronyd service and verify the functioning of the NTP client with the chronyc utility using its sources and tracking subcommands.
1sudo service chronyd start2
1─> chronyc sources2MS Name/IP address Stratum Poll Reach LastRx Last sample3===============================================================================4^- alphyn.canonical.com 2 10 377 29m -2864us[-2829us] +/- 105ms5^- chilipepper.canonical.com 2 10 377 22m +2987us[+2988us] +/- 102ms6^- pugot.canonical.com 2 10 377 92 -1572us[-1571us] +/- 100ms7^- golem.canonical.com 2 10 377 479 -505us[ -509us] +/- 109ms8^- time.cloudflare.com 3 10 377 25m +9676us[+9687us] +/- 22ms9^- a.chl.la 2 10 377 486 +1995us[+1991us] +/- 87ms10^- ns4.asda.gr 2 10 377 469 +7679us[+7674us] +/- 160ms11^- 0.cl.ntp.edgeuno.com 3 10 377 990 -5310us[-5326us] +/- 228ms12^* 169.254.169.123 3 4 377 2 +157ns[ +552ns] +/- 535us
1─> chronyc tracking2Reference ID : A9FEA97B (169.254.169.123)3Stratum : 44Ref time (UTC) : Wed Jun 09 23:41:53 20215System time : 0.000000990 seconds fast of NTP time6Last offset : +0.000000155 seconds7RMS offset : 0.000001250 seconds8Frequency : 2.439 ppm slow9Residual freq : +0.000 ppm10Skew : 0.023 ppm11Root delay : 0.000512199 seconds12Root dispersion : 0.000275599 seconds13Update interval : 16.2 seconds14Leap status : Normal
5. Configure chrony as an NTP server
First, make sure that chronyd is running on your system as an NTP client by looking at the instructions in Step 4.2.
5.1 Update chrony.conf with allow directive
Once
chronyd
allow
chrony.conf
allow
1echo 'allow 0/0' >> /etc/chrony/chrony.conf2
5.2 Rerun chronyd in NTP server configuration
Re-run
chronyd
1sudo service chronyd restart2
Again, verify that chronyd is running with the chronyc tracking or chronyc sources command.
5.3 Sanity check server mode of chronyd with a Python script
Use the following python script to verify the NTP server mode of chronyd is running locally.
1#!/usr/bin/env python2#3# Requirements: ntplib (easy_install ntplib)4import ntplib5from time import ctime6import argparse78parser = argparse.ArgumentParser( description="test-ntp.py - Test a set of IP addresses for NTP " )9parser.add_argument("--ip", action="append", help="IP address to check for NTP")10a = parser.parse_args()11if a.ip is not None:12 c = ntplib.NTPClient()13 for ip in a.ip:14 try:15 response = c.request(ip)16 if response:17 print (ip+" NTP Active "+ ctime(response.tx_time))18 except:19 print (ip+" NTP Deactivated")20else:21 parser.print_help()22 exit(1)
Invoke the script as
python3 <script-name>.py --ip localhost.
1─> python3 ~/Experiments/test-ntp-server.py --ip localhost2localhost NTP Active Wed Jun 9 23:59:41 2021
6. Enable symmetric key based authentication in the NTP server
You can enable symmetric key based authentication for communication with the NTP server by adding keys to the
/etc/chrony/chrony.keys
keygen
chronyc
6.1 Generate AES-128-CMAC key for authentication and configure it in NTP server
The key generated by the
chronyc keygen
chrony.keys
1chronyc keygen 1 AES128 128 > /etc/chrony/chrony.keys2
Multiple keys can be added to the
chrony.keys
1
Verify that the key has been added to the
chrony.keys
sudo cat /etc/chrony/chrony.keys
6.2 Rerun NTP server to use the authentication keys
Once the NTP server is re-run, it will service both:
- Clients that have authentication code (MAC), generated with the key known to the server, in their request payload, AND
- Clients that do not communicate in authentication mode, i.e. they do not have MAC in their request payload.
1sudo service chronyd restart