DNS: установка BIND, DNS Load Balancing и network-based routing через view

By | 03/21/2018
 

Ниже описывается установка DNS сервера BIND (Berkeley Internet Name Domain) на AWS EC2 в VPC + два дополнительных инстанса в разных подсетях (А и В), после чего на нём реализуем следующее:

  1. DNS round-robin Load Balancer – будет распределять трафик по очереди на каждый из двух дополнительных интансов
  2. DNS network-based routing –  тут задача интереснее:
    1. если запрос приходит из подсети A – возвращаем адрес из подсети A
    2. если запрос приходит из подсети B – возвращаем адрес из посети B
    3. всем остальным – возвращаем “общий” IP

Практического смысла во второй части особо нет, особенно если дело касается AWS, но для “поиграться” с DNS “маршрутизацией” на основе сети клиента – подойдёт.

Когда-то аналогично выполнялась настройка GeoIP маршрутизации через BIND – для второй части используем точно такой же подход: view и match-clinets.

DNS AWS

Лирическое отступление, касающееся DNS network-based routing и AWS.

У Amazon для раздачи разных IP используется другой подход: в VPC создаётся свой DNS (если указана опция enableDnsSupport, по умолчанию она True), и DNS запросы внутри этой VPC направляются на него (см. DNS Support in Your VPC и Amazon DNS Server).

Далее этот DNS указывается в resolv.conf EC2 интанса самим AWS во время запуска EC2 в VPC:

admin@ip-10-0-1-246:~$ cat /etc/resolv.conf | grep name
nameserver 10.0.0.2

Поэтому при запросе DNS с EC2 – будет использован приватный IP:

root@ip-10-0-1-157:/home/admin# dig ec2-34-253-58-71.eu-west-1.compute.amazonaws.com +short
10.0.1.157
root@ip-10-0-1-157:/home/admin# dig @10.0.0.2 ec2-34-253-58-71.eu-west-1.compute.amazonaws.com +short          
10.0.1.157

А “через мир”, например DNS Google – внешний:

root@ip-10-0-1-157:/home/admin# dig @8.8.8.8 ec2-34-253-58-71.eu-west-1.compute.amazonaws.com +short
34.253.58.71

т.к. Google получает информацию о зонах с authority servers, которые для доменов Amazon-а являются… DNS серверами Amazon-а, которые и возвращают публичный IP.

Проверим: находим Authority Section для домена eu-west-1.compute.amazonaws.com, который содержит нашу запись ec2-34-253-58-71.eu-west-1.compute.amazonaws.com:

dig eu-west-1.compute.amazonaws.com +noall +authority
; <<>> DiG 9.12.0 <<>> eu-west-1.compute.amazonaws.com +noall +authority
;; global options: +cmd
eu-west-1.compute.amazonaws.com. 872 IN SOA     dns-external-master.amazon.com. root.amazon.com. 2013095035 28800 900 604800 7207

И проверяем значение IN A, который отдаёт dns-external-master.amazon.com (и который в результате попадает в DNS Google и нашего провайдера):

14:28:28 [setevoy@setevoy-arch-work ~]  $ dig @dns-external-master.amazon.com ec2-34-253-58-71.eu-west-1.compute.amazonaws.com +short
34.253.58.71

Понятно, что запрос с EC2 напрямую (через @ns.name.tld) к тому же DNS вернёт тот же результат:

root@ip-10-0-1-157:/home/admin# dig @dns-external-master.amazon.com ec2-34-253-58-71.eu-west-1.compute.amazonaws.com +short
34.253.58.71

Создание сервисов

Для начала развернём тестовое окружение, которое будет включать в себя 3 EC2 – один для DNS, и два в роли клиентов, и VPC с тремя подсетями – для DNS и для клиентов.

Подсети все будут публичными, потому обойдёмся без NAT Gateway.

VPC

Создаём VPC:

aws ec2 create-vpc --cidr-block 10.0.0.0/16

Добавляем тег Name:

aws ec2 create-tags --resources vpc-13951475 --tags Key=Name,Value=DNStest

Проверяем:

aws ec2 describe-vpcs --vpc-ids vpc-13951475 --query 'Vpcs[*].Tags' --output text
Name    DNStest

Security Group

Обновляем Security Group этой VPC – открываем 22 TCP:

aws ec2 authorize-security-group-ingress --group-id sg-69520913 --protocol tcp --port 22 --cidr 194.***.***.45/24

