Samba DC DDNS update

u_sam_ddnsВ данной статье будет показано, как настроить динамическое обновление DNS записей на Samba DC, используя DHCP сервер isc-dhcp-server. Настройка будет производиться на контроллерах домена, сконфигурированных в статьях Samba Active Directory domain controller и Joining a Samba DC to an Existing Active Directory.

Установим DHCP сервер isc-dhcp-server на контроллер DC1

# apt install isc-dhcp-server

Добавим в AD пользователя dhcpduser, от имени которого будет запускаться скрипт динамического обновления DNS записей

# samba-tool user create dhcpduser --description="Unprivileged user for TSIG-GSSAPI DNS updates via ISC DHCP server" --random-password

Установим неограниченный срок действия пароля для dhcpduser

# samba-tool user setexpiry dhcpduser --noexpiry

Добавим пользователя dhcpduser в группу DnsAdmins

# samba-tool group addmembers DnsAdmins dhcpduser

Экспортируем keytab файл для пользователя dhcpduser и выставим для него права

# samba-tool domain exportkeytab --principal=dhcpduser@4SKILL.LOC /etc/dhcp/dhcpduser.keytab
# chown dhcpd:dhcpd /etc/dhcp/dhcpduser.keytab
# chmod 400 /etc/dhcp/dhcpduser.keytab

Создадим директорию для скрипта, выполняющего динамическое обновление DNS записей

# mkdir -p /etc/dhcp/bin

Создадим скрипт, выполняющий динамическое обновление DNS записей

# nano /etc/dhcp/bin/dhcp-dyndns.sh

#!/bin/bash

# /etc/dhcp/bin/dhcp-dyndns.sh

# This script is for secure DDNS updates on Samba 4
# Version: 0.8.7

# DNS domain
domain=$(hostname -d)
if [ -z ${domain} ]; then
    echo "Cannot obtain domain name, is DNS set up correctly?"
    echo "Cannot continue... Exiting."
    logger "Cannot obtain domain name, is DNS set up correctly?"
    logger "Cannot continue... Exiting."
    exit 1
fi

# Samba 4 realm
REALM=$(echo ${domain^^})

# Additional nsupdate flags (-g already applied), e.g. "-d" for debug
#NSUPDFLAGS="-d"

# krbcc ticket cache
export KRB5CCNAME="/tmp/dhcp-dyndns.cc"

# Kerberos principal
SETPRINCIPAL="dhcpduser@${REALM}"
# Kerberos keytab
# /etc/dhcp/dhcpduser.keytab
# krbcc ticket cache
# /tmp/dhcp-dyndns.cc

TESTUSER=$(wbinfo -u | grep dhcpduser)
if [ -z "${TESTUSER}" ]; then
    echo "No AD dhcp user exists, need to create it first.. exiting."
    echo "you can do this by typing the following commands"
    echo "kinit Administrator@${REALM}"
    echo "samba-tool user create dhcpduser --random-password --description=\"Unprivileged user for DNS updates via ISC DHCP server\""
    echo "samba-tool user setexpiry dhcpduser --noexpiry"
    echo "samba-tool group addmembers DnsAdmins dhcpduser"
    exit 1
fi

# Check for Kerberos keytab
if [ ! -f /etc/dhcp/dhcpduser.keytab ]; then
    echo "Required keytab /etc/dhcp/dhcpduser.keytab not found, it needs to be created."
    echo "Use the following commands as root"
    echo "samba-tool domain exportkeytab --principal=${SETPRINCIPAL} /etc/dhcp/dhcpduser.keytab"
    echo "chown dhcpd:dhcpd /etc/dhcp/dhcpduser.keytab"
    echo "chmod 400 /etc/dhcp/dhcpduser.keytab"
    exit 1
fi

# Variables supplied by dhcpd.conf
action=$1
ip=$2
DHCID=$3
name=${4%%.*}

usage()
{
echo "USAGE:"
echo "  `basename $0` add ip-address dhcid|mac-address hostname"
echo "  `basename $0` delete ip-address dhcid|mac-address"
}

