DHCP сервер для Linux AD-DC Ubuntu 18.04. Интеграция с BIND9. Вишенка на торте. Это классно когда у нас есть работающий Active Directory Domain Controller на Linux, но этого мало. Жизнь в мире, где в нашей локальной DNS зоне автоматически обновляются только IP адреса устройств непосредственно состоящих в домене не так радужна как могла бы быть. Решить это проблему мы и попробуем в этой статье. Заранее нужно обозначить что наше решение не будет обновлять обратную зону (PTR записи).
-
Контроллер домена Ubuntu — Настройка DHCP сервера
- Для начала устанавливаем DHCP сервер
sudo apt-get install isc-dhcp-server
- Затем создаём пользователя домена для работы с обновлениями
sudo samba-tool user create dhcpduser --description="Unprivileged user for TSIG-GSSAPI DNS updates via ISC DHCP server" --random-password
- Так же устанавливаем истечение пароля и добавляем в группу DnsAdmins
sudo samba-tool user setexpiry dhcpduser --noexpiry sudo samba-tool group addmembers DnsAdmins dhcpduser
AdminGuide.Ru@ag-dc-1:~$ sudo samba-tool user setexpiry dhcpduser --noexpiry Expiry for user 'dhcpduser' disabled. AdminGuide.Ru@ag-dc-1:~$ sudo samba-tool group addmembers DnsAdmins dhcpduser Added members to group DnsAdmins
- Теперь экспортируем данные
sudo samba-tool domain exportkeytab --principal=dhcpduser@ADMINGUIDE.LAN /etc/dhcpduser.keytab sudo chown dhcpd:dhcpd /etc/dhcpduser.keytab sudo chmod 400 /etc/dhcpduser.keytab
- Создаём скрипт
sudo nano /usr/local/bin/dhcp-dyndns.sh
#!/bin/bash # /usr/local/bin/dhcp-dyndns.sh # This script is for secure DDNS updates on Samba 4 # Version: 0.8.9 # Uncomment the next line if using a self compiled Samba and adjust for your PREFIX #PATH="/usr/local/samba/bin:/usr/local/samba/sbin:$PATH" BINDIR=$(samba -b | grep 'BINDIR' | grep -v 'SBINDIR' | awk '{print $NF}') WBINFO="$BINDIR/wbinfo" # DNS domain domain=$(hostname -d) if [ -z ${domain} ]; then 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/dhcpduser.keytab # krbcc ticket cache # /tmp/dhcp-dyndns.cc TESTUSER="$($WBINFO -u) | grep 'dhcpduser')" if [ -z "${TESTUSER}" ]; then logger "No AD dhcp user exists, need to create it first.. exiting." logger "you can do this by typing the following commands" logger "kinit Administrator@${REALM}" logger "samba-tool user create dhcpduser --random-password --description=\"Unprivileged user for DNS updates via ISC DHCP server\"" logger "samba-tool user setexpiry dhcpduser --noexpiry" logger "samba-tool group addmembers DnsAdmins dhcpduser" exit 1 fi # Check for Kerberos keytab if [ ! -f /etc/dhcpduser.keytab ]; then echo "Required keytab /etc/dhcpduser.keytab not found, it needs to be created." echo "Use the following commands as root" echo "samba-tool domain exportkeytab --principal=${SETPRINCIPAL} /etc/dhcpduser.keytab" echo "chown XXXX:XXXX /etc/dhcpduser.keytab" echo "Replace 'XXXX:XXXX' with the user & group that dhcpd runs as on your distro" echo "chmod 400 /etc/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/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=$? ;; delete) _KERBEROS nsupdate -g ${NSUPDFLAGS} << UPDATE server 127.0.0.1 realm ${REALM} update delete ${name}.${domain} 3600 A send UPDATE result1=$? ;; *) echo "Invalid action specified" exit 103 ;; esac result="${result1}" if [ "${result}" != "0" ]; then logger "DHCP-DNS Update failed: ${result}" else logger "DHCP-DNS Update succeeded" fi exit ${result}
Устанавливаем права на скрипт
sudo chmod 755 /usr/local/bin/dhcp-dyndns.sh
- Модифицируем файл с настройками
Создаём бекап и модифицируем конфигsudo cp /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd.conf_bak sudo nano /etc/dhcp/dhcpd.conf
Заменив содержимое на следующее:
authoritative; ddns-update-style none; subnet 192.168.1.0 netmask 255.255.255.0 { #Подсеть и маска на которую будет вещать dhcp сервер option subnet-mask 255.255.255.0; option broadcast-address 192.168.1.255; option time-offset 0; option routers 192.168.1.1; #Шлюз option domain-name "adminguide.lan"; #Имя домена option domain-name-servers 192.168.1.100; #ДНС сервера option netbios-name-servers 192.168.1.100; #NetBIOS сервера option ntp-servers 192.168.1.100; #NTP сервера pool { #Пулл адресов max-lease-time 1800; # Максимальное время аренды в секундах range 192.168.1.110 192.168.1.199; #Диапазон адресов } } on commit { set noname = concat("dhcp-", binary-to-ascii(10, 8, "-", leased-address)); set ClientIP = binary-to-ascii(10, 8, ".", leased-address); set ClientDHCID = concat ( suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2) ); set ClientName = pick-first-value(option host-name, config-option-host-name, client-name, noname); log(concat("adminguide.ru commit: IP: ", ClientIP, " DHCID: ", ClientDHCID, " Name: ", ClientName)); execute("/usr/local/bin/dhcp-dyndns.sh", "add", ClientIP, ClientDHCID, ClientName); } on release { set ClientIP = binary-to-ascii(10, 8, ".", leased-address); set ClientDHCID = concat ( suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2) ); log(concat("Release: IP: ", ClientIP)); execute("/usr/local/bin/dhcp-dyndns.sh", "delete", ClientIP, ClientDHCID, ClientName); } 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("/usr/local/bin/dhcp-dyndns.sh", "delete", ClientIP, "", "0"); }
- Редактируем права на запуск
sudo nano /etc/apparmor.d/usr.sbin.dhcpd
Добавляем в конец файла перед закрывающей скобкой }
/usr/local/bin/dhcp-dyndns.sh rix, /dev/tty wr, /usr/sbin/samba rix, /usr/bin/gawk rix, /usr/bin/grep rix, /usr/bin/hostname rix, /usr/bin/logger rix, /usr/bin/wbinfo rix, /usr/bin/date rix, /usr/bin/klist rix, /usr/bin/host rix, /proc/** wr, /usr/bin/kinit rix, /etc/dhcpduser.keytab rk, /run/samba/winbindd/pipe wr, /etc/dhcpduser.keytab rk, /tmp/* wrk, /usr/bin/nsupdate rix,
Рестарт AppArmor
sudo /etc/init.d/apparmor stop && sudo /etc/init.d/apparmor start
Рестарт DHCP сервера
sudo service isc-dhcp-server stop && sudo service isc-dhcp-server start
-
DHCP сервер для Linux AD-DC — Проверяем работу DHCP
В сети с ad-dc-1 у меня есть еще 1 ubuntu server с именем client-lin-1. Он не в домене, он не настраивался, он просто есть и он получает сетевые настройки по dhcp.
Пытаюсь пингануть этот клиент по имени, результат нулевой.
Включаю этот сервер, жду пока загрузится. После того как сервер загрузился, пытаюсь снова, пинг идёт.
Команды ping client-lin-1 и ping client-lin-1.adminguide.lan теперь будут успешно пинговать эту машину по имени. Как и другие ваши устройства не находящиеся в домене и получающие адреса по DHCP от контроллера домена.
Освобождаю и повторно запрашиваю IP адрес выполняя на клиенте команду:sudo dhclient -r && sudo dhclient
Смотрю логи командой
tail -n 250 /var/log/syslog
Вижу ответ похожий на:
Aug 30 16:56:23 ag-dc-1 dhcpd[10880]: Release: IP: 192.168.1.114 Aug 30 16:56:23 ag-dc-1 dhcpd[10880]: execute_statement argv[0] = /usr/local/bin/dhcp-dyndns.sh Aug 30 16:56:23 ag-dc-1 dhcpd[10880]: execute_statement argv[1] = delete Aug 30 16:56:23 ag-dc-1 dhcpd[10880]: execute_statement argv[2] = 192.168.1.114 Aug 30 16:56:23 ag-dc-1 dhcpd[10880]: execute_statement argv[3] = 00:0c:29:20:ce:d2 Aug 30 16:56:23 ag-dc-1 named[675]: samba_dlz: starting transaction on zone adminguide.lan Aug 30 16:56:23 ag-dc-1 named[675]: samba_dlz: allowing update of signer=dhcpduser\@ADMINGUIDE.LAN name=3\(NXDOMAIN\).adminguide.lan tcpaddr=127.0.0.1 type=A key=3167229815.sig-ag-dc-1.adminguide.lan/160/0 Aug 30 16:56:23 ag-dc-1 named[675]: client @0x7f1c180b8670 127.0.0.1#58645/key dhcpduser\@ADMINGUIDE.LAN: updating zone 'adminguide.lan/NONE': deleting rrset at '3\(NXDOMAIN\).adminguide.lan' A Aug 30 16:56:23 ag-dc-1 named[675]: samba_dlz: committed transaction on zone adminguide.lan Aug 30 16:56:23 ag-dc-1 dhcpd: DHCP-DNS Update succeeded Aug 30 16:56:23 ag-dc-1 dhcpd[10880]: DHCPRELEASE of 192.168.1.114 from 00:0c:29:20:ce:d2 (client-lin-1) via ens160 (found) Aug 30 16:56:23 ag-dc-1 dhcpd[10880]: DHCPDISCOVER from 00:0c:29:20:ce:d2 via ens160 Aug 30 16:56:24 ag-dc-1 dhcpd[10880]: DHCPOFFER on 192.168.1.114 to 00:0c:29:20:ce:d2 (client-lin-1) via ens160 Aug 30 16:56:24 ag-dc-1 dhcpd[10880]: adminguide.ru commit: IP: 192.168.1.114 DHCID: 00:0c:29:20:ce:d2 Name: client-lin-1 Aug 30 16:56:24 ag-dc-1 dhcpd[10880]: execute_statement argv[0] = /usr/local/bin/dhcp-dyndns.sh Aug 30 16:56:24 ag-dc-1 dhcpd[10880]: execute_statement argv[1] = add Aug 30 16:56:24 ag-dc-1 dhcpd[10880]: execute_statement argv[2] = 192.168.1.114 Aug 30 16:56:24 ag-dc-1 dhcpd[10880]: execute_statement argv[3] = 00:0c:29:20:ce:d2 Aug 30 16:56:24 ag-dc-1 dhcpd[10880]: execute_statement argv[4] = client-lin-1 Aug 30 16:56:24 ag-dc-1 named[675]: samba_dlz: starting transaction on zone adminguide.lan Aug 30 16:56:24 ag-dc-1 named[675]: samba_dlz: allowing update of signer=dhcpduser\@ADMINGUIDE.LAN name=client-lin-1.adminguide.lan tcpaddr=127.0.0.1 type=A key=3775092585.sig-ag-dc-1.adminguide.lan/160/0 Aug 30 16:56:24 ag-dc-1 named[675]: samba_dlz: allowing update of signer=dhcpduser\@ADMINGUIDE.LAN name=client-lin-1.adminguide.lan tcpaddr=127.0.0.1 type=A key=3775092585.sig-ag-dc-1.adminguide.lan/160/0 Aug 30 16:56:24 ag-dc-1 named[675]: client @0x7f1bf808a7f0 127.0.0.1#60997/key dhcpduser\@ADMINGUIDE.LAN: updating zone 'adminguide.lan/NONE': deleting rrset at 'client-lin-1.adminguide.lan' A Aug 30 16:56:24 ag-dc-1 named[675]: samba_dlz: subtracted rdataset client-lin-1.adminguide.lan 'client-lin-1.adminguide.lan.#0113600#011IN#011A#011192.168.1.112' Aug 30 16:56:24 ag-dc-1 named[675]: client @0x7f1bf808a7f0 127.0.0.1#60997/key dhcpduser\@ADMINGUIDE.LAN: updating zone 'adminguide.lan/NONE': adding an RR at 'client-lin-1.adminguide.lan' A 192.168.1.114 Aug 30 16:56:24 ag-dc-1 named[675]: samba_dlz: added rdataset client-lin-1.adminguide.lan 'client-lin-1.adminguide.lan.#0113600#011IN#011A#011192.168.1.114' Aug 30 16:56:24 ag-dc-1 named[675]: samba_dlz: subtracted rdataset adminguide.lan 'adminguide.lan.#0113600#011IN#011SOA#011ag-dc-1.adminguide.lan. hostmaster.adminguide.lan. 48 900 600 86400 3600' Aug 30 16:56:24 ag-dc-1 named[675]: samba_dlz: added rdataset adminguide.lan 'adminguide.lan.#0113600#011IN#011SOA#011ag-dc-1.adminguide.lan. hostmaster.adminguide.lan. 49 900 600 86400 3600' Aug 30 16:56:24 ag-dc-1 named[675]: samba_dlz: committed transaction on zone adminguide.lan Aug 30 16:56:24 ag-dc-1 dhcpd: DHCP-DNS Update succeeded Aug 30 16:56:24 ag-dc-1 dhcpd[10880]: DHCPREQUEST for 192.168.1.114 (192.168.1.100) from 00:0c:29:20:ce:d2 (client-lin-1) via ens160 Aug 30 16:56:24 ag-dc-1 dhcpd[10880]: DHCPACK on 192.168.1.114 to 00:0c:29:20:ce:d2 (client-lin-1) via ens160
- Для начала устанавливаем DHCP сервер
-
DHCP сервер для Linux AD-DC — Заключение
Таким образом мы и подошли к концу. Никогда не стоит забывать, что для улучшений ещё очень большой простор, но этот вариант позволит админу иметь в небольшом офисе лицензионный Active Directory Domain Controller с DNS и DHCP серверами, способными обслуживать не только компьютеры присоединённые к домену, но и все машины вообще. Что позволит уйти от настройки локальных сервисов на статические ip адреса, и перейти на использование динамических ip адресов в связке с dns именами устройств
P.S. Если у вас несколько сетевых интерфейсов настроенных на получение сетевых настроек по DHCP, они все получат настройки. Но команда host <device_name> вернёт адрес последнего интерфейса обратившегося к DHCP серверу.
P.S.S. Дополнение от пользователя @alex117100:
Если вы хотите автоматическое обновление обратной зоны, замените соответствующие куски в файле dhcpd.conf на представленные alex117100
# ddns update on commit { set noname = concat("dhcp-", binary-to-ascii(10, 8, "-", leased-address)); set ClientIP = binary-to-ascii(10, 8, ".", leased-address); set ClientDHCID = concat ( suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2) ); 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("/usr/local/bin/dhcp-dyndns.sh", "delete", ClientIP, ClientDHCID); execute("/usr/local/bin/dhcp-dyndns.sh", "add", ClientIP, ClientDHCID, ClientName); } on release { set ClientIP = binary-to-ascii(10, 8, ".", leased-address); set ClientDHCID = concat ( suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,1,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,2,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,3,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,4,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,5,1))),2), ":", suffix (concat ("0", binary-to-ascii (16, 8, "", substring(hardware,6,1))),2) ); log(concat("Release: IP: ", ClientIP)); execute("/usr/local/bin/dhcp-dyndns.sh", "delete", ClientIP, ClientDHCID); } 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("/usr/local/bin/dhcp-dyndns.sh", "delete", ClientIP, "", "0"); }
13 комментариев
Добрый день,
Все работает все тесты прошли успешно. Но при подключении к оснастке DNS обратная зона не видна. Прямая зона загрузилась. Это правильное поведение?
После перезагрузки настроенный и работающий сервер перестает авторизовывать даже уже введённые в домен машинки.
kinit administrator возвращает: Cannot contact any KDC for realm ‘*******.LAN’ while getting initial credentials.
Копал в сторону krb5kdc, пока ничего не накопал.
Опытным путём, было выяснено что проблемы начинаются после версии самбы 4.6.8, пока я жду появления стабильной версии среди последних релизов, о чём наверное сделаю отдельную публикацию.
Пропустил момент из этой статьи с настройкой и перезапуском Apparmor — и, о чудо! — контроллер домена заработал, как положено. Пока не раскопал, почему Apparmor блокировал работу керберос.
Ещё из непонятного — днс форвардинг с контроллера доменана шлюз иногда как будто отваливается, на клиентских компьютерах «пропадает» интернет из-за отсутствия резолвинга. Проходит само.
Отваливание днс-форвардинга на шлюз вроде понял — управляемый свитч des-3028 (ещё разбираюсь, какой из них и не все ли попеременно — их у меня 10 штук по зданию) начинают блокировать трафик контроллера домена о.О: одновременно отваливается локальная сеть и интернет на машинках, висящих на этих свитчах. Машинки, висящие на других свитчах, локальную сеть не теряют, но теряют интернет, бо шлюз подключен к КД через один из свитчей des-3028.
С наскоку проблему не победил, надо курить документацию свитчей.
После установки выяснилось. Контроллер работает на уровне 2008_R2. Попытка повысить до уровня 2012_R2 приводит к ошибкам. sudo samba-tool domain level raise —domain-level=2012_R2. Кто-нибудь сталкивался? Как победить?
Привет, самба не умеет в контроллер домена выше чем 2008 r2
Куда скинуть допиленный скрипт обновления dns? В моем варианте обновляются обратные dns зоны.
Привет! Можно ссылкой на https://pastebin.com/ прямо в комментарий 🙂
Дружище спасибо за твои статьи! пока всё получается!
А где посмотреть аренду адресов…? Когда-то настраивал шлюз на debian’e, в связке с DHCP+DNS. Там это просматривалось в /var/lib/dhcp/dhcpd.leases
Добрый вечер.
Настроил сервер по вашим статьям. Все работает отлично. Спасибо.
Но хочу чтобы этот сервер был еще и интернет-шлюзом.
В нем две сетевые карты — одна смотрит в интернет, другая в локальную сеть.
Как только я включаю интерфейс смотрящий в интернет, система начинает работать со сбоями, а именно сервер пингуется не только на свой локальный адрес и свое имя но и еще на ip сетевой карты смотрящей в инетрнет, из-за этого доменная сеть не работает стабильно.
Спасибо.
Тут могу только посоветовать установить на этот сервер гипервизор и внутри него поднять одну виртмашину со шлюзом и вторую с контроллером домена. По реализации контроллера домена и шлюза в рамках одной ОС могу лишь очень не рекомендовать так делать т.к. это выстрел себе в колено сидя на бочке пороха выброшенной из самолёта и стремительно летящей прямиком в ад.