Time synchronization

Learn more about how both FreeIPA and Active Directory environments are synchronized to an authoritative time source.

The Kerberos protocol's security model is critically dependent on synchronized time across all participating systems. Timestamps are embedded within Kerberos tickets to prevent replay attacks, where an attacker might capture a ticket and attempt to reuse it later. If the time difference (clock skew) between a client, a server, and the KDC exceeds a configured tolerance, authentication requests will be rejected with errors similar to Clock skew too great.

Because of this sensitivity, both FreeIPA and Active Directory environments must be synchronized to an authoritative time source.

FreeIPA uses the chrony service to synchronize its time with an NTP server. You can verify time synchronization settings with the following commands:
  • less /etc/chrony.conf
  • chronyc sources
#####################################
##### FreeIPA commands	     #####
#####################################
# check for "server" in chrony configuration
less /etc/chrony.conf
server 169.254.169.123 prefer iburst trust


chronyc sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^* 169.254.169.123               3   8   377   223  -7697ns[  -11us] +/-  324us


# The IP address (169.254.169.123) is the address for the Amazon Time Sync Service that provides highly accurate time synchronization for instances running using the Network Time Protocol (NTP)

In an Active Directory environment, the server holding the PDC Emulator (PDCe) FSMO role acts as the primary time source for the entire domain.

Log in to any Active Directory Domain Controller and run the netdom query fsmo command to find the PDC.

rem # Find your PDC Emulator, the server name listed for "PDC"
netdom query fsmo
Schema master               EC2AMAZ-UVREDMU.hybrid.cloudera.org
Domain naming master        EC2AMAZ-UVREDMU.hybrid.cloudera.org
PDC                         EC2AMAZ-UVREDMU.hybrid.cloudera.org
RID pool manager            EC2AMAZ-UVREDMU.hybrid.cloudera.org
Infrastructure master       EC2AMAZ-UVREDMU.hybrid.cloudera.org
The command completed successfully.

Log in to the PDC Emulator instance and run the following commands:

#####################################
##### AD commands      	     #####
#####################################


rem # Check the presence of the NTP server
w32tm /query /status
Leap Indicator: 0(no warning)
Stratum: 4 (secondary reference - syncd by (S)NTP)
Precision: -23 (119.209ns per tick)
Root Delay: 0.0006070s
Root Dispersion: 0.0249495s
ReferenceId: 0xA9FEA97B (source IP:  169.254.169.123)
Last Successful Sync Time: 11/5/2025 9:07:38 AM
Source: 169.254.169.123,0x9
Poll Interval: 6 (64s)


w32tm /query /peers
#Peers: 3

Peer: time.windows.com,0x8
State: Active
Time Remaining: 22.4656548s
Mode: 3 (Client)
Stratum: 3 (secondary reference - syncd by (S)NTP)
PeerPoll Interval: 6 (64s)
HostPoll Interval: 6 (64s)

Peer: 169.254.169.123,0x9
State: Active
Time Remaining: 636.8803514s
Mode: 3 (Client)
Stratum: 3 (secondary reference - syncd by (S)NTP)
PeerPoll Interval: 6 (64s)
HostPoll Interval: 6 (64s)

Both instances synced with an NTP server should be sufficient, but the safest choice is to configure both your FreeIPA server and your Active Directory PDC Emulator to use the same authoritative time source.

Active Directory reconfiguration is less viable, so the preferred method is to configure the new server and add a new FreeIPA recipe to persist the change on each subsequently upscaled FreeIPA node.

#!/bin/bash

# ---
# This script updates /etc/chrony.conf to use a new, single time server.
# It comments out all existing 'server' or 'pool' lines and adds the
# new server (provided as an argument) with 'prefer iburst'.
#
# Usage:
#   sudo ./update_chrony.sh <new-server-fqdn-or-ip>
#
# Example:
#   sudo ./update_chrony.sh ad-pdc.your-domain.com
# ---

# Exit immediately if a command fails
set -e

# --- Configuration ---
NEW_SERVER="$1"
CONFIG_FILE="/etc/chrony.conf"
SERVICE_NAME="chronyd"

# --- 1. Validation ---

# Check if running as root
if [ "$(id -u)" -ne 0 ]; then
   echo "This script must be run as root or with sudo."
   exit 1
fi

# Check if a server argument was provided
if [ -z "$NEW_SERVER" ]; then
    echo "Error: No server provided."
    echo "Usage: sudo $0 <new-server-fqdn-or-ip>"
    exit 1
fi

echo "--- Starting Chrony Update ---"

# --- 2. Backup ---
BACKUP_FILE="${CONFIG_FILE}.bak-$(date +%Y%m%d-%H%M%S)"
echo "Creating backup at $BACKUP_FILE..."
cp "$CONFIG_FILE" "$BACKUP_FILE"

# --- 3. Update Config ---
echo "Commenting out existing 'server' and 'pool' directives in $CONFIG_FILE..."
# This sed command finds lines starting with 'server ' or 'pool ' and puts a # in front.
sed -i -E 's/^(server|pool)\s/#&/' "$CONFIG_FILE"

echo "Adding new server: $NEW_SERVER..."
# This sed command inserts the new server line right before the 'driftfile' line.
sed -i "/^driftfile/i server $NEW_SERVER prefer iburst\n" "$CONFIG_FILE"

echo "Config file updated."

# --- 4. Restart Service ---
echo "Restarting $SERVICE_NAME service to apply changes..."
systemctl restart "$SERVICE_NAME"
echo "Service restarted."

# --- 5. Verify ---
echo
echo "Verifying $SERVICE_NAME status (should be 'active'):"
# Show just the 'Active:' line from the status
systemctl status "$SERVICE_NAME" --no-pager | grep 'Active:'

echo
echo "Checking new sources... (it may take a moment to connect and sync)"
# Give chrony a second to start, then check sources
sleep 1
chronyc sources

echo
echo "--- Chrony Update Complete ---"