Настройка OpenVPN с авторизацией через LDAP

Данная небольшая статья поведает как настроить openvpn, да не просто так, а с авторизацией через LDAP. Раз уж я рассказывал до этого как настраивать LDAP, то пришла пора его для чего-то применить. Вот одно их полезных моментов куда его можно применить в целях организации закрытой инфраструктуры изолированной от попадания того кого не нужно. OpenVpn в этом деле незаменимая вещь, позволяющая давать доступ тому кому надо, а кого не надо оставлять за бортом. Ну а LDAP предельно упрощает предоставление таких прав нужным людям.

Для начала приведу общий конфиг для openvpn остановивлюсь на тех вещах которые нужны именно для нормальной работы opnevpn+ldap

tmp-dir /tmp
local 142.2.44.55
port 2000
proto tcp-server
tcp-queue-limit 256
bcast-buffers 4096
duplicate-cn
dev tun0
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/local.crt
client-cert-not-required
username-as-common-name
key /etc/openvpn/keys/local.key
dh /etc/openvpn/keys/dh2048.pem
server 10.30.0.0 255.255.255.0
push "route 10.11.0.0 255.255.0.0"
push "dhcp-option DNS 10.11.0.1"
push "dhcp-option DOMAIN example.local"
push "sndbuf 393216"
push "rcvbuf 393216"
tls-server
tls-auth /etc/openvpn/keys/ta.key 0
tls-timeout 120
auth MD5
cipher AES-256-CBC
keepalive 10 120
max-clients 100
user nobody
group nogroup
persist-key
persist-tun
script-security 3 execve
status /var/log/openvpn/openvpn-status.log
log /var/log/openvpn/openvpn.log
verb 4
plugin /usr/lib/openvpn/openvpn-auth-ldap.so "auth-ldap.conf"

В целом все как при обычном конфигурировании openvpn, есть небольшие только отличия

username-as-common-name – меняет авторизацию по common name из сертификата на авторизацию по логину и паролю, то что именно нам и надо.

plugin /usr/lib/openvpn/openvpn-auth-ldap.so “auth-ldap.conf” – подключает в качестве плагина openvpn-auth-ldap.so, который даест возможность вытаскивать из LDAP данные пользователя и использовать их для прохождения авторизации. На дебиане он ставиться довольно просто:

apt-get install openvpn-auth-ldap

В основном конфиге все, более добавлять ничего не надо. Есть еще дополнительный конфиг auth-ldap.conf где и осуществляется вся магия авторизации через LDAP.

URL ldap://10.11.0.2
BindDN cn=user,dc=example
Password pass
Timeout 15

BaseDN “ou=people,dc=example”
SearchFilter “(&(uid=%u)(attr1=vpn))”
RequireGroup false

Тут указаны данные к какому LDAP серверу подсоединяться

URL ldap://10.11.0.2

с какими правами работать

BindDN cn=user,dc=example , Password pass

и в какой директории искать

BaseDN “ou=people,dc=example”

Так же указан фильтр по которому будет производиться выборка

SearchFilter “(&(uid=%u)(attr1=vpn))”

это значит что будет проводиться поиск по указанному пользователю и если у него есть атрибут attr1=vpn, что позволяет ограничить в директории пользователей на тех кому нужен доступ по VPN и кому нет, так же можно разграничить доступ по разным VPN.

Данный конфиг не позволяет работать с группами, что в целом довольно неудобно, потому что добавлять и удалять атрибуты в целом неудобно, особенно когда есть группы, которыми гораздо проще управлять. Для работы с группами конфиг будет следующий

URL ldap://10.11.0.2
BindDN cn=user,dc=example
Password pass
Timeout 15

BaseDN “ou=people,dc=example”
SearchFilter “(uid=%u)”
RequireGroup true

BaseDN “cn=openvpn,ou=groups,dc=example”
SearchFilter “(cn=openvpn)”
MemberAttribute memberUid

 

Добавляется секция с поиском в группе указанного пользователя. Теперь для предоставления прав на доступ достаточно добавить пользователя в указанную группу или удалить если он там больше не нужен. Вот в общем и все, надеюсь эта статья будет вам полезна.

Универсальный резолвер – unbound