53 UDP и TCP для BIND отовсюду (т.к. мы будем обслуживать собственню зону, и нам надо будет её отдавать другим DNS):

aws ec2 authorize-security-group-ingress --group-id sg-69520913 --protocol udp --port 53 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-id sg-69520913 --protocol tcp --port 53 --cidr 0.0.0.0/0

Subnets

Создаём подсеть для ЕС2 с BIND:

aws ec2 create-subnet --vpc-id vpc-13951475 --cidr-block 10.0.1.0/24

Тег:

aws ec2 create-tags --resources subnet-48657413 --tags Key=Name,Value=DNStestBINDnet

Аналогично добавляем ещё две подсети для клиентов:

aws ec2 create-subnet --vpc-id vpc-13951475 --cidr-block 10.0.2.0/24
aws ec2 create-tags --resources subnet-817e6fda --tags Key=Name,Value=DNStestSubnetA
aws ec2 create-subnet --vpc-id vpc-13951475 --cidr-block 10.0.3.0/24
aws ec2 create-tags --resources subnet-c2776699 --tags Key=Name,Value=DNStestSubnetB

Internet Gateway

Добавляем Internet Gateway:

aws ec2 create-internet-gateway
aws ec2 create-tags --resources igw-c1690ca6 --tags Key=Name,Value=DNStestIGW

Подключаем IGW к VPC:

aws ec2 attach-internet-gateway --internet-gateway-id igw-c1690ca6 --vpc-id vpc-13951475

Route Table

Добавляем таблицу маршрутизации:

aws ec2 create-route-table --vpc-id vpc-13951475
aws ec2 create-tags --resources rtb-cdbf63b4 --tags Key=Name,Value=DNStestRTB

Добавляем правило маршрутизации в эту таблицу – весь трафик к 0.0.0.0 через IGW, созданный ранеее:

aws ec2 create-route --route-table-id rtb-cdbf63b4 --destination-cidr-block 0.0.0.0/0 --gateway-id igw-c1690ca6

Подключаем эту таблицу к подсетям:

aws ec2 associate-route-table --route-table-id rtb-cdbf63b4 --subnet-id subnet-48657413
aws ec2 associate-route-table --route-table-id rtb-cdbf63b4 --subnet-id subnet-817e6fda
aws ec2 associate-route-table --route-table-id rtb-cdbf63b4 --subnet-id subnet-c2776699

EC2

Создаём инстансы.

Для BIND:

aws ec2 run-instances --image-id ami-913a40e8 --count 1 --instance-type t2.nano --key-name rtfm-dev --subnet-id subnet-48657413 --associate-public-ip-address --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=BINDtestServer}]'

Клиент в посети А:

aws ec2 run-instances --image-id ami-913a40e8 --count 1 --instance-type t2.nano --key-name rtfm-dev --subnet-id subnet-817e6fda --associate-public-ip-address --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=BINDtestClientA}]'

Клиент B:

aws ec2 run-instances --image-id ami-913a40e8 --count 1 --instance-type t2.nano --key-name rtfm-dev --subnet-id subnet-c2776699 --associate-public-ip-address --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=BINDtestClientB}]'

Подключаемся, проверяем сеть:

ssh -i rtfm-dev.pem admin@34.253.58.71
admin@ip-10-0-1-157:~$ ping ya.ru -c 1
PING ya.ru (87.250.250.242) 56(84) bytes of data.
64 bytes from ya.ru (87.250.250.242): icmp_seq=1 ttl=36 time=44.4 ms
--- ya.ru ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 44.424/44.424/44.424/0.000 ms

ОК – можно приступать к установке BIND.

Установка BIND

Наш BIND будет авторитарным (authoritative) сервером для домена bindtest.rtfm.co.ua, и рекурсивным (или resolving) сервером для клиентов А и В.

“Поняслася!” (с)

Устанавливаем BIND:

root@ip-10-0-1-157:/home/admin# apt update && apt -y install bind9 bind9utils bind9-doc

Редактируем /etc/bind/named.conf.options, добавляем ACL, который будет содержать сервера, с которых будут разрешены рекурсивные запросы (сам сервер, и клиенты А и В).

Перед options добавляем ACL “trusted”:

acl "trusted" {

    10.0.1.157; # current host
    10.0.2.145; # ClientA
    10.0.3.164; # ClientB
};

В сам блок options добавляем:

