B5. Власні DNS і TLS
У модулі 13 ланцюжок «клієнт → резолвер → авторитетний сервер» описано словами, а в модулі 15 словами ж описано, як клієнт вирішує, чи вірити сертифікату. Тут ви збираєте обидва механізми власноруч, на одній машині й без інтернету, тому нічого не приховано від вас ні кешем провайдера, ні браузерним сховищем довіри.
Після цієї роботи ви зможете:
- описати зону в файлі й підняти для неї авторитетний сервер (
nsd); - налаштувати рекурсивний резолвер (
unbound) так, щоб він знав, де шукати вашу зону, і показати, що він справді питає авторитетний сервер, а потім віддає відповідь із кешу із зменшуваним TTL; - випустити власний центр сертифікації й сертифікат сервера з правильним
subjectAltNameза допомогоюopenssl; - налаштувати
nginxна HTTPS лише з TLS 1.2 і 1.3; - довести, що клієнт вірить вашому CA і більше нікому, і що перевірка імені справді відбувається;
- прочитати рукостискання TLS 1.2 у
tsharkі знайти в ньому SNI, вибір шифру й сертифікат.
Так виглядає внутрішня інфраструктура будь-якої компанії: власний домен для внутрішніх служб, свій CA для сертифікатів, яким не потрібен публічний центр. Коли після цього «сайт не відкривається з помилкою сертифіката», ви знаєте, на якому з п’яти місць шукати причину.
Завдання
Section titled “Завдання”Результат роботи: чотири хости в просторах імен (три служби й клієнт) і два файли, що їх перевіряє чекер: сертифікат вашого 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 |
за вашим вибором | — |
Що зробити:
- Зібрати топологію з таблиці й переконатися, що
b5-cliпінгує всіх трьох. - Написати файл зони, підняти
nsdуb5-auth(слухає лише10.55.0.54). - Підняти
unboundуb5-resізstub-zoneдляmini.test, що вказує на10.55.0.54. Дозволити запити лише з10.55.0.0/24. - Навчити
b5-cliкористуватися цим резолвером так, щоб працювало іdig, іcurl, іgetent hosts. - Створити CA: ключ і самопідписаний сертифікат із
CA:TRUE. Випустити для сервера окремий ключ і сертифікат, підписаний цим CA, ізsubjectAltNamewww.mini.testіapi.mini.test, чинний 90 днів. - Налаштувати
nginxуb5-web: HTTPS на10.55.0.80:443,TLSv1.2іTLSv1.3, сторінка будь-якого змісту. - З
b5-cliвідкритиhttps://www.mini.test/черезcurl --cacert. - Записати рукостискання TLS 1.2 у
handshake.pcapі розібрати його вtshark.
Чого робити не треба. DNSSEC, передачу зони на вторинний сервер,
ACME й Let’s Encrypt, відкликання сертифікатів, проміжний CA.
Сертифікат CA не треба додавати в системне сховище довіри: вся суть
у тому, що curl отримує його явно.
Обмеження. Жодного доступу до інтернету й жодних записів у /etc/hosts.
Імена мають розв’язуватись лише через DNS у вашій ієрархії. Процеси
запускайте зі своїми конфігами й pid-файлами, а не через системні
служби: nsd, unbound і nginx з пакетів за замовчуванням слухають
усі адреси господаря.
Готово, коли sudo ./check.sh проходить усі перевірки,
а на запитання «Що треба вміти підтвердити» нижче ви можете відповісти
власними словами.
Перед початком
Section titled “Перед початком”- Прочитайте в модулі 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 '*', інакше запит піде до проксі, а не в простір імен.
-
Топологія.
Створіть чотири простори імен і міст
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. -
Авторитетна зона.
Файл зони з таблиці вище (
$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: з його останнього поля резолвер бере час, яким кешує саму відсутність імені. -
Резолвер.
Конфіг
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-authtcpdump -ni any udp port 53і спитайте резолвер про ім’я, якого він ще не бачив. -
Клієнт.
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. -
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. -
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-clicurl --noproxy '*' --cacert pki/ca.crt https://www.mini.test/повертає вашу сторінку. Тепер без--cacert: очікуйте помилку перевірки. А теперhttps://10.55.0.80/із вашим--cacert: очікуйте відмову, бо IP-адреси вSANнемає. -
Рукостискання в tshark.
У
b5-cliзапустіть захоплення вhandshake.pcap(tcpdump -w, порт 443), зробітьcurl --tls-max 1.2 --cacert ..., зупиніть захоплення. Розберіть:Terminal window tshark -r handshake.pcap -Y tls.handshake -O tlstshark -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). -
Те саме через
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, ланцюжок сертифікатів, узгоджений протокол і шифр.
Перевірка
Section titled “Перевірка”З каталогу, де лежать pki/ca.crt і handshake.pcap:
sudo /шлях/до/labs/b5-dns-tls/check.sh# або з явними шляхами:sudo ./check.sh ~/b5/pki/ca.crt ~/b5/handshake.pcapЧекер нічого не будує й не зупиняє. Він спирається лише на назви просторів імен і адреси з таблиці, тож як ви назвали інтерфейси і як з’єднали хости, значення не має. Перевіряється:
- Адреси й зв’язність: кожен простір має свою адресу, клієнт пінгує решту.
- Авторитетний сервер: відповідь має прапорець
aa, записи й TTL 300 збігаються з таблицею,CNAMEправильний,SOAіNSє, неіснуюче ім’я даєNXDOMAIN. - Резолвер: є
raі немаєaa;apiрозкривається черезCNAME; запит про щойно вигадану назву справді з’являється в трафікуb5-authвід адреси резолвера; TTL у повторній відповіді менший за перший;getent hostsуb5-cliпрацює. - PKI:
ca.crtмаєCA:TRUE, самопідписаний і чинний; сертифікат сервера, який віддаєnginx, не самопідписаний, не є CA, містить обидва імені вSANі чинний. - HTTPS:
curl --cacertдає 200 дляwwwіapi;openssl s_clientпідтверджує ланцюжок і ім’я; за IP-адресою й без--cacertперевірка відхиляє. - Версії: TLS 1.2 і 1.3 працюють, 1.0 і 1.1 вимкнені.
- Знімок: у
handshake.pcapєClientHelloз SNIwww.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 |
Часті помилки
Section titled “Часті помилки”Резолвер відповідає 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, а не імена інтерфейсів,
яких ви не пам’ятаєте.
Далі, якщо цікаво
Section titled “Далі, якщо цікаво”Підпишіть зону DNSSEC (ldns-keygen, ldns-signzone) і доведіть, що
резолвер із довіреним якорем відкидає підроблену відповідь. Додайте
проміжний CA і збирайте ланцюжок із двох сертифікатів. Увімкніть
взаємну автентифікацію (mTLS): ssl_verify_client on у nginx і клієнтський
сертифікат від вашого CA. Підніміть другий авторитетний сервер і
налаштуйте передачу зони (AXFR).