Автоматическая синхронизация файлов конфигурации master и slave DNS серверов [2008]
Зачем это нужно?
Для одного из проектов мне потребовалось обеспечить автоматическое распространение DNS зон, прописанных на master dns, slave серверам. Так как зон ожидалось не больше 100-200 мне хотелось сделать максимально простую, но в тоже время безопасную схему синхронизации серверов, без использования LDAP или SQL в качестве backend. В итоге я решил задачу используя shell скрипты, которыми решил поделиться с общественностью. Всё нижеописанное работает на OS FreeBSD но должно без проблем работать и в любой другой UNIX OS c BIND в роли DNS.
Как это работает
Все master зоны на primary dns лежат в отдельной директории (/etc/namedb/master-auto) и названы в формате <domain>.db.
Например example.com.db, kernel.org.db и т.п. Это важный момент, так как на этом основан алгоритм получения списка доменов (это проще и удобнее чем читать named.conf). Используя протокол SSH клиенты (secondary сервера) запрашивают у primary сервера список доменов и, в случае различий с локальным списком, обновляют конфигурацию. Клиентов может быть сколько угодно, обновление происходит по cron, например, раз в 10 минут. Для безопасного транспорта содержимого зон используется TSIG протокол.
Конфигурация сервера
Как я уже писал выше, primary сервер должен по протоколу SSH отдавать список обслуживаемых доменов. Для этого я завёл пользователя dnssync. Shell данного пользователя будет специально созданный для данной цели sh скрипт.
# pw user add dnssync -s /home/dnssync/domainlist.sh
Пароль пользователю не нужен, так как для подключения будет использоваться SSH ключ.
Теперь создадим сам скрипт:
mkdir /home/dnssync; chmod 700 /home/dnssync;
vi /home/dnssync/domainlist.sh
#!/bin/sh
export COLUMNS=1 # directory with <zone>.db files cd /etc/namedb/master-auto echo "DOMAINLIST_START" /bin/ls *.db|/usr/bin/sed 's/\.db//' echo "DOMAINLIST_END"
Корректируем права доступа:
chmod +x /home/dnssync/domainlist.sh
Как видно из текста скрипта, всё что он делает - это получает список файлов в директории, убирает суффикс .db и добавляет к выводу DOMAINLIST_START перед листингом и DOMAINLIST_END в конце вывода. Для проверки запустите /home/dnssync/domainlist.sh - должно быть что-то вроде
Теперь перейдём к настройке secondary DNS. Для начала нам потребуется настроить авторизацию по ключу для подключения к главному серверу. Если ключ ещё не создан, запустим ssh-keygen, указав пустой passphrase. Нам потребуется скопировать публичный ключ (по умолчанию /root/.ssh/id_rsa.pub в FreeBSD) в список авторизованных ключей на главном сервере (в файл /home/dnssync/.ssh/authorized_keys). В этом же файле можно задать IP адрес владельца ключа для большей безопасности. Чтобы убедиться, что всё работает, на клиенте введём команду ssh dnssync@<master_ip>, например # 'ssh dnssync@1.2.3.4 sync'. Последний аргумент требуется, чтобы сервер не показывал motd и прочие радости. В случае правильной настройки должен быть выведен список доменов, без запроса пароля.
Теперь установим клиентский скрипт, который отвечает за изменение конфигурации BIND и его перезапуск:
# fetching domain list from the master /usr/bin/ssh -o BatchMode=yes ${MASTERUSER}@${MASTERHOST} fetch > ${DNSTMPDIR}/domains.tmp </dev/null if [ "$?" -ne "0" ]; then echo "Error while transferring" exit 1 fi
# simple check of the received file if [ -z `grep DOMAINLIST_START ${DNSTMPDIR}/domains.tmp` -o -z `grep DOMAINLIST_END ${DNSTMPDIR}/domains.tmp` ]; then echo "Invalid data received" exit 1; fi
# check if the files are equal if [ -f ${DNSTMPDIR}/domains -a -z "`/usr/bin/cmp ${DNSTMPDIR}/domains.tmp ${DNSTMPDIR}/domains 2>/dev/null`" ]; then # files are equal, do nothing exit 0; fi
# copy temporary file to the primary /bin/cp ${DNSTMPDIR}/domains.tmp ${DNSTMPDIR}/domains
# creating output file for the dns /usr/bin/grep -v DOMAINLIST_ ${DNSTMPDIR}/domains \ | sed 's/\(.*\)/zone "\1" in { type slave; file "slave\/\1.db"; masters {'${MASTERHOST}';}; };/' \ > /etc/namedb/slave.conf
/etc/rc.d/named restart >/dev/null
Корректируем права доступа:
chmod 700 /root/bin/dnssync.sh
Этот скрипт при запуске подключается к master серверу, скачивает список доменов (проверяя его корректность), сравнивает с имеющимся файлов и в случае изменений создаёт /etc/namedb/slave.conf, содержащий список slave зон после чего перезапускает BIND. Запустите скрипт, в случае если всё работает правильно вы должны получить файл /etc/namedb/slave.conf содержащий конфигурацию slave зон. Чтобы named читал этот файл добавим строчку 'include "slave.conf";' в файл /etc/named.conf и перезапустим named. В случае отсутствия ошибок в директории /etc/namedb/slave появятся файлы зон. Для автоматической работы скрипт dnssync.sh добавляем в crontab пользователя root с требуемой вам периодичностью.
Для вторичных серверов поступаете аналогично.
TSIG - безопасная передача зон
Для увеличение безопасности работы я рекомендую использовать механизм TSIG. Достаточно подробное описание настройки можно прочитать в статье "Защита сервера DNS", так что я не вижу смысла дублировать это в своей заметке.
Заключение
Описанная схема прекрасно подходит для сравнительно небольших конфигураций. К её плюсам можно отнести простоту реализации (только shell), высокую безопасность и лёгкую переносимость. Недостатки - каждый раз передаётся полный список зон, в случае обновления требуется перезапуск named. В масштабах большого регистратора рекомендую подумать о более эффективных методах репликации, но для большинства других задач эти недостатки совершенно не существенны. Как всегда - буду рад замечаниям и советам.