_KERBEROS () {
# get current time as a number
test=$(date +%d'-'%m'-'%y' '%H':'%M':'%S)
# Note: there have been problems with this
# check that 'date' returns something like
# 04-09-15 09:38:14

# Check for valid kerberos ticket
#logger "${test} [dyndns] : Running check for valid kerberos ticket"
klist -c /tmp/dhcp-dyndns.cc -s
if [ "$?" != "0" ]; then
    logger "${test} [dyndns] : Getting new ticket, old one has expired"
    kinit -F -k -t /etc/dhcp/dhcpduser.keytab -c /tmp/dhcp-dyndns.cc "${SETPRINCIPAL}"
    if [ "$?" != "0" ]; then
        logger "${test} [dyndns] : dhcpd kinit for dynamic DNS failed"
        exit 1;
    fi
fi

}

# Exit if no ip address or mac-address
if [ -z "${ip}" ] || [ -z "${DHCID}" ]; then
    usage
    exit 1
fi

# Exit if no computer name supplied, unless the action is 'delete'
if [ "${name}" = "" ]; then
    if [ "${action}" = "delete" ]; then
        name=$(host -t PTR "${ip}" | awk '{print $NF}' | awk -F '.' '{print $1}')
    else
        usage
        exit 1;
    fi
fi

# Set PTR address
ptr=$(echo ${ip} | awk -F '.' '{print $4"."$3"."$2"."$1".in-addr.arpa"}')

## nsupdate ##

case "${action}" in
add)
    _KERBEROS

nsupdate -g ${NSUPDFLAGS} << UPDATE
server 127.0.0.1
realm ${REALM}
update delete ${name}.${domain} 3600 A
update add ${name}.${domain} 3600 A ${ip}
send
UPDATE
result1=$?

nsupdate -g ${NSUPDFLAGS} << UPDATE
server 127.0.0.1
realm ${REALM}
update delete ${ptr} 3600 PTR
update add ${ptr} 3600 PTR ${name}.${domain}
send
UPDATE
result2=$?
;;
delete)
     _KERBEROS

nsupdate -g ${NSUPDFLAGS} << UPDATE
server 127.0.0.1
realm ${REALM}
update delete ${name}.${domain} 3600 A
send
UPDATE
result1=$?
nsupdate -g ${NSUPDFLAGS} << UPDATE
server 127.0.0.1
realm ${REALM}
update delete ${ptr} 3600 PTR
send
UPDATE
result2=$?
;;
*)
echo "Invalid action specified"
exit 103
;;
esac

result="${result1}${result2}"

if [ "${result}" != "00" ]; then
    logger "DHCP-DNS Update failed: ${result}"
else
    logger "DHCP-DNS Update succeeded"
fi

exit ${result}

Выставим права на скрипт

# chmod 755 /etc/dhcp/bin/dhcp-dyndns.sh

Создадим резервную копию конфигурационного файла DHCP сервера

# cp /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd.conf.orig

Отредактируем конфигурационный файл DHCP сервера

# nano /etc/dhcp/dhcpd.conf

authoritative;                 # Сервер является авторитетным для домена.
ddns-update-style none;        # Динамическое обновление DNS отключено. Информация о DNS обновляется скриптом.

default-lease-time 691200;     # Время аренды ip адреса в секундах.
max-lease-time 864000;         # Максимальное время аренды ip адреса в секундаx.

# Общие опции для всех областей.
option domain-name "4skill.loc";                                 # DNS суффикс.
option domain-name-servers 192.168.10.11, 192.168.10.12;         # Адреса DNS серверов.
option netbios-name-servers 192.168.10.11, 192.168.10.12;        # Адреса WINS серверов.
option ntp-servers 192.168.10.11, 192.168.10.12;                 # Адреса NTP серверов.

# Описание области.
subnet 192.168.10.0 netmask 255.255.255.0 {        # Определение области.
  option subnet-mask 255.255.255.0;                # Маска сети.
  option routers 192.168.10.254;                   # Шлюз по умолчанию.
  option broadcast-address 192.168.10.255;         # Широковещательный адрес.
  pool {                                           # Определение пула.
    range 192.168.10.20 192.168.10.199;            # Диапазон выдаваемых адресов.
  }
}