...
    recursion yes;                 # enables resursive queries
    allow-recursion { trusted; };  # allows recursive queries from "trusted" clients
    listen-on { 10.128.10.11; };   # ns1 private IP address - listen on private network only
    allow-transfer { none; };      # disable zone transfers by default
...

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

acl "trusted" {

    10.0.1.157; # current host
    127.0.0.1;
    10.0.2.145; # ClientA
    10.0.3.164; # ClientB
};

options {

    directory "/var/cache/bind";
    dnssec-validation auto;
    auth-nxdomain no;              # conform to RFC1035
    listen-on-v6 { any; };

    recursion yes;                  # enables resursive queries
    allow-recursion { trusted; };   # allows recursive queries from "trusted" clients
    allow-transfer { none; };       # disable zone transfers by default
    allow-query { any; };
    # disable built-in server information 
    version none;                   
    hostname none;                  
    server-id none;                 
};

logging {
    channel b_query {
        file "/var/log/bind9/query.log" versions 2 size 1m;
        print-time yes;
        severity info;
    };
    category queries { b_query; };
};

Создаём каталог для логов:

root@ip-10-0-1-157:/etc/bind# mkdir /var/log/bind9 && chown bind:bind /var/log/bind9

Проверяем конфиг:

root@ip-10-0-1-157:/etc/bind# named-checkconf

Добавляем BIND в автозапуск:

root@ip-10-0-1-157:/etc/bind# systemctl enable bind9
Synchronizing state of bind9.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable bind9

Перезапускаем сервис:

root@ip-10-0-1-157:/etc/bind# systemctl restart bind9

Проверяем:

root@ip-10-0-1-157:/etc/bind# netstat -anp | grep named
tcp        0      0 10.0.1.157:53           0.0.0.0:*               LISTEN      1782/named
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN      1782/named
tcp        0      0 127.0.0.1:953           0.0.0.0:*               LISTEN      1782/named
tcp6       0      0 :::53                   :::*                    LISTEN      1782/named
tcp6       0      0 ::1:953                 :::*                    LISTEN      1782/named
udp        0      0 10.0.1.157:53           0.0.0.0:*                           1782/named
udp        0      0 127.0.0.1:53            0.0.0.0:*                           1782/named
udp6       0      0 :::53                   :::*                                1782/named

Пробуем запрос:

root@ip-10-0-1-157:/etc/bind# dig @localhost ya.ru +short
87.250.250.242

Лог:

root@ip-10-0-1-157:/etc/bind# tail /var/log/bind9/query.log
21-Mar-2018 13:41:14.014 client 127.0.0.1#40641 (ya,ru): query: ya.ru IN A +E (127.0.0.1)

ОК, тут всё готово.

Настройка Authoritative сервера

Наш BIND работает на EC2, на IP которого через CNAME направлены домены ns1-example.rtfm.co.ua и ns2-example.rtfm.co.ua (потребуется два, что бы добавить новый субдомен у регистратора):

14:42:19 [setevoy@setevoy-arch-work ~]  $ dig ns1-example.rtfm.co.ua +short
ec2-34-253-58-71.eu-west-1.compute.amazonaws.com.
34.253.58.71

Это будут Name Servers для нашего bindtest.rtfm.co.ua, над которым мы будем “проводить эксперименты”.

Сами домены ns1-example.rtfm.co.ua и ns2-* обслуживаются серверами регистратора – Freehost.ua:

16:24:05 [setevoy@venti ~] $ whois rtfm.co.ua | grep "Name Server"
Name Server:DELTA.FREEHOST.COM.UA
Name Server:ALPHA.FREEHOST.COM.UA
Name Server:BETA.FREEHOST.COM.UA
Name Server:GAMMA.FREEHOST.COM.UA

Добавление зоны в BIND

Редактируем /etc/bind/named.conf.local, добавляем указание на домен (зону), который мы будем обслуживать:

zone "bindtest.rtfm.co.ua" {
        type master;
        file "/etc/bind/zones/db.bindtest.rtfm.co.ua";
};

Создаём каталог:

root@ip-10-0-1-157:/etc/bind# mkdir /etc/bind/zones/

В нём создаём файл зоны – копируем файл /etc/bind/db.local:

root@ip-10-0-1-157:/etc/bind# cp /etc/bind/db.local /etc/bind/zones/db.bindtest.rtfm.co.ua

