Debian – Using host as ntp-client and lxc-router as ntp-server

debianlxcntpntpd

I installed ntpd on my Debian host machine to keep the hardware RTC "up-to-date". By sharing the system's clock the time gets automatically propagated to all installed containers (lxc). One of those containers runs my router.

I'd like to use this router to propagate its time to all interested devices in my networks, so they don't need an internet connection by themselves. I don't want to use the host as server (hopefully disabled by interface ignore all).

How can I install and configure a pure ntp-server in a container, which takes the system's clock as its only reference? It shall never set the clock by itself.

How can I install and configure a pure ntp-client, which doesn't accept incoming connections from other peers and leaks as few informations as possible?

Best Answer

The configuration of NTP deviates from what I'd call intuitive. It installs, by default, a client which reads and writes the system's clock and starts listening on all interfaces and bridges and eagerly uses them to provide informations about its status without authentication.

I had a hard time gathering all informations and documentation to get this (hopefully) right. Even the default configuration file contained several statements that aren't covered by the man-pages.

The following configuration seems to work fine without providing excessive informations and services.

This is the configuration to be installed on the host machine to enforce a client-only operation:

>> my-host:/etc/ntp.conf

# stop listening for incoming connections an all interfaces including 0.0.0.0 and [::]
interface ignore all
interface ignore wildcard

# only allow listening on the interface used to contact the time servers
interface listen 10.2.20.2

# your pools or servers
pool 0.debian.pool.ntp.org iburst
pool 1.debian.pool.ntp.org iburst
pool 2.debian.pool.ntp.org iburst
pool 3.debian.pool.ntp.org iburst

# by default drop all incoming connections on all interfaces
restrict default ignore

# unrestriced control for local connections
restrict 127.0.0.1
restrict ::1

# Needed for adding pool entries
restrict source notrap nomodify noquery

Restarting the service gives us a comprehensible list of listening sockets. (my-host:ntp cannot be avoided because of the way NTPd works.)

my-host:# netstat -a|grep ntp
udp        0      0 my-host:ntp   0.0.0.0:*
udp        0      0 localhost:ntp 0.0.0.0:*
udp6       0      0 localhost:ntp [::]:*

This is the configuration to be installed on the router-container to enforce a server-only operation (backed by the system's clock as source of time, thanks to @BillThor):

>> router:/etc/ntp.conf

# don't update the system's clock
disable kernel

# local clock as preferred and only source
server 127.127.1.0 prefer

# stop listening for incoming connections an all interfaces including 0.0.0.0 and [::]
interface ignore all
interface ignore wildcard

# whitelist addresses to listen on for NTP clients
interface listen 10.1.2.1
interface listen 10.2.2.2
interface listen 10.3.2.3
interface listen 10.4.2.4
interface listen 10.5.2.5

# set "serve" as the only permission given to all listening interfaces per default
restrict default kod notrap nomodify nopeer noquery limited

# unrestriced control for local connections
restrict 127.0.0.1
restrict ::1

# broadcast time (optional)
broadcast 10.1.255.255
broadcast 10.2.255.255
broadcast 10.3.255.255
broadcast 10.4.255.255
broadcast 10.5.255.255

Restarting the service gives us the local clock as preferred source and a list of (optional) broadcast targets

router:# ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*LOCAL(0)        .LOCL.           5 l   16   64    3    0.000    0.000   0.000
 10.1.255.255    .BCST.          16 B    -   64    0    0.000    0.000   0.000
 10.2.255.255    .BCST.          16 B    -   64    0    0.000    0.000   0.000
 10.3.255.255    .BCST.          16 B    -   64    0    0.000    0.000   0.000
 10.4.255.255    .BCST.          16 B    -   64    0    0.000    0.000   0.000
 10.5.255.255    .BCST.          16 B    -   64    0    0.000    0.000   0.000

... and a comprehensible list of listening sockets to serve the local network.

router:# netstat -a|grep ntp
udp        0      0 router-lan5:ntp 0.0.0.0:*
udp        0      0 router-lan4:ntp 0.0.0.0:*
udp        0      0 router-lan3:ntp 0.0.0.0:*
udp        0      0 router-lan2:ntp 0.0.0.0:*
udp        0      0 router-lan1:ntp 0.0.0.0:*
udp        0      0 localhost:ntp   0.0.0.0:*
udp6       0      0 localhost:ntp   [::]:*

The disable kernel (thanks to @PaulGear) prohibits the daemon from setting the system's clock which isn't allowed within a typical container. Otherwise it floods the log with:

ntpd[1568]: adj_systime: Operation not permitted

On startup there are still some harmless glitches, I don't know how to get rid of:

ntpd[1568]: start_kern_loop: ntp_loopfilter.c line 1119: ntp_adjtime: Operation not permitted
ntpd[1568]: set_freq: ntp_loopfilter.c line 1082: ntp_adjtime: Operation not permitted