# Резервирование адреса.
host cl-55 {                                  # Имя клиента.
  hardware ethernet 00:0c:29:8d:60:7b;        # MAC адрес.
  fixed-address 192.168.10.55;                # IP адрес.
}

# Запуск скрипта на добавление A и PTR записей.
on commit {
set noname = concat("dhcp-", binary-to-ascii(10, 8, "-", leased-address));
set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
set ClientDHCID = binary-to-ascii(16, 8, ":", hardware);
set ClientName = pick-first-value(option host-name, config-option-host-name, client-name, noname);
log(concat("Commit: IP: ", ClientIP, " DHCID: ", ClientDHCID, " Name: ", ClientName));
execute("/etc/dhcp/bin/dhcp-dyndns.sh", "add", ClientIP, ClientDHCID, ClientName);
}

# Запуск скрипта на удаление A и PTR записей.
on release {
set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
set ClientDHCID = binary-to-ascii(16, 8, ":", hardware);
log(concat("Release: IP: ", ClientIP));
execute("/etc/dhcp/bin/dhcp-dyndns.sh", "delete", ClientIP, ClientDHCID);
}

# Запуск скрипта на удаление A и PTR записей, из-за истекшего срока жизни.
on expiry {
set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
# cannot get a ClientMac here, apparently this only works when actually receiving a packet
log(concat("Expired: IP: ", ClientIP));
# cannot get a ClientName here, for some reason that always fails
execute("/etc/dhcp/bin/dhcp-dyndns.sh", "delete", ClientIP, "", "0");
}

Добавим необходимые разрешения в AppArmor

# nano /etc/apparmor.d/local/usr.sbin.dhcpd