Сегодня я бы хотел поведать еще об одном важном компоненте IT инфрастуктуры таким каким несомненно является резолвер. И в качестве такого резолвера я бы хотел бы представить вам очень быстрый и надежный сервер для кеширования ДНС – unbound. Пользуюсь я им давно и его возможности и производительность во всем меня устраивает. То же самое касается и простоты настройки этого демона. В целом конфигурационный файл его снабжен достаточно подробными пояснения так, что разобраться во всем хозяйстве не сложно, но я на некоторых моментах все-таки остановлюсь

В самом конфигурационном файле довольно много опций, я буду показывать только те, которые в основном используются, те что остаются по умолчанию я не буду упоминать. Итак начнем, в начале конфига есть секция, где указываются настройки самого сервера:

server:
#Указывает как подробно будут идти записи в логи, есть вариант 0 - совсем мало, 1 - чуть побольше
verbosity: 1
#Интервал сбора статистики в секндах
statistics-interval: 30
# Расширенная статистика, по умолчанию выключена, влияет на скорость работы, нужна только при каких-то отладочных моментах
# extended-statistics: no
# Количество тредов запускаемых при старте демона
num-threads: 4

Тут все понятно, логи, статистика, ну и мультитредовость, куда уж без нее на мноядерных системах.

Дальше у нас немного настроек по интерфейсам, на каких адресах висеть и какие порты слушать:

# По умолчанию работает на (127.0.0.1 и ::1).
# Можно указать 0.0.0.0 и ::0 тогда будет работать на всех имеющихся адресах.
# Я указываю конкретные адреса на которых резолверу можно работать, так удобнее и надежнее, по одному интерфейсу на строчку
interface: 127.0.0.1
interface: 10.11.12.15
interface: 10.12.13.16
interface: 122.3.22.131
# interface: 192.0.2.154@5003
# interface: 2001:DB8::5
# Экспериментальная опция, включающая подстановку адреса источника в ответ, работает не везде, выключаю, поскольку не особо и надо
interface-automatic: no
# Можно указать порт для работы отличный от дефолтного 53, по сути это скорее вредно чем полезно и может пригодится только в очень малом количестве случаев
# port: 53
# Указываем адрес с которого будут уходить запросы к внешним ДНС, поскольку будут приходить туда же стоит указывать внешний адрес
outgoing-interface: 122.3.22.131
# outgoing-interface: 2001:DB8::5
# outgoing-interface: 2001:DB8::6

Дальше в конфиге идет довольно большая секция касающаяся сетевых настроек, лимитов и разного рода таймаутов, по большей части они хороши как есть и прекрасно будут работать и так, поэтому стоит их трогать если действительно может помочь решить какую-то проблему.

# Включаем IPv4, "yes" или "no".
do-ip4: yes
# Включаем IPv6, "yes" или "no".
do-ip6: no
# Включаем UDP, "yes" или "no".
do-udp: yes
# Включаем TCP, "yes" или "no".
do-tcp: yes
# Запускаем как демона, "yes" or "no".
do-daemonize: yes

# Указываем с каких адресов можно делать запросы через этот резолвер, указываем тех кому действительно можно
access-control: 0.0.0.0/0 refuse
access-control: 127.0.0.0/8 allow
access-control: 10.0.0.0/8 allow
access-control: 122.3.22.0/22 allow
# access-control: ::1 allow
# access-control: ::ffff:127.0.0.1 allow

Довольно важные параметры для настройки, помогающие контролировать и ограничивать кому можно и кому нельзя пользоваться резолверами, помогает отсеять постороних
Дальше идет довольно большое количество опций для настройки безопасности работы демона и ухода от различного типа атак, тут каждый может указать то что ему больше подходит по назначению и условиям работы.

# Полезная довольно опция, в которой можно указать какие зоны обслуживаются локально и с помощью опции local-data указать значения тех или иных записей
# При этом с помощью разных опций указать что делать с запросами для этих зон
# o deny - сбрасывает все запросы.
# o refuse - отбивает с ошибкой.
# o static - отдает статически прописанные значения которые есть в local-data, на все остальное выдает что нет данных
# o transparent - отдает значения в local data, но и нормально резолвит остальные записи
# o redirect - перенаправляет запросы на другой домен.
# o nodefault - используется для резолвинга AS112 зон.
local-zone: "grombon.local." transparent
local-zone: "10.10.in-addr.arpa." transparent
local-zone: "lookup.net." transparent
# Примеров с использования local-data может быть несколько
# local-data: "mycomputer.local. IN A 192.0.2.51"
# local-data: 'mytext.local TXT "content of text record"'
# local-data: "adserver.example.com A 127.0.0.1"
# local-zone: "example.com" redirect
# local-data: "example.com A 192.0.2.3"
# local-data-ptr: "192.0.2.3 www.example.com"

Следующие несколько параметров дают возможность удаленного управления unbound, если вам это действительно нужно, то разберетесь сами тут все не так уж и сложно

В конце конфигурационного файла есть возможность для указания зон запросы для которых нужно в обязательном порядке перенаправлять на другие сервера

# Перенаправляет все запросы для зоны на указанный адрес
stub-zone:
name: "lookup.net"
stub-addr: 165.45.55.15
# форвардит все запросы на указанные адреса неймсерверов, очень схожий с предыдущей опцией параметр.
forward-zone:
name: "example.ru"
forward-addr: 165.45.55.15
forward-addr: 165.45.54.15
forward-addr: 165.45.53.15
forward-zone:
name: "grombon.local"
forward-addr: 165.45.55.15
forward-addr: 165.45.54.15
forward-addr: 165.45.53.15
forward-zone:
name: "10.10.in-addr.arpa"
forward-addr: 165.45.55.15
forward-addr: 165.45.54.15
forward-addr: 165.45.53.15

В целом разобраться во всем не так уж и сложно, сложностей никаких. В работе сервер неприхотлив, надежен и требует минимума внимания. Настроил и забыл. То что надо.

Настройка TLS для LDAP

Не так давно я описал в статье настройку репликации LDAP серверов по схеме multimaster. В данной заметке я опишу как настроить работу LDAP по зашифрованному каналу в том числе и для репликации. Понадобиться это может в довольно большом количестве случаев, например если вам надо прокинуть реплику куда-то во вне защищенной сети или если ваша сеть публичная. В общем зашифровать данные никогда не бывает лишним. В LDAP это делается довольно просто. Итак, исходные данные такие же как и в предыдущей статье, будем считать, что та схема уже сделана и нормально функционирует, и просто к ней в дополнение организовываем шифрование.

Как и прежде, все настройки мы храним с самом LDAP и реплицируем между всем серверами реплики. В качестве ключей будем использовать самоподписные ключи сгенерированные с помощью утилит из набора GNU TLS. Ключи сделанные через openssl работать не будут, так что пользоваться придется certtool, что совсем не сложно. Для начала установим набор утилит:

apt-get install gnutls-bin

Теперь можно сгенерировать корневые сертификаты для нашего самоподписного сертификата, пока я этого не сделал, получал подобную ошибку:

slapd TLS: can't connect: A TLS packet with unexpected length was received..

Поэтому делаем набор ключ и сертификат для корневого сертификата и им подписываем сертификат для непосредственно рабочей пары:

certtool --generate-privkey --outfile ca.key
certtool --generate-self-signed --load-privkey ca.key --outfile ca.crt

Генерим рабочую пару:

certtool --generate-privkey --outfile ldap.prod.local.key
certtool --generate-certificate --load-privkey ldap.prod.local.key --outfile ldap.prod.local.crt --load-ca-certificate ca.crt --load-ca-privkey ca.key

Кладем все полученные сертификаты и приватный ключик в папочку где они будут доступны для сервера, например в /etc/ldap/ssl. Добавляем владельца и группу:

chown -R openldap:openldap /etc/ldap/ssl

Вносим изменения в конфиг, добавляя туда информацию о ключах с помощью следующих строчек

dn: cn=config
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ldap/ssl/ca.crt
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/ssl/ldap.prod.local.key
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/ssl/ldap.prod.local.crt

Теперь можно перезапустить сервер с работой по шифрованному протоколу, для этого идем в /etc/default/slapd и в строчке

SLAPD_SERVICES="ldap://server1.prod.local ldapi:///"

Добавляем еще один биндинг

ldaps://server1.prod.local, так чтобы полная строчка стала выглядеть так:

SLAPD_SERVICES="ldap://server1.prod.local ldapi:/// ldaps://server1.prod.local"

Делаем это на каждом из серверов и перезапускаем службу:

/etc/init.d/slapd restart

Теперь демон будет, помимо 389 порта, еще доступен на 636 порту, не забудьте открыть его в файерволе. Для того чтобы помимо обычных запросов, шифровались и запросы по реплике, то при конфигурировании реплики надо указывать ключик starttls=yes, при этом остальные параметры остаются без изменений, в общем конфиг для репликации конфигов будет выглядеть таким вот образом:

dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcSyncRepl
olcSyncRepl: rid=001 provider=ldap://server1.prod.local binddn="cn=admin,cn=config"
bindmethod=simple credentials=ck3u8gj3
searchbase="cn=config" type=refreshAndPersist
retry="5 5 300 5" timeout=1 starttls=yes
olcSyncRepl: rid=002 provider=ldap://server2.prod.local binddn="cn=admin,cn=config"
bindmethod=simple credentials=ck3u8gj3
searchbase="cn=config" type=refreshAndPersist
retry="5 5 300 5" timeout=1 starttls=yes
-
add: olcMirrorMode
olcMirrorMode: TRUE

С этого момента все данные пересылаемые по сети шифруются и не так легко доступны для просмотра посторонними лицами, что не может не радовать, ведь с этой целью это все и было затеяно.

Настройка репликации LDAP Multimaster

В какой-то момент понадобилось старую схему LDAP с одиноким сервисом переделать в что-то более надежное и устойчивое, способное выдерживать сбои и держать большую нагрузку. После недолгих изысканий было принято решение реализовать схему мастер-мастер. Удобство данной схемы в равноценности всех серверов в реплике и возможность вносить изменения на любом сервере. Устанавливать буду на сервера с Debian Linux тут это довольно просто делается. Конфиги будут хранится в самом LDAP и тоже будут реплицироваться между серверами. Сервера будут server1.prod.local и server2.prod.local. Итак, поехали.

Устанавливаем необходимые пакеты

apt-get install slapd ldap-utils

Далее начинаем прописывать конфиги, конфиги будут храниться в самом LDAP так что будем все конфигурить через ldiff с помощью команды

ldapmodify -Y EXTERNAL -H ldapi:/// -f 1.ldiff

На обоих серверах прописываем ID – ServerID (у каждого сервера свой) следующим ldiff

dn: cn=config
changetype: modify
add: olcServerID
olcServerID: 1

Добавляем пароль для сервиса репликации конфигов на обоих серверах

dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootPW
olcRootPW: jcb8332jf30

Включаем модуль для репликации syncprov на обоих серверах

dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: {1}syncprov.la

На обоих серверах прописываем сервера с которыми у нас будет проходить репликация

dn: cn=config
changetype: modify
add: olcServerID
olcServerID: 1 ldap://server1.prod.local
olcServerID: 2 ldap://server2.prod.local

Добавляем оверлей на обоих серверах чтобы пошла репликация

dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov

Включаем репликацию конфигов, это тоже делаем на обоих серверах

dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcSyncRepl
olcSyncRepl: rid=001 provider=ldap://server1.prod.local binddn="cn=admin,cn=config"
bindmethod=simple credentials=ck3u8gj3
searchbase="cn=config" type=refreshAndPersist
retry="5 5 300 5" timeout=1
olcSyncRepl: rid=002 provider=ldap://server2.prod.local binddn="cn=admin,cn=config"
bindmethod=simple credentials=ck3u8gj3
searchbase="cn=config" type=refreshAndPersist
retry="5 5 300 5" timeout=1
-
add: olcMirrorMode
olcMirrorMode: TRUE

Теперь репликация конфигов работает и все остальные действия можно выполнять на одном из серверов.
Далее нужно включить репликацию для нашей основной базы где у нас содержаться или будут содержаться все данные, база у нас пусть называется prod.
Для начала создадим пользователя для репликации, т.к. создаваться он должен в самой базе, то создавать его надо командой

ldapmodify -vvvvv -D "cn=admin,dc=prod" -W -H ldapi:/// -f sync.diff

dn: cn=sync,dc=prof
changetype: add
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: sync
description: Syncrepl user for mirrormode operation
userPassword: {SSHA}n+8YKycr9Q/GpuCf4sDfSOQ+zg3csv3Ae

Прописываем тем же способом acl

dn: olcDatabase={1}hdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous auth by dn="cn=proxy,dc=prod" read by dn="cn=manager,dc=prod" write by dn="cn=sync,dc=prod" read by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by self write by dn="cn=admin,dc=prod" write by * read

Включаем репликацию

dn: olcDatabase={1}hdb,cn=config
changeType: modify
add: olcSyncrepl
olcSyncrepl: rid=003 provider=ldap://server1.prod.local bindmethod=simple binddn="cn=sync,dc=fs" credentials=vkj48gfj searchbase="dc=prod" schemachecking=on type=refreshAndPersist retry="5 5 300 5" timeout=1
olcSyncRepl: rid=004 provider=ldap://server1.prod.local binddn="cn=sync,dc=prod" bindmethod=simple credentials=vkj48gfj searchbase="dc=prod" schemachecking=on type=refreshAndPersist retry="5 5 300 5" timeout=1
-
add: olcMirrorMode
olcMirrorMode: TRUE

Добавляем индексы на нужные поля

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: objectClass eq
olcDbIndex: cn eq
olcDbIndex: gidNumber eq
olcDbIndex: memberUid eq
olcDbIndex: uid eq
olcDbIndex: uidNumber eq
olcDbIndex: uniqueMember eq
olcDbIndex: accessTo eq
olcDbIndex: entryUUID eq

После этого нужно выключить сервер slapd (/etc/init.d/slapd stop) и выполнить команду

slapindex

Которая создаст необходимые индексы для базы. И включить сервер. Это надо сделать на обоих серверах
Добавляем лимиты чтобы все работало без ошибок даже при большом количестве полей

dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcLimits
olcLimits: dn.exact="cn=sync,dc=prod" time.soft=unlimited time.hard=unlimited size.soft=unlimited size.hard=unlimited
-
add: olcSizeLimit
olcSizeLimit: 10000
-
replace: olcDbConfig
olcDbConfig: {0}set_cachesize 0 209715200 1
olcDbConfig: {1}set_lk_max_objects 1024000
olcDbConfig: {2}set_lk_max_locks 10240
olcDbConfig: {3}set_lk_max_lockers 10240

В целом конфигурация основных моментов закончена, репликация баз где конфиги и базы где хранятся данные уже работает.

Настраиваем бекап, бекап делается через простой скриптик

backup.sh
#!/bin/sh
YMD=`date +%Y.%m.%d-%HHours`;
slapcat > /etc/ldap/ldap.ldiff;
cd /root/ldap-backup/files;
tar c /etc/ldap/ >$YMD-server1-ldap-etc.tar; gzip $YMD-server1-ldap-etc.tar;

В случае необходимости восстановиться из бекапа делаем это так

restore.sh
#!/bin/sh
/etc/init.d/slapd stop;
rm /var/lib/ldap/*;
rm /root/ldap-backup/etc -rf;
slapadd -l /root/ldap-backup/etc/ldap/ldap.ldiff;
chown openldap:openldap /var/lib/ldap -R

/etc/init.d/slapd start;

 

Добавил статью про настройку TLS для соединения с LDAP

Настройка сервера точного времени на базе NTP

Для работы сложной инфраструктуры, когда много сервисов работают одновременно очень важно иметь в пределах общего IT пространства одинаковое время на всех серверах. Самое удобное это делать с помощью автоматической синхронизацией с серверами точного времени. В большинстве случаев можно пользоваться общедоступными серверами, которых довольно много в интернете. Но в случае организации замкнутой среды, да и вообще для тех кто предпочитается все контролировать, хорошим вариантом будет организация своего собственного сервера точного времени, а лучше двух, для надежности.

     Использовать для своей синхронизации они будут сервера из того же интернета, и для достижения большей точности (stratum 2 и выше) будем выбирать наиболее точные и надежные. Список серверов по регионам можно подсмотреть тут http://support.ntp.org/bin/view/Servers/StratumOneTimeServers . Как правило стабильных открытых серверов со stratum 1 (непосредственно подключенных к источнику точного времени) не так много и нагрузка на них довольно большая. Поэтому создания своего сервера для синхронизации это в том числе пусть снять лишнюю нагрузку с них и получить свой стабильный сервер для точного времени.
     Для настройки возьмем старый, добрый сервер NTP. Не важно на какой версии ОС вы будете ее ставить, конфиг одинаков везде. Выложу сразу итоговую конфигурацию и потом расскажу что к чему и зачем.
 interface listen 10.11.12.2
 interface listen 188.8.88.8
 interface drop 10.11.12.1
 interface drop 188.8.88.8
 interface ignore wildcard
 interface drop lo

 server 91.226.136.139
 server 195.91.239.8
 server 95.140.94.2
 server 77.234.201.218
 server 77.37.146.85

 driftfile /var/lib/ntp/ntp.drift
 logconfig =all
 logfile /var/log/ntpd.log

 restrict default ignore
 restrict 127.0.0.1

 restrict 91.226.136.139 noquery notrap
 restrict 195.91.239.8 noquery notrap
 restrict 95.140.94.2 noquery notrap
 restrict 77.234.201.218 noquery notrap
 restrict 77.37.146.85 noquery notrap

 restrict 10.11.12.0 mask 255.255.255.0 nomodify notrap
 restrict 10.14.0.0 mask 255.255.0.0 nomodify notrap
     Итак, что есть что
 interface listen 10.11.12.2
 interface listen 188.8.88.8
 interface drop 10.11.12.1
 interface drop 188.8.88.8
 interface ignore wildcard
 interface drop lo
     В этом блоке мы определяем на каких интерфейсах и адресах мы разрешим работать NTP, а где запрещаем если надо.
 server 91.226.136.139
 server 195.91.239.8
 server 95.140.94.2
 server 77.234.201.218
 server 77.37.146.85
     Здесь прописываем сервера к которым мы будем обращаться за синхронизацией, среди них есть несколько stratum 1 так, итоговый stratum нашего сервера будет на уровне 2.
 driftfile /var/lib/ntp/ntp.drift
 logconfig =all
 logfile /var/log/ntpd.log
     Внутренние настройки NTP по поводу того где будет лежать логи, drift-файл и уровень логирования
 restrict 91.226.136.139 noquery notrap
 restrict 195.91.239.8 noquery notrap
 restrict 95.140.94.2 noquery notrap
 restrict 77.234.201.218 noquery notrap
 restrict 77.37.146.85 noquery notrap

 restrict 10.11.12.0 mask 255.255.255.0 nomodify notrap
 restrict 10.14.0.0 mask 255.255.0.0 nomodify notrap
     Настройки того кому можно и как обращаться к данному серверу, кому попало лазать не следует, раз мы делаем приватный сервер только для своих. В случае желания сделать открытый сервер для всех настройки будут уже совсем другие. Но это история для другой статьи совсем.

Запускаем сервер и смотрим что он выдает по своим пирам, у меня после некоторого времени работы получилось примерно так

 #ntpq -p
      remote           refid      st t when poll reach   delay   offset  jitter
 ==============================================================================
 +n44.time2.d6.hs .GPS.            1 u 1019 1024  377   44.560   -5.584   3.620
 *195.91.239.8    .PPS.            1 u  880 1024  377    8.200    1.835   0.801
 -95.140.94.2     194.190.168.1    2 u  700 1024  377    8.407    5.305   0.647
 -glavhost.com    194.190.168.1    2 u  939 1024  377    8.340    4.098  46.622
 +broadband-77-37 46.46.152.214    2 u  793 1024  377    9.088    0.569   0.432
Теперь можно настроить клиента, как ни удивительно но это опять таки будет NTP
Для клиентов конфиг выглядит вот таким образом:
server 10.11.12.2 prefer
server 10.11.13.2 prefer
driftfile /var/lib/ntp/ntp.drift
logfile /var/log/ntpd.log
restrict default ignore
restrict 127.0.0.1
restrict 10.11.12.2 noquery notrap
restrict 10.11.13.2 noquery notrap
restrict 10.11.12.0 mask 255.255.248.0 nomodify notrap
     Урезанная версия конфига нашего верхнего сервера, где в качестве пиров для получения точного времени указаны сервер (ы) который мы настроили перед этим. Дав ему поработать немного, чтобы синхронизироваться и выполнив ntpq
# ntpq -p
      remote           refid      st t when poll reach   delay   offset  jitter
 ==============================================================================
 +10.11.12.2    195.91.239.8     2 u  947 1024  377    0.157    1.241   1.148
 *10.11.13.2  195.91.239.8     2 u  847 1024  377    0.158   -0.689   0.194
     Как то так. Как видно, наши корневые сервера определяются как stratum 2, что в общем-то неплохо и для большинства задач хватает, если вам требуется точность на уровне stratum 1, что в общем-то маловероятно, то нужно приобретать устройство GPRS, Glonass или любое другое имеющее возможность получать данные о точном времени, и которое можно подключить к серверу и получать с него данные. Но это совсем другая задача.