Цепочка доверия (Chain of Trust)
Сертификат сам по себе ничего не доказывает — доверие к нему возникает только через цепочку подписей, которая ведет к заранее доверенному корню. Когда компоненты Netgap аутентифицируют друг друга по mTLS, TLS-стек rustls на каждой стороне выполняет именно эту проверку: строит цепочку от предъявленного сертификата до корневого CA, указанного в конфигурации (это может быть публичный CA, корпоративный УЦ заказчика или тестовый корень для экспериментов). Эта статья объясняет, как устроена цепочка, как работает алгоритм проверки и какие практические особенности есть у private PKI на тестовых стендах.
Термины (сертификат, CA, подпись) введены в обзоре методички; как физически выпустить каждый уровень цепочки — в статье Собственная PKI.
1. Три уровня цепочки
Root CA — корень доверия
- Самоподписан: его сертификат подписан его же приватным ключом, поля subject и issuer совпадают.
- Ему доверяют безусловно — не потому, что кто-то его подписал, а потому, что он заранее помещен в хранилище доверенных корней (Root Store). Публичные корни встроены в операционные системы и браузеры; в private PKI корень раздается компонентам явно.
- Приватный ключ корня — самый ценный секрет всей системы: его хранят офлайн и используют максимально редко.
Intermediate CA — посредник
Root CA подписывает промежуточный CA и делегирует ему право выпускать конечные сертификаты. Промежуточный уровень нужен по двум причинам:
- защита корня — приватный ключ Root CA можно отключить от сети и не использовать в повседневных операциях: сертификаты выпускает промежуточный CA;
- легкий отзыв — если промежуточный CA скомпрометирован, его отзывают и заменяют, не меняя корневой сертификат у всех участников системы.
Leaf — конечный сертификат
Сертификат конкретного сервера (например, gw-1.cluster.local) или mTLS-клиента. Он находится в самом низу цепочки и не имеет права подписывать другие сертификаты (в нем стоит basicConstraints=CA:FALSE).
2. Как проверяющая сторона проверяет цепочку
Представьте: клиент пришел на шлюз Netgap по mTLS и предъявил свой client.crt. Сервер должен решить — верить или нет. Проверка идет снизу вверх:
- Конечный сертификат. Сервер смотрит на
client.crt, видит поле issuer — «Intermediate CA 1» — и проверяет подпись на сертификате публичным ключом этого Intermediate CA. - Промежуточный сертификат. У Intermediate CA 1 в поле issuer указан «Root CA» — подпись на промежуточном сертификате проверяется публичным ключом корня.
- Корень — точка останова. Дойдя до самоподписанного сертификата, сервер сверяется со своим локальным хранилищем доверенных корней (Root Store). Если корень там есть — цепочка замкнулась; если нет — цепочка оборвалась.
Проверка цепочки подписей — только часть валидации. Дополнительно проверяются срок действия каждого сертификата, соответствие имени (SAN), назначение ключа (keyUsage, extendedKeyUsage) и статус отзыва — подробнее в статьях Инспекция и проверка и Отзыв сертификатов.
3. Особенность mTLS и private PKI на тестовых стендах
В обычном HTTPS цепочки длинные и публичные — например, ISRG Root X1 → Let's Encrypt R3 → ваш сайт, а браузер доверяет сотням публичных корней сразу.
Netgap не ограничивает выбор удостоверяющего центра: набор доверенных корней определяется конфигурацией — заказчик может использовать сертификаты публичного CA или собственного корпоративного УЦ. Но для тестирования и экспериментов удобно развернуть собственную (private) PKI, и у нее есть свои особенности:
- цепочка может быть короткой: свой Root CA → сертификат сервиса, без промежуточного уровня (именно такой минимальный вариант разобран в практикуме по PKI);
- серверу тестового стенда не нужно доверять всему миру: в конфигурации rustls в качестве хранилища доверия можно указать ровно один файл —
ca.crtтестового корня. Тогда клиент с сертификатом от любого другого CA (пусть даже валидным) будет отвергнут сразу, потому что его цепочка ведет не к этому корню — удобно для изолированных экспериментов.
Общий принцип один и тот же в любом окружении: принимаются только сертификаты, чья цепочка ведет к одному из корней, загруженных в хранилище доверия, — какие именно корни там лежат, решает владелец инсталляции. Как это настраивается в коде — в статье mTLS на rustls; как из проверенного сертификата извлекается идентичность клиента — в статье Идентичность клиента.
4. Certificate bundling (fullchain)
Проверяющая сторона хранит у себя только корень. Все промежуточные сертификаты обязана прислать предъявляющая сторона вместе со своим leaf — иначе цепочку не из чего построить.
Если сервер настроен отдавать только свой server.crt без промежуточного, клиент не сможет достроить цепочку до корня и завершит соединение ошибкой. Поэтому leaf и промежуточные сертификаты склеивают в один файл-бандл:
# Порядок важен: сначала leaf, затем промежуточные (снизу вверх)
cat server.crt intermediate.crt > fullchain.crt
В настройках серверов указывается именно объединенный файл — отсюда привычное имя fullchain.pem у Let's Encrypt. Корень в бандл не включают: он и так должен быть у проверяющей стороны, а присланному корню доверять все равно нельзя.
В минимальной тестовой private PKI (Root CA → leaf, без промежуточных) бандл вырождается в один server.crt. Но если в цепочке появляется промежуточный CA (что типично для публичных и корпоративных УЦ) — не забудьте перейти на fullchain, иначе получите труднодиагностируемые обрывы handshake.
Следующий шаг — выпуск всех уровней цепочки через OpenSSL.