Редактируем /etc/bind/zones/db.bindtest.rtfm.co.ua, меняем SOA с записи вида:

@   IN  SOA localhost. root.localhost. (

На:

@   IN  SOA bindtest.rtfm.co.ua. ns1-example.rtfm.co.ua. (

Тут bindtest.rtfm.co.ua – домен, который мы будем обслуживать, а ns1-example.rtfm.co.ua – FQDN нашего ЕС2 с BIND-ом, он и будет Start of authority для bindtest.rtfm.co.ua.

Обновляем остальную информацию, не забываем увеличивать поле Serial на единицу при каждому изменении.

Приводим его к виду:

$TTL    604800
@   IN  SOA bindtest.rtfm.co.ua. ns1-example.rtfm.co.ua. (
                  3     ; Serial
             604800     ; Refresh
              86400     ; Retry
            2419200     ; Expire
             604800 )   ; Negative Cache TTL
;
@   IN  NS  ns1-example.rtfm.co.ua.
@   IN  NS  ns2-example.rtfm.co.ua.
@   IN  A   34.253.58.71

Проверяем конфиги:

root@ip-10-0-1-157:/etc/bind# named-checkconf

Проверяем файл зоны:

root@ip-10-0-1-157:/etc/bind# named-checkzone bindtest.rtfm.co.ua zones/db.bindtest.rtfm.co.ua
zone bindtest.rtfm.co.ua/IN: loaded serial 4
OK

Перезагружаем named:

root@ip-10-0-1-157:/etc/bind# systemctl restart bind9

Пробуем получить информацию:

root@ip-10-0-1-157:/etc/bind# dig @localhost bindtest.rtfm.co.ua +answer
; <<>> DiG 9.10.3-P4-Debian <<>> @localhost bindtest.rtfm.co.ua +answer
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4154
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;bindtest.rtfm.co.ua.           IN      A
;; ANSWER SECTION:
bindtest.rtfm.co.ua.    604800  IN      A       34.253.58.71
;; AUTHORITY SECTION:
bindtest.rtfm.co.ua.    604800  IN      NS      ns1-example.rtfm.co.ua.
bindtest.rtfm.co.ua.    604800  IN      NS      ns2-example.rtfm.co.ua.
ОК -- тут всё работает.

Добавляем у регистратора домена rtfm.co.ua запись bindtest.rtfm.co.ua с параметрами IN NS ns1-example.rtfm.co.ua и ns2-example.rtfm.co.ua:

И пробуем получить информацию о домене “из мира”:

16:37:54 [setevoy@setevoy-arch-work ~]  $ dig @ns1-example.rtfm.co.ua bindtest.rtfm.co.ua +short
34.253.58.71

DNS Load Balancing

Идея простого DNS Load Balancing – вернуть клиенту несколько IP в ответ на запрос записи IN A.

В списке IP, который будет возвращать BIND порядок IP меняется случайным образом – такой себе round-robin. Клиент первым делом попробует выполнить подключение к первому из полученных IP, и если это не сработает – он использует следующий из списка.

ОК, обновляем файл зоны:

$TTL    604800
@   IN  SOA bindtest.rtfm.co.ua. ns1-example.rtfm.co.ua. (
                  5     ; Serial
             604800     ; Refresh
              86400     ; Retry
            2419200     ; Expire
             604800 )   ; Negative Cache TTL
;
@   IN  NS  ns1-example.rtfm.co.ua.
@   IN  NS  ns2-example.rtfm.co.ua.
@   IN  A   34.253.58.71
@   IN  A   34.240.126.223
@   IN  A   34.242.8.220

Тут 34.242.8.220 – публичный IP Клиента А, а 34.240.126.223 – Клиента В, используем просто для примера.

Не забываем обновить Serial.

Проверяем файл зоны:

root@ip-10-0-1-157:/etc/bind# named-checkzone bindtest.rtfm.co.ua zones/db.bindtest.rtfm.co.ua
zone bindtest.rtfm.co.ua/IN: loaded serial 5
OK

Пробуем получить IP:

17:11:42 [setevoy@setevoy-arch-work ~]  $ dig bindtest.rtfm.co.ua +short
34.253.58.71
34.242.8.220
34.240.126.223
17:11:50 [setevoy@setevoy-arch-work ~]  $ dig bindtest.rtfm.co.ua +short
34.242.8.220
34.240.126.223
34.253.58.71
17:12:00 [setevoy@setevoy-arch-work ~]  $ dig bindtest.rtfm.co.ua +short
34.240.126.223
34.253.58.71
34.242.8.220

Три раза получаем первыми разные IP – вот и простой DNS Load balancer.

Продемонстрируем с NIGNX – на каждом хосте устанавливаем его:

17:14:06 [setevoy@setevoy-arch-work ~/Work/Bitbucket/aws-credentials] [master*] $ ssh -i rtfm-dev.pem admin@34.240.126.223 'sudo apt install -y nginx'
17:14:37 [setevoy@setevoy-arch-work ~/Work/Bitbucket/aws-credentials] [master*] $ ssh -i rtfm-dev.pem admin@34.253.58.71 'sudo apt install -y nginx'
17:15:04 [setevoy@setevoy-arch-work ~/Work/Bitbucket/aws-credentials] [master*] $ ssh -i rtfm-dev.pem admin@34.242.8.220 'sudo apt install -y nginx'

На каждом обновляем файл /var/www/html/index.nginx-debian.html:

ssh -i rtfm-dev.pem admin@34.253.58.71 'sudo bash -c "echo BindServer > /var/www/html/index.nginx-debian.html"'
ssh -i rtfm-dev.pem admin@34.242.8.220 'sudo bash -c "echo This is ClientA > /var/www/html/index.nginx-debian.html"'
ssh -i rtfm-dev.pem admin@34.240.126.223 'sudo bash -c "echo This is ClientB > /var/www/html/index.nginx-debian.html"'

Открываем порт 80 в SecurityGroup:

aws ec2 authorize-security-group-ingress --group-id sg-69520913 --protocol tcp --port 80 --cidr 0.0.0.0/0

Проверяем:

17:21:34 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
This is ClientB
17:21:35 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
BindServer
17:21:36 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
This is ClientA
17:21:37 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
This is ClientB
17:21:38 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
BindServer
17:21:39 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
This is ClientA
17:21:40 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
This is ClientB

Гасим NGINX на одном из северов, например на ClientB:

17:20:06 [setevoy@setevoy-arch-work ~/Work/Bitbucket/aws-credentials] [master*] $ ssh -i rtfm-dev.pem admin@34.240.126.223 'sudo bash -c "service nginx stop"'

Проверяем:

17:22:23 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
This is ClientA
17:25:52 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
BindServer
17:25:53 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
BindServer
17:25:54 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
This is ClientA
17:25:55 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
BindServer
17:25:56 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
BindServer
17:25:57 [setevoy@setevoy-arch-work ~]  $ curl bindtest.rtfm.co.ua
This is ClientA

Главный недостаток DNS Load Balancer – что он не имеет никакой возможности узнать насколько загружен тот или иной хост из пула адресов, которые DNS возвращает клиенту, и даже не может проверить – жив ли он (например – отвечает ли NGINX на 80 порту), поэтому не стоит считать его fail-over механизмом.

Кроме того – DNS медленно реагирует на изменения в конфигурации: пока не истечёт TTL для зоны – другие DNS не обновят информацию в своих кешах и будут отдавать старые параметры.

DNS network-based routing

Следующая задача – обеспечить раздачу разных IP в зависимости от того – откуда пришёл клиент.

Если запрос приходит от ClientA (из подсети A) – отдаём ему IP 34.242.8.220, если ClientB – то 34.240.126.223, для всех остальных – 34.253.58.71.

Аналогичный подход  используется в посте Debian: настройка GeoIP для BIND – создаём отдельные файлы зон для различных клиентов, и с помощью view и оператора match-clients выбираем какую зону кому отдавать.

Обновляем named.conf.options – создаём access control list-ы для каждого клиента  – подсетей, которые создавали:

...
acl "subnet-a" {
    10.0.2.0/24;
};

acl "subnet-b" {
    10.0.3.0/24;
};
...

Копируем файл зоны db.bindtest.rtfm.co.ua – создаём два дополнительных файла – для клиентов из подсети А, и для клиентов из подсети В:

root@ip-10-0-1-157:/etc/bind# cp zones/db.bindtest.rtfm.co.ua zones/db-net-a.bindtest.rtfm.co.ua
root@ip-10-0-1-157:/etc/bind# cp zones/db.bindtest.rtfm.co.ua zones/db-net-b.bindtest.rtfm.co.ua

Теперь у нас тут есть:

root@ip-10-0-1-157:/etc/bind# ls -l zones
total 12
-rw-r--r-- 1 root bind 328 Mar 21 15:10 db.bindtest.rtfm.co.ua
-rw-r--r-- 1 root bind 328 Mar 21 15:53 db-net-a.bindtest.rtfm.co.ua
-rw-r--r-- 1 root bind 328 Mar 21 15:53 db-net-b.bindtest.rtfm.co.ua

Данные из файла db.bindtest.rtfm.co.ua будем отдавать всем “внешним” клиентам, данные из db-net-a.bindtest.rtfm.co.ua – клиентам из подсети А, данные из db-net-b.bindtest.rtfm.co.ua – клиентам из подсети В.

Обновляем в них IN A, оставляем по одной, и инкременим Serial:

root@ip-10-0-1-157:/etc/bind# grep -r "A\|Serial" zones/* | grep -v SOA
zones/db.bindtest.rtfm.co.ua:                         6         ; Serial
zones/db.bindtest.rtfm.co.ua:@  IN      A       34.253.58.71
zones/db-net-a.bindtest.rtfm.co.ua:                           6         ; Serial
zones/db-net-a.bindtest.rtfm.co.ua:@   IN  A   34.242.8.220
zones/db-net-b.bindtest.rtfm.co.ua:                           6         ; Serial
zones/db-net-b.bindtest.rtfm.co.ua:@   IN  A   34.240.126.223

Проверяем:

root@ip-10-0-1-157:/etc/bind# named-checkzone bindtest.rtfm.co.ua zones/db.bindtest.rtfm.co.ua
zone bindtest.rtfm.co.ua/IN: loaded serial 6
OK
root@ip-10-0-1-157:/etc/bind# named-checkzone bindtest.rtfm.co.ua zones/db-net-a.bindtest.rtfm.co.ua
zone bindtest.rtfm.co.ua/IN: loaded serial 6
OK
root@ip-10-0-1-157:/etc/bind# named-checkzone bindtest.rtfm.co.ua zones/db-net-b.bindtest.rtfm.co.ua
zone bindtest.rtfm.co.ua/IN: loaded serial 6
OK

Обновляем name.conf.local добавляем view и условия:

view "network-A" {
    match-clients { subnet-a; };
    recursion no;
    zone bindtest.rtfm.co.ua {
        type master;
        file "/etc/bind/zones/db-net-a.bindtest.rtfm.co.ua";
    };
};

view "network-B" {
    match-clients { subnet-b; };
    recursion no;
    zone bindtest.rtfm.co.ua {
        type master;
        file "/etc/bind/zones/db-net-b.bindtest.rtfm.co.ua";
    };
};

view "NotMatched" {
    match-clients { any; };
    recursion no;
    zone bindtest.rtfm.co.ua {
        type master;
        file "/etc/bind/zones/db.bindtest.rtfm.co.ua";
    };
};

Во избежание ошибки:

root@ip-10-0-1-157:/etc/bind# named-checkconf
/etc/bind/named.conf.default-zones:2: when using 'view' statements, all zones must be in views

Добавляем view для всех зон в /etc/bind/named.conf.default-zones:

view localhost_resolver {
    // prime the server with knowledge of the root servers
    zone "." {
        type hint;
        file "/etc/bind/db.root";
    };

    // be authoritative for the localhost forward and reverse zones, and for
    // broadcast zones as per RFC 1912

    zone "localhost" {
        type master;
        file "/etc/bind/db.local";
    };

    zone "127.in-addr.arpa" {
        type master;
        file "/etc/bind/db.127";
    };

    zone "0.in-addr.arpa" {
        type master;
        file "/etc/bind/db.0";
    };

    zone "255.in-addr.arpa" {
        type master;
        file "/etc/bind/db.255";
    };
};

Проверяем:

root@ip-10-0-1-157:/etc/bind# named-checkconf

Перезапускаем bind:

root@ip-10-0-1-157:/etc/bind# systemctl restart bind9

Пробуем с клиента А:

18:15:28 [setevoy@setevoy-arch-work ~/Work/Bitbucket/aws-credentials] [master*] $ ssh -i rtfm-dev.pem admin@34.242.8.220 dig @ns1-example.rtfm.co.ua bindtest.rtfm.co.ua +short
34.242.8.220

И лог BIND:

21-Mar-2018 16:15:30.585 client 10.0.2.145#55753 (bindtest.rtfm.co.ua): view network-A: query: bindtest.rtfm.co.ua IN A +E (10.0.1.157)

Пробуем с клиента из подсети В:

18:15:30 [setevoy@setevoy-arch-work ~/Work/Bitbucket/aws-credentials] [master*] $ ssh -i rtfm-dev.pem admin@34.240.126.223 dig @ns1-example.rtfm.co.ua bindtest.rtfm.co.ua +short
34.240.126.223

И лог BIND:

21-Mar-2018 16:15:30.585 client 10.0.2.145#55753 (bindtest.rtfm.co.ua): view network-A: query: bindtest.rtfm.co.ua IN A +E (10.0.1.157)
21-Mar-2018 16:16:12.364 client 10.0.3.164#36711 (bindtest.rtfm.co.ua): view network-B: query: bindtest.rtfm.co.ua IN A +E (10.0.1.157)

И пробуем из мира:

18:16:52 [setevoy@setevoy-arch-work ~]  $ dig @ns1-example.rtfm.co.ua bindtest.rtfm.co.ua +short
34.253.58.71

Лог:

21-Mar-2018 16:15:30.585 client 10.0.2.145#55753 (bindtest.rtfm.co.ua): view network-A: query: bindtest.rtfm.co.ua IN A +E (10.0.1.157)
21-Mar-2018 16:16:12.364 client 10.0.3.164#36711 (bindtest.rtfm.co.ua): view network-B: query: bindtest.rtfm.co.ua IN A +E (10.0.1.157)
21-Mar-2018 16:16:52.487 client 194.***.***.45#12659 (bindtest.rtfm.co.ua): view NotMatched: query: bindtest.rtfm.co.ua IN A +E (10.0.1.157)

Один нюанс тут – если мы вызов curl с любого из клиентов – он нам везде вернёт 34.253.58.71:

18:24:05 [setevoy@setevoy-arch-work ~/Work/Bitbucket/aws-credentials] [master*] $ ssh -i rtfm-dev.pem admin@34.242.8.220 curl -s bindtest.rtfm.co.ua
BindServer
18:36:01 [setevoy@setevoy-arch-work ~/Work/Bitbucket/aws-credentials] [master*] $ ssh -i rtfm-dev.pem admin@34.240.126.223 curl -s bindtest.rtfm.co.ua
BindServer

А в логе будет указано сработвашее условие NotMached:

21-Mar-2018 16:36:14.348 client 52.213.251.132#13928 (bindtest.rtfm.co.ua): view NotMatched: query: bindtest.rtfm.co.ua IN A -EDC (10.0.1.157)
21-Mar-2018 16:36:14.390 client 34.245.138.44#57054 (bindtest.rtfm.co.ua): view NotMatched: query: bindtest.rtfm.co.ua IN AAAA -EDC (10.0.1.157)

Если обратить внимание на client – 52.213.251.132 и 34.245.138.44 – то становится понятна причина, вспомним наши ACL-ки:

...
acl "subnet-a" {
    10.0.2.0/24;
};

acl "subnet-b" {
    10.0.3.0/24;
};
...

Кроме того – всоминаем resolv.conf, о котором упоминалось в начале – он содержит 10.0.0.2, который уже выполняет запрос через вышестоящий DNS, в результате к нашему ns1-example.rtfm.co.ua запросы приходят не с IP Клиента А и В, а от внешних DNS-серверов.

Обновим /etc/resolv.conf например на Клиенте А, укажем IP нашего DNS, что бы Клиент А обращался к нему напрямую:

nameserver 34.253.58.71

На BIND обновляем ACL для подсети-а:

...
acl "subnet-a" {
    10.0.2.0/24;
    34.242.8.220;
};
...

Перезапускаем:

root@ip-10-0-1-157:/etc/bind# systemctl restart bind9

Пробуем curl с клиента-А:

18:44:34 [setevoy@setevoy-arch-work ~/Work/Bitbucket/aws-credentials] [master*] $ ssh -i rtfm-dev.pem admin@34.242.8.220 curl -s bindtest.rtfm.co.ua
This is ClientA

И лог BIND:

21-Mar-2018 16:44:39.276 client 34.242.8.220#39845 (bindtest.rtfm.co.ua): view network-A: query: bindtest.rtfm.co.ua IN AAAA + (10.0.1.157)

Вот – как-то так оно всё и работает…