/bin/bash ix,
/bin/date rix,
/bin/grep rix,
/bin/hostname rix,
/dev/tty rw,
/etc/dhcp/bin/dhcp-dyndns.sh rix,
/etc/gss/mech.d/ r,
/proc/*/loginuid r,
/run/samba/winbindd/pipe wr,
/tmp/** rwmk,
/usr/bin/gawk rix,
/usr/bin/host rix,
/usr/bin/kinit rix,
/usr/bin/klist rix,
/usr/bin/logger rix,
/usr/bin/nsupdate rix,
/usr/bin/wbinfo rix,
/var/lib/samba/private/krb5.conf r,

Перезапустим AppArmor

# service apparmor reload

Запустим DHCP сервер

# service isc-dhcp-server start

 

Обеспечение отказоустойчивости

Для обеспечения отказоустойчивости, нужно установить DHCP сервер на вторичный контроллер домена DC2.

Установим DHCP сервер isc-dhcp-server на контроллер DC2

# apt install isc-dhcp-server

Далее необходимо проделать те же действия, что и на контроллере DC1, начиная с экспорта keytab файла для пользователя dhcpduser.

На первом контроллере DC1 нужно добавить следующие строки в dhcpd.conf

# nano /etc/dhcp/dhcpd.conf

failover peer "dhcp-failover" {
  primary;
  address dc1.4skill.loc;
  peer address dc2.4skill.loc;
  max-response-delay 60;
  max-unacked-updates 10;
  mclt 3600;
  split 128;
  load balance max seconds 3;
}
. . .

 pool {                                            # Определение пула.
    failover peer "dhcp-failover";
    range 192.168.10.20 192.168.10.199;            # Диапазон выдаваемых адресов.
  }
. . .

Параметр split распределяет ответственность за DHCP запросы. Значение 128 означает, что оба сервера будут отвечать на DHCP запросы. При значении 255, отвечать на запросы будет только первичный контроллер DC1. При значении 0,  отвечать на запросы будет вторичный контроллер DC2.

Аналогичные действия нужно проделать на контроллере DC2

# nano /etc/dhcp/dhcpd.conf

failover peer "dhcp-failover" {
  secondary;
  address dc2.4skill.loc;
  peer address dc1.4skill.loc;
  max-response-delay 60;
  max-unacked-updates 10;
  load balance max seconds 3;
}
. . .

  pool {                                           # Определение пула.
    failover peer "dhcp-failover";
    range 192.168.10.20 192.168.10.199;            # Диапазон выдаваемых адресов.
  }
. . .

Важно, чтобы определение failover peer находилось выше описания области сети.

Сгенерируем OMAPI ключ

# dnssec-keygen -a HMAC-MD5 -b 512 -n USER DHCP_OMAPI

Генерация ключа происходит не быстро. Чем меньше битность, тем быстрее генерируется ключ. Битность определена ключом -b.

Извлечем ключ из сгенерированного файла

# cat Kdhcp_omapi.+*.private |grep ^Key|cut -d ' ' -f2-

Добавим на обоих контроллерах в dhcpd.conf следующие строки

# nano /etc/dhcp/dhcpd.conf

omapi-port 7911;
omapi-key omapi_key;

key omapi_key {
 algorithm hmac-md5;
 secret "PUT_YOUR_KEY_HERE";
}

В поле secret нужно вставить извлеченный ранее ключ.

Чтобы изменения вступили в силу, нужно перезапустить DHCP службу на обоих контроллерах

# service isc-dhcp-server restart

Поскольку обновление DNS записей производится скриптом, в лог файле /var/log/syslog могут встречаться ошибки, связанные с динамическим обновлением. DNS клиенты Windows будут пытаться самостоятельно обновить информацию о DNS и получат отказ. Это поведение можно отключить, создав групповую политику. В конфигурации компьютера нужно пройти по следующему пути

Конфигурация компьютера
  Политики
    Административные шаблоны
      Сеть
        DNS-клиент

и выставить элементы «Регистрировать PTR-записи» и «Динамическое обновление» в состояние «Отключена».

Более подробную информацию можно найти на страницах официального руководства в разделе Configure DHCP to update DNS records with BIND9.

 

Samba DC DDNS update: 2 комментария

  1. Сергей

    Отличный сайт. Много дополнений к моим серверам сделал. Все по делу и в одном месте. Прям бери отсюда и разворачивай вою сеть. Браво!

    Проблемка: при выдаче IP компам не из домена запись в DNS не создается. В логах:
    Unable to execute /etc/dhcp/bin/dhcp-dyndns.sh: Permission denied execute: /etc/dhcp/bin/dhcp-dyndns.sh exit status 32512
    Пробовал сменить права. Не помогает.
    Может я чего-то не доделал? Не подскажете куда копать? Какие у вас права на этот файл?
    Спасибо

    1. Андрей Автор записи

      Добрый день! Спасибо за приятный отзыв=)
      Сейчас собрал стенд, состоящий из одного контроллера и windows клиента. Сборка осуществлялась по статьям Samba Active Directory domain controller и Samba DC DDNS update.
      Клиент на windows 10 получил IP без проблем.
      ddns_example
      Вот права на dhcp-dyndns.sh

      # ls -lah /etc/dhcp/bin/dhcp-dyndns.sh
      -rwxr-xr-x 1 root root 3,9K авг 31 12:03 /etc/dhcp/bin/dhcp-dyndns.sh

      При развертывании контроллера на Sambа, важным является порядок установки bind и samba.
      Удобнее сначала ставить bind, затем samba, в таком случае не нужно будет выставлять вручную права на файлы в /usr/local/samba/private/ и прочие.
      Подробнее об этом в BIND9 DLZ DNS Back End.
      Для диагностики динамического обновления, нужно выполнить команду

      samba_dnsupdate --verbose --all-names

      она должна отработать без ошибок, подробнее можно прочитать в Testing Dynamic DNS Updates.
      P.S. Я тоже очень долго разбирался с динамическими обновлениями, в моем случае проблема крылась в настройке AppArmor, подробнее об этом написано в BIND9 DLZ AppArmor and SELinux Integration.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *