Перейти до вмісту

B5. Власні DNS і TLS

середнійспирається на модуль 13, модуль 15

У модулі 13 ланцюжок «клієнт → резолвер → авторитетний сервер» описано словами, а в модулі 15 словами ж описано, як клієнт вирішує, чи вірити сертифікату. Тут ви збираєте обидва механізми власноруч, на одній машині й без інтернету, тому нічого не приховано від вас ні кешем провайдера, ні браузерним сховищем довіри.

Після цієї роботи ви зможете:

  • описати зону в файлі й підняти для неї авторитетний сервер (nsd);
  • налаштувати рекурсивний резолвер (unbound) так, щоб він знав, де шукати вашу зону, і показати, що він справді питає авторитетний сервер, а потім віддає відповідь із кешу із зменшуваним TTL;
  • випустити власний центр сертифікації й сертифікат сервера з правильним subjectAltName за допомогою openssl;
  • налаштувати nginx на HTTPS лише з TLS 1.2 і 1.3;
  • довести, що клієнт вірить вашому CA і більше нікому, і що перевірка імені справді відбувається;
  • прочитати рукостискання TLS 1.2 у tshark і знайти в ньому SNI, вибір шифру й сертифікат.

Так виглядає внутрішня інфраструктура будь-якої компанії: власний домен для внутрішніх служб, свій CA для сертифікатів, яким не потрібен публічний центр. Коли після цього «сайт не відкривається з помилкою сертифіката», ви знаєте, на якому з п’яти місць шукати причину.

Результат роботи: чотири хости в просторах імен (три служби й клієнт) і два файли, що їх перевіряє чекер: сертифікат вашого CA і знімок рукостискання.

Топологія. Назви просторів імен і адреси фіксовані, назви інтерфейсів ви обираєте самі. Усі чотири хости лежать в одній підмережі 10.55.0.0/24; з’єднати їх можна як завгодно (у рекомендованому варіанті це міст у п’ятому просторі b5-sw, як у B1).

Простір імен Адреса Що в ньому працює
b5-cli 10.55.0.10/24 клієнт: dig, curl, openssl s_client, tshark
b5-res 10.55.0.53/24 рекурсивний резолвер unbound
b5-auth 10.55.0.54/24 авторитетний сервер зони nsd (або bind9)
b5-web 10.55.0.80/24 nginx з HTTPS на порту 443

Домен і записи. Вигаданий домен mini.test (зона .test зарезервована для випробувань і в публічному DNS ніколи не з’явиться). Зона містить:

Запис Значення TTL
mini.test. NS ns1.mini.test. 300
ns1.mini.test. A 10.55.0.54 300
www.mini.test. A 10.55.0.80 300
api.mini.test. CNAME www.mini.test. 300
mini.test. SOA за вашим вибором —

Що зробити:

  1. Зібрати топологію з таблиці й переконатися, що b5-cli пінгує всіх трьох.
  2. Написати файл зони, підняти nsd у b5-auth (слухає лише 10.55.0.54).
  3. Підняти unbound у b5-res із stub-zone для mini.test, що вказує на 10.55.0.54. Дозволити запити лише з 10.55.0.0/24.
  4. Навчити b5-cli користуватися цим резолвером так, щоб працювало і dig, і curl, і getent hosts.
  5. Створити CA: ключ і самопідписаний сертифікат із CA:TRUE. Випустити для сервера окремий ключ і сертифікат, підписаний цим CA, із subjectAltName www.mini.test і api.mini.test, чинний 90 днів.
  6. Налаштувати nginx у b5-web: HTTPS на 10.55.0.80:443, TLSv1.2 і TLSv1.3, сторінка будь-якого змісту.
  7. З b5-cli відкрити https://www.mini.test/ через curl --cacert.
  8. Записати рукостискання TLS 1.2 у handshake.pcap і розібрати його в tshark.

Чого робити не треба. DNSSEC, передачу зони на вторинний сервер, ACME й Let’s Encrypt, відкликання сертифікатів, проміжний CA. Сертифікат CA не треба додавати в системне сховище довіри: вся суть у тому, що curl отримує його явно.

Обмеження. Жодного доступу до інтернету й жодних записів у /etc/hosts. Імена мають розв’язуватись лише через DNS у вашій ієрархії. Процеси запускайте зі своїми конфігами й pid-файлами, а не через системні служби: nsd, unbound і nginx з пакетів за замовчуванням слухають усі адреси господаря.

