Автоматизация выпуска и ротация сертификатов
Компоненты Netgap аутентифицируют друг друга по mTLS, а межшлюзовой трафик шифруется TLS 1.3. Ручной выпуск сертификатов через OpenSSL (см. Выпуск сертификатов через OpenSSL) отлично подходит для обучения, тестирования и экспериментальных стендов, но не масштабируется: как только сервисов становится десятки, а сертификаты — короткоживущими (TTL 1–24 часа, см. Отзыв сертификатов), перевыпуск обязан происходить автоматически, без участия человека. Эта статья — обзор инструментов автоматизации: HashiCorp Vault PKI, cert-manager для Kubernetes и Service Mesh, а также разбор «живого» mTLS-соединения двух сервисов с сертификатами от Vault.
1. HashiCorp Vault: динамический PKI
Vault — популярный инструмент управления секретами со встроенным движком PKI, который превращает Vault в полноценный автоматический удостоверяющий центр (CA):
- при настройке в Vault загружается (или генерируется) корневой ключ и сертификат;
- приложение, скрипт или CI/CD-пайплайн делает HTTP-запрос
POST /v1/pki/issue/my-role, передавая имя нужного клиента или сервера; - Vault на лету генерирует приватный ключ и сертификат (например, с TTL 24 часа) и возвращает их в JSON-ответе вместе с корневым
ca.crt; - приложение подхватывает файлы; задолго до истечения TTL процесс повторяется автоматически.
Vault нужен только для выпуска сертификатов. Сама проверка подлинности при соединении происходит по классическим правилам асимметричной криптографии между двумя сервисами — в момент handshake Vault не участвует. Это разгружает сеть и не добавляет задержек соединениям.
Главный плюс: сертификаты короткоживущие. Если ключ утек, через несколько часов он сам «превратится в тыкву», и проверки CRL/OCSP часто становятся просто не нужны — подробнее в разделе 6.
2. Как сервисам доверять корню Vault: варианты Truststore
Чтобы сервис принимал сертификаты, выпущенные Vault, его корневой ca.crt нужно добавить в хранилище доверенных сертификатов (Truststore) — на уровне ОС, контейнера, кода или прокси. Теория того, зачем это нужно, — в статье Цепочка доверия.
Вариант 1: на уровне Linux-сервера.
# Ubuntu / Debian
sudo cp ca.crt /usr/local/share/ca-certificates/vault-ca.crt
sudo update-ca-certificates
# CentOS / RHEL / Rocky Linux
sudo cp ca.crt /etc/pki/ca-trust/source/anchors/vault-ca.crt
sudo update-ca-trust extract
Вариант 2: внутри Docker-контейнера.
FROM alpine:latest
COPY certs/ca.crt /usr/local/share/ca-certificates/vault-ca.crt
RUN apk update && apk add --no-cache ca-certificates && update-ca-certificates
# Далее — запуск вашего приложения
Вариант 3: на уровне кода приложения (когда нет прав на изменение ОС):
- Go — явно создать пул сертификатов
x509.NewCertPool()из файла и передать его вtls.Config{RootCAs: certPool}; - Node.js — указать путь через переменную окружения:
export NODE_EXTRA_CA_CERTS="/path/to/vault-ca.crt"перед запускомnode app.js; - Python (requests) — передать путь к корню в параметре verify:
requests.get('https://service-b.internal', verify='/path/to/vault-ca.crt'); - Java — импортировать корень в TrustStore утилитой keytool:
keytool -importcert -trustcacerts -file ca.crt -alias vaultCA -keystore cacerts.jks -storepass changeitи запустить приложение с флагом-Djavax.net.ssl.trustStore=cacerts.jks; - Rust (rustls) — добавить
ca.crtвRootCertStore, как описано в статье mTLS на rustls.
Вариант 4: на уровне Nginx — если mTLS терминирует прокси перед сервисом:
server {
listen 443 ssl;
server_name service-a.internal;
# Собственные сертификаты этого сервиса (тоже выпущены Vault)
ssl_certificate /etc/nginx/certs/service-a.crt;
ssl_certificate_key /etc/nginx/certs/service-a.key;
# Корень Vault — для проверки клиентов, приходящих к сервису
ssl_client_certificate /etc/nginx/certs/vault-ca.crt;
ssl_verify_client on; # включаем строгий mTLS
}
3. Живое mTLS-соединение двух сервисов с сертификатами от Vault
Разберем, как Сервер А (клиент) и Сервер Б (сервер) проверяют друг друга, когда оба получили сертификаты от Vault, а ca.crt уже лежит в их Truststore:
- Сервер А проверяет Сервера Б (стандартный TLS). Сервер Б присылает свой сертификат. Сервер А проверяет его цифровую подпись открытым ключом из локального
ca.crtи математически убеждается: «этот сертификат действительно выпущен моим доверенным Vault CA, данные внутри не подменены». Дополнительно проверяются срок действия и совпадение Subject/SAN с именем Сервера Б. - Сервер Б проверяет Сервера А (собственно mTLS). Сервер Б отправляет
CertificateRequest; Сервер А присылает свой клиентский сертификат, и Сервер Б точно так же проверяет его своимca.crt. Если подпись сходится — Сервер А «свой». Дальше идентичность клиента (CN, SPIFFE ID) можно использовать для авторизации — см. Идентичность клиента. - Защита от кражи сертификата (
CertificateVerify). Просто предъявить чужой сертификат недостаточно — он передается по сети и его можно перехватить. Сервер А хеширует все предыдущие сообщения сессии, подписывает хеш своим приватным ключом и отправляетCertificateVerify. Сервер Б проверяет подпись открытым ключом из сертификата А: если математика сошлась, перед ним законный владелец ключа, а не злоумышленник со скопированным.crt-файлом.
4. Cert-manager для Kubernetes
Если инфраструктура работает в Kubernetes, стандарт де-факто — оператор cert-manager:
- cert-manager разворачивается внутри кластера;
- создается объект
Issuer— кто подписывает сертификаты (Vault, Let's Encrypt или собственный локальный CA); - создается манифест
Certificate: «нужен mTLS-сертификат дляapi.internal, срок 30 дней, обновлять за 5 дней до окончания»; - cert-manager сам генерирует ключи, обращается к Issuer, забирает сертификат и кладет его в стандартный Kubernetes
Secret; - поды или Ingress-контроллер монтируют секрет; при обновлении сертификата приложения подтягивают новые данные автоматически (или после рестарта).
5. Service Mesh (Istio / Linkerd): mTLS «из коробки»
Когда mTLS-шифрованием нужно связать сотни микросервисов, управлять сертификатами каждого даже через cert-manager тяжело. Service Mesh снимает задачу с разработчика полностью:
- код приложения пишет обычный HTTP и вообще «не знает» о сертификатах;
- рядом с каждым контейнером mesh автоматически поднимает sidecar-прокси (в Istio — Envoy);
- компонент
istiodработает как локальный CA и выписывает каждому прокси короткоживущие сертификаты (обычно 12–24 часа) с идентичностью в формате SPIFFE (см. Идентичность клиента); - весь трафик между сервисами идет через прокси: они сами выполняют mTLS-handshake, проверяют сертификаты и шифруют канал;
- ротация ключей происходит в памяти прокси, незаметно для приложения.
6. Стратегия отзыва при автоматизации
Раз выпуск автоматический, сертификаты можно делать короткоживущими — и это меняет подход к отзыву:
- короткий TTL (рекомендуется для Vault): сертификаты живут 1–12 часов и обновляются в фоне. При компрометации сервиса администратор просто блокирует ему доступ к Vault — старый сертификат истечет сам через несколько часов. CRL/OCSP в таком сценарии часто вообще отключают;
- проверка по CRL: если сертификаты долгоживущие, проверяющая сторона обязана при каждом соединении сверяться со списком отзыва, который хостит Vault.
Сравнение механизмов отзыва и их ограничения — в статье Отзыв сертификатов.
Короткий TTL означает, что сервис должен уметь подменять сертификат без перезапуска. В Rust это делается атомарной заменой ServerConfig в памяти (например, через ArcSwap): новые соединения получают свежую конфигурацию, уже открытые спокойно дорабатывают на старой. Рабочий пример — в статье mTLS на rustls.
7. Сравнение подходов
| Критерий | OpenSSL вручную | Vault PKI | cert-manager | Service Mesh |
|---|---|---|---|---|
| Выпуск | Руками, по командам из private-pki | API-запрос, автоматически | Декларативно, оператором | Полностью прозрачно |
| Ротация | Ручная | Автоматическая (короткий TTL) | Автоматическая (по манифесту) | Автоматическая, в памяти прокси |
| Типичный TTL | Месяцы/годы | Часы/сутки | Недели/месяцы | 12–24 часа |
| Участие разработчика | Полное | Интеграция с API/агентом | Написание манифестов | Нулевое |
| Область применения | Обучение, стенды, корень PKI | Виртуалки, bare metal, гибрид | Kubernetes | Kubernetes, сотни микросервисов |
| Отзыв | CRL/OCSP вручную | Короткий TTL или CRL | Через Issuer | Короткий TTL |
Общие правила независимо от выбранного инструмента: корень CA должен доставляться во все Truststore как часть процесса деплоя; TTL сертификатов выбирается осознанно, а стратегия отзыва соответствует TTL (Отзыв сертификатов); сервисы обновляют сертификаты в фоне задолго до истечения срока без перезапуска (mTLS на rustls); доступ к API выпуска (роли Vault, Issuer) ограничивается так, чтобы сервис мог запросить сертификат только со своим именем.