Modern systems must syncronize their clocks, to avoid problems with time sensitive software (such as Kerberos), and to allow log correlation. This page outlines how to configure Network Time Protocol (NTP) software using CFEngine version 2.
Installation
Either install the same ntpd version on all systems (via a software depot), or ensure the configuration works for each different supported platform (e.g. the default ntpd software on Mac OS X, the ntpd package on RedHat Linux, or OpenNTPD on other systems). Different versions of ntpd may require different configuration, though standardizing on driftfile and other details will reduce the complexity of the ntp.conf configuration.
ntpd could also be included in a base system image, or required in a KickStart configuration file.
pool.ntp.org Configuration
Clients with Internet connectivity can use the public pool.ntp.org time servers. Firewalls must allow User Datagram Protocol (UDP) 123 traffic to (and back from) the public time servers.
CFEngine configuration should be spread into different files, and import used to include relevant configuration. This example assumes a master cfagent.conf contains includes for CFEngine Classes in cf.classes, and a cf.applications that in turn includes cf.app_ntp for ntpd configuration. A global cf.site should also include an AddInstallable statement with a restart_ntp class.
The configuration files should be stored under version control.
- cfagent.conf
- cf.classes
- cf.site
- cf.applications
- cf.app_ntp
- ntp.conf
- /etc/ntp/step-tickers
import:
any::
cf.main
cf.classes
cf.site
cf.applications
The cf.classes should define different time roles for systems, such as role_ntp_client or role_ntp_server. I also use a app_ntp class to determine whether to read the cf.app_ntp configuration. This prevents ntpd configuration before the package for ntpd has been installed; a different utility handles what classes need the ntpd package installed.
classes:
any::
role_ntp_client = ( any )
_darwin::
app_ntp = ( FileExists(/usr/sbin/ntpd) )
_linux::
app_ntp = ( FileExists(/usr/sbin/ntpd) )
Define a installable restart_ntp class. This allows other configuration to define the restart_ntp class, which cf.app_ntp will then handle properly based on the operating system in question. The restart_ntp class should be set when ntp.conf changes, or perhaps if the system’s network settings change.
control:
any::
AddInstallable = (
…
restart_ntp
…
)
The import under cf.applications ensures the app_ntp class set in cf.classes is available to read the cf.app_ntp configuration file.
import:
app_ntp::
cf.app_ntp
The cf.app_ntp file contains statements that configure and ensure ntpd runs. The following example assumes all systems can use the same ntp.conf configuration file, and all have a ntp user and group defined on the system.
control:
any::
ntp_config_dest = ( /etc/ntp.conf )
role_ntp_client::
ntp_config_src = ( ${masterfiles}/conf/ntp/client/ntp.conf )
ntp_step_ticker = ( ${masterfiles}/conf/ntp/client/step-tickers )
copy:
any::
${ntp_config_src} dest=${ntp_config_dest}
mode=0444 backup=false type=checksum
server=${policyhost}
define=restart_ntpd
redhat::
${ntp_step_ticker} dest=/etc/ntp/step-tickers
mode=0444 backup=false type=checksum
server=${policyhost}
directories:
any::
/var/lib/ntp owner=ntp group=ntp mode=0755
files:
any::
/var/lib/ntp/drift owner=ntp group=ntp mode=0644 r=0
processes:
redhat::
# restart ntpd if not found running
"ntpd" restart "/sbin/service ntpd restart"
shellcommands:
redhat.restart_ntpd::
# handler for restarts
"/sbin/service ntpd restart >/dev/null 2>&1" useshell=true
redhat::
# ensure ntpd runs at startup
"/sbin/chkconfig ntpd on" ifelapsed=179
Example configuration files, set to use the public pool.ntp.org servers.
List three different servers, and configure a fudge localhost clock.
# $Header$
# Client NTP Configuration
# deny by default, allow all from loopback range
restrict default ignore
restrict 127.0.0.0 mask 255.0.0.0
# reference servers (use at least three, in event one down or bad)
server 0.pool.ntp.org
server 1.pool.ntp.org
server 2.pool.ntp.org
restrict 0.pool.ntp.org mask 255.255.255.255 nomodify notrap noquery
restrict 1.pool.ntp.org mask 255.255.255.255 nomodify notrap noquery
restrict 2.pool.ntp.org mask 255.255.255.255 nomodify notrap noquery
# fallback clock
server 127.127.1.0
fudge 127.127.1.0 stratum 10
driftfile /var/lib/ntp/drift
If using pool.ntp.org servers instead of in-house ones, ntpd may need to be restarted periodically (monthly?) to pick up on new time servers?
RedHat Linux uses this file to perform a rough adjustment with ntpdate before ntpd starts up. List three to four different servers to use.
0.pool.ntp.org
1.pool.ntp.org
2.pool.ntp.org
Three Tier Infrastructure
Larger sites may not allow NTP traffic from client systems to the Internet. Instead, clients must syncronize against at least three internal time servers. The internal servers peer with one another, and syncronize against another layer of time servers. The top level time servers syncronize with hardware clocks (such as Global Positioning System (GPS) receivers) and stratum 1 time servers on the Internet.
Larger sites could also use Anycast to route NTP traffic.
Firewall Rules
Internal clients need UDP 123 access to and back from the role_ntp_server_private systems. Some firewalls, such as Packet Filter (PF), can keep state on NTP traffic, and does not need to allow new connections from the servers back to the clients:
pass out on $if_public proto udp to any port ntp keep state
block in on $if_public proto udp to any port ntp
The role_ntp_server_private systems require UDP 123 access between one another, and to (and from) the role_ntp_server_public servers. The role_ntp_server_public servers will need Internet access to any stratum 1 time servers syncronized with. Consider adding the role_ntp_server_public servers to the pool.ntp.org time servers.
Any monitoring systems will need UDP 123 access to (and back from) the various time servers being monitored.
Configuration
- cf.classes
- cf.app_ntp
- ntp.conf
Add classes for the two new server types, and make everything else a NTP client.
classes:
any::
role_ntp_server_public = ( clock01 clock02 )
role_ntp_server_private = ( time01 time02 time03 time04 )
role_ntp_client = (
any -role_ntp_server_public -role_ntp_server_private
)
Expand the ntp.conf copies to account for the two new ntp.conf files.
control:
any::
ntp_config_dest = ( /etc/ntp.conf )
ntp_config_dir = ( ${masterfiles}/conf/ntp )
role_ntp_client::
ntp_config_src = ( ${ntp_config_dir}/client/ntp.conf )
ntp_step_ticker = ( ${ntp_config_dir}/client/step-tickers )
role_ntp_server_private::
ntp_config_src = ( ${ntp_config_dir}/server_private/ntp.conf )
ntp_step_ticker = ( ${ntp_config_dir}/server_private/step-tickers )
role_ntp_server_public::
ntp_config_src = ( ${ntp_config_dir}/server_public/ntp.conf )
ntp_step_ticker = ( ${ntp_config_dir}/server_public/step-tickers )
copy:
any::
${ntp_config_src} dest=${ntp_config_dest}
mode=0444 backup=false type=checksum
server=${policyhost}
define=restart_ntpd
redhat::
${ntp_step_ticker} dest=/etc/ntp/step-tickers
mode=0444 backup=false type=checksum
server=${policyhost}
In the server ntp.conf files, allow access from client systems, peer off the servers at the same level, and syncronize with higher servers.
Testing
Use monitoring software to track the time drift; checks should warn if a time server drifts out of line, or if a client cannot reach a server. Monitoring software such as Nagios should have plugins available to check NTP. If testing ntpd in a development environment before moving it to production, be sure to:
- Confirm whether localhost can query ntpd, and that the time servers are reachable by the client.
- Confirm the monitoring hosts (if any) can query ntpd.
$ ntpq -p
remote refid st t when poll reach delay offset jitter
============================================================================
+192.0.2.121 192.0.2.123 3 u 29 64 377 0.321 0.169 0.101
+192.0.2.122 192.0.2.123 3 u 44 64 377 0.278 -0.801 0.120
*192.0.2.124 192.0.2.123 3 u 34 64 377 0.217 -0.582 0.109
LOCAL(0) LOCAL(0) 10 l 35 64 377 0.000 0.000 0.001
$ ntpq -p client.dev.example.org
…
If the system time has drifted too far, ntpd will not be able to correct the problem. In this case, run ntpdate to correct the time to a “close enough” value. Look for *LOCAL(0) in the output of ntpq to detect when the local fudge clock is being used instead of the servers.
Timezone
If possible, set all systems to UTC. This facilitates growth or mergers that lead to data centers in different time zones. Users should set a local TZ environment setting to display in the local format, if desired. However, users with custom TZ settings must then use sudo -H … or otherwise ensure that their custom timezone does not pollute the system, for example when restarting software as root.