Готово, коли sudo ./check.sh проходить усі перевірки, а на запитання «Що треба вміти підтвердити» нижче ви можете відповісти власними словами.

  • Прочитайте в модулі 13 розділи про авторитетні сервери, рекурсивний резолвер і TTL, а в модулі 15 розділи про ланцюжок довіри, subjectAltName і рукостискання TLS 1.2 та 1.3.
  • Потрібні права root і пакети nsd, unbound, bind9-dnsutils (для dig), nginx, openssl, tshark, tcpdump, curl. Їх ставить setup/provision.sh; вручну: sudo apt-get install nsd unbound bind9-dnsutils nginx openssl tshark tcpdump.
  • Створіть робочий каталог, наприклад ~/b5, і тримайте в ньому конфіги, каталог pki/ (там має лежати ca.crt) і handshake.pcap. Чекер запускається з цього каталогу.
  • Якщо в середовищі задано https_proxy, додавайте до curl --noproxy '*', інакше запит піде до проксі, а не в простір імен.
  1. Топологія.

    Створіть чотири простори імен і міст b5-sw, з’єднайте їх парами veth, призначте адреси. Створюйте кінці пари одразу у своїх просторах (ip link add ... netns ... type veth peer name ... netns ...): так у просторі господаря не з’являються інтерфейси зі збірними іменами.

    Перевірте: ip netns exec b5-cli ping -c1 10.55.0.54 і так само для .53 та .80.

  2. Авторитетна зона.

    Файл зони з таблиці вище ($TTL 300, SOA, NS, адреси, CNAME). Конфіг nsd: ip-address: 10.55.0.54, username: "", chroot: "", власні pidfile і zonesdir, zone: з name: "mini.test". Запускайте ip netns exec b5-auth nsd -c <конфіг>.

    Перевірте з b5-cli: dig @10.55.0.54 www.mini.test. У прапорцях відповіді має бути aa: сервер відповідає як авторитетний. Запитайте неіснуюче ім’я в зоні й подивіться на статус NXDOMAIN і на запис SOA у розділі AUTHORITY: з його останнього поля резолвер бере час, яким кешує саму відсутність імені.

  3. Резолвер.

    Конфіг unbound: interface: 10.55.0.53, access-control: 10.55.0.0/24 allow, username: "", chroot: "", власний pidfile, а для вашої зони:

    stub-zone:
    name: "mini.test"
    stub-addr: 10.55.0.54

    Крім того, зона не підписана, тож потрібен domain-insecure: "mini.test", а вбудовану обробку зони test. треба вимкнути (див. «Часті помилки»: саме тут застрягають).

    Перевірте: dig @10.55.0.53 www.mini.test повертає 10.55.0.80 з прапорцем ra і без aa. Повторіть запит через 2 секунди: TTL у відповіді має зменшитися (відповідь із кешу). Щоб побачити, що резолвер справді ходить до авторитетного сервера, запустіть у b5-auth tcpdump -ni any udp port 53 і спитайте резолвер про ім’я, якого він ще не бачив.

  4. Клієнт.

    ip netns exec підмінює /etc/resolv.conf файлом /etc/netns/<простір>/resolv.conf, якщо він існує. Створіть такий файл для b5-cli з рядком nameserver 10.55.0.53.

    Перевірте: ip netns exec b5-cli getent hosts www.mini.test.

  5. CA і сертифікат сервера.

    Порядок такий: ключ CA; самопідписаний сертифікат CA з basicConstraints=critical,CA:TRUE; окремий ключ сервера; запит на підпис (CSR); підпис запиту ключем CA з файлом розширень, у якому subjectAltName, basicConstraints=CA:FALSE і extendedKeyUsage=serverAuth. Сучасні клієнти дивляться на subjectAltName, а поле CN ігнорують (модуль 15).

    Перевірте: openssl x509 -in server.crt -noout -text показує у вашому SAN обидва імені, а openssl verify -CAfile pki/ca.crt server.crt відповідає OK.

  6. nginx.

    Конфіг із директивами daemon on, pid, error_log, блоком http і server, що слухає 10.55.0.80:443 ssl, з ssl_certificate, ssl_certificate_key і ssl_protocols TLSv1.2 TLSv1.3. Запускайте ip netns exec b5-web nginx -c <конфіг> -p <каталог>.

    Перевірте: з b5-cli curl --noproxy '*' --cacert pki/ca.crt https://www.mini.test/ повертає вашу сторінку. Тепер без --cacert: очікуйте помилку перевірки. А тепер https://10.55.0.80/ із вашим --cacert: очікуйте відмову, бо IP-адреси в SAN немає.

  7. Рукостискання в tshark.

    У b5-cli запустіть захоплення в handshake.pcap (tcpdump -w, порт 443), зробіть curl --tls-max 1.2 --cacert ..., зупиніть захоплення. Розберіть:

    Terminal window
    tshark -r handshake.pcap -Y tls.handshake -O tls
    tshark -r handshake.pcap -Y 'tls.handshake.type == 1' \
    -T fields -e tls.handshake.extensions_server_name

    Знайдіть ClientHello із server_name (SNI), перелік шифрів у пропозиції клієнта, вибір сервера в ServerHello і повідомлення Certificate, у якому видно ваш сертифікат.

    Повторіть захоплення з --tlsv1.3 і подивіться, що з повідомленням Certificate сталося (модуль 15).

  8. Те саме через openssl s_client.

    ip netns exec b5-cli openssl s_client -connect 10.55.0.80:443 -servername www.mini.test -CAfile pki/ca.crt -verify_hostname www.mini.test. Знайдіть у виводі Verify return code, ланцюжок сертифікатів, узгоджений протокол і шифр.

З каталогу, де лежать pki/ca.crt і handshake.pcap:

Terminal window
sudo /шлях/до/labs/b5-dns-tls/check.sh
# або з явними шляхами:
sudo ./check.sh ~/b5/pki/ca.crt ~/b5/handshake.pcap

Чекер нічого не будує й не зупиняє. Він спирається лише на назви просторів імен і адреси з таблиці, тож як ви назвали інтерфейси і як з’єднали хости, значення не має. Перевіряється:

  1. Адреси й зв’язність: кожен простір має свою адресу, клієнт пінгує решту.
  2. Авторитетний сервер: відповідь має прапорець aa, записи й TTL 300 збігаються з таблицею, CNAME правильний, SOA і NS є, неіснуюче ім’я дає NXDOMAIN.
  3. Резолвер: є ra і немає aa; api розкривається через CNAME; запит про щойно вигадану назву справді з’являється в трафіку b5-auth від адреси резолвера; TTL у повторній відповіді менший за перший; getent hosts у b5-cli працює.
  4. PKI: ca.crt має CA:TRUE, самопідписаний і чинний; сертифікат сервера, який віддає nginx, не самопідписаний, не є CA, містить обидва імені в SAN і чинний.
  5. HTTPS: curl --cacert дає 200 для www і api; openssl s_client підтверджує ланцюжок і ім’я; за IP-адресою й без --cacert перевірка відхиляє.
  6. Версії: TLS 1.2 і 1.3 працюють, 1.0 і 1.1 вимкнені.
  7. Знімок: у handshake.pcap є ClientHello з SNI www.mini.test, ServerHello і Certificate.

Що треба вміти підтвердити

Section titled “Що треба вміти підтвердити”
Твердження Чим доводиться
Авторитетний сервер відповідає сам прапорець aa у dig @10.55.0.54
Резолвер не авторитетний, а рекурсивний ra без aa у dig @10.55.0.53
Резолвер питає авторитетний сервер tcpdump у b5-auth
Кеш працює TTL зменшується між двома запитами
Ланцюжок довіри замкнено на вашому CA openssl verify -CAfile
Ім’я перевіряється за SAN, а не за CN відмова curl за IP-адресою
SNI передається відкритим текстом ClientHello у tshark
У TLS 1.3 сертифікат сховано порівняння знімків 1.2 і 1.3

Резолвер відповідає NXDOMAIN із прапорцем aa на власну зону. unbound типово сам «обслуговує» локальні зони з RFC 6761, серед яких test., і не питає нікого. Вимкніть це для нашого випадку: local-zone: "test." nodefault.

nsd або unbound не стартують чи не слухають. З пакета вони запускаються від власного користувача й у chroot. У власному конфігу поставте username: "" і chroot: "", а шляхи до pid-файлів, зони й журналу вкажіть у каталозі, куди вони мають право писати.

curl не знаходить ім’я, хоча dig @10.55.0.53 працює. dig із явним сервером обходить resolv.conf, а curl його читає. Подивіться на ip netns exec b5-cli cat /etc/resolv.conf.

curl іде не в простір імен, а до проксі. Якщо в середовищі є https_proxy, додайте --noproxy '*'.

Сертифікат є, а curl каже no alternative certificate subject name matches. Ім’я в адресі немає в subjectAltName. CN=www.mini.test без SAN сучасні клієнти не приймають. Перевірте openssl x509 -noout -ext subjectAltName.

unable to get local issuer certificate. Клієнт не має вашого CA, або nginx віддає не той сертифікат. Перевірте openssl s_client -showcerts і порівняйте, хто видав сертифікат.

Підписали сертифікат, а CA:TRUE не додали. Тоді CA не є центром сертифікації. І навпаки: openssl req -x509 без явних розширень видає серверу самопідписаний сертифікат, який теж має CA:TRUE. Чекер це бачить.

У tshark нема повідомлення Certificate. Ви захопили TLS 1.3, де все після ServerHello зашифровано. Захопіть з curl --tls-max 1.2.

Пакети з’являються двічі чи не з того інтерфейсу. Для tcpdump у просторі імен використовуйте -i any, а не імена інтерфейсів, яких ви не пам’ятаєте.

Підпишіть зону DNSSEC (ldns-keygen, ldns-signzone) і доведіть, що резолвер із довіреним якорем відкидає підроблену відповідь. Додайте проміжний CA і збирайте ланцюжок із двох сертифікатів. Увімкніть взаємну автентифікацію (mTLS): ssl_verify_client on у nginx і клієнтський сертифікат від вашого CA. Підніміть другий авторитетний сервер і налаштуйте передачу зони (AXFR).