Cert-Manager на Kubernetes: Полное руководство по настройке автоматизированного управления TLS-сертификатами
Cert-Manager — это контроллер Kubernetes с открытым исходным кодом, который полностью автоматизирует жизненный цикл TLS-сертификатов — от первоначальной выдачи через валидацию до обновления — путём прямой интеграции с центрами сертификации, такими как Let’s Encrypt, HashiCorp Vault и частными PKI-системами. Он устраняет необходимость в ручных процессах работы с сертификатами, рассматривая их как нативные ресурсы Kubernetes, управляемые декларативно через Custom Resource Definitions (CRDs).
Для любого производственного кластера Kubernetes просроченные или неправильно настроенные TLS-сертификаты являются одной из наиболее распространённых причин незапланированных простоев. Cert-Manager решает эту проблему, непрерывно согласовывая состояние сертификатов, автоматически обновляя учётные данные до истечения срока действия и сохраняя полученный ключевой материал в Kubernetes Secrets, которые контроллеры Ingress и рабочие нагрузки могут использовать немедленно.
Почему Cert-Manager является стандартом для автоматизации TLS в Kubernetes
До того как Cert-Manager стал де-факто решением, команды либо создавали скрипты для обновления certbot на отдельных узлах, вручную ротировали сертификаты между пространствами имён, либо полагались на специфические для облачных провайдеров интеграции, которые создавали привязку к поставщику. Cert-Manager объединяет все эти подходы под единой, нативной для Kubernetes плоскостью управления.
Ключевые преимущества перед специализированными подходами:
- Декларативное управление: намерение относительно сертификата выражается в виде YAML-манифеста, версионируемого вместе с кодом приложения.
- Автоматическое согласование: цикл контроллера обнаруживает расхождение между желаемым и фактическим состоянием сертификата и исправляет его без участия человека.
- Поддержка нескольких издателей: один кластер может одновременно использовать Let’s Encrypt для публичных сервисов, внутренний CA для mTLS сервисной сети и HashiCorp Vault для рабочих нагрузок, чувствительных к секретам.
- Журнал аудита: каждый объект
CertificateRequestсохраняется в Kubernetes API, предоставляя вам полную историю выдачи.
Запуск Kubernetes на платформе VPS Хостинга с хранилищем на основе NVMe и полным root-доступом даёт вам контроль, необходимый для настройки пользовательских DNS-резолверов, управления правилами брандмауэра для ACME HTTP-01 запросов и установки CRDs на уровне кластера без ограничений — всё это является обязательными условиями для производственного развёртывания Cert-Manager.
Основная архитектура: как Cert-Manager работает изнутри
Понимание внутренней архитектуры Cert-Manager предотвращает неправильные конфигурации и помогает быстро отлаживать сбои при выдаче.
Конечный автомат жизненного цикла сертификата
Cert-Manager управляет сертификатами через детерминированный конечный автомат. Каждый ресурс Certificate проходит через следующие состояния:
- Pending (Ожидание) — объект
Certificateсуществует, но ни один действительныйCertificateRequestне был выполнен. - Issuing (Выдача) —
CertificateRequestбыл создан и отправлен настроенному издателю. - Ready (Готов) — действительный, не истёкший сертификат хранится в указанном Kubernetes
Secret. - Renewal Pending (Ожидание обновления) — сертификат находится в пределах окна
renewBefore(по умолчанию: за 30 дней до истечения срока), и новыйCertificateRequestобрабатывается.
Контроллер отслеживает все объекты Certificate в масштабе кластера и непрерывно согласовывает их состояние. Если Secret удалён вручную, Cert-Manager обнаруживает отсутствующий ресурс и немедленно инициирует повторную выдачу — критически важное самовосстанавливающееся поведение, предотвращающее случайные сбои.
Основные компоненты CRD
| Ресурс | Область | Назначение |
|---|---|---|
| — | — | — |
| `Issuer` | Пространство имён | Определяет конфигурацию CA для одного пространства имён |
| `ClusterIssuer` | Весь кластер | Определяет конфигурацию CA, доступную для всех пространств имён |
| `Certificate` | Пространство имён | Объявляет желаемый TLS-сертификат и его свойства |
| `CertificateRequest` | Пространство имён | Отслеживает единственный, одномоментный запрос на подпись сертификата |
| `Order` | Пространство имён | Представляет ACME-заказ у CA (например, Let’s Encrypt) |
| `Challenge` | Пространство имён | Отслеживает единственный ACME-запрос (HTTP-01 или DNS-01) |
Ресурсы Order и Challenge создаются автоматически издателем ACME — вы редко взаимодействуете с ними напрямую, но их проверка является основным путём отладки при зависании выдачи.
Хранение сертификатов и формат Secret
После выдачи Cert-Manager записывает три ключа данных в целевой Kubernetes Secret:
tls.crt— полная цепочка сертификатов (конечный + промежуточные), в кодировке PEM.tls.key— закрытый ключ, в кодировке PEM.ca.crt— сертификат издающего CA (заполняется для внутренних CA; может быть пустым для ACME-издателей).
Контроллеры Ingress, сервисные сети и поды приложений монтируют этот Secret напрямую. Формат совместим с NGINX, Traefik, Istio, Linkerd и большинством других нативных для Kubernetes потребителей TLS.
Поддерживаемые издатели и когда использовать каждый из них
ACME (Let’s Encrypt и альтернативы)
Протокол ACME является наиболее распространённым путём выдачи. Cert-Manager реализует полный ACME-клиент RFC 8555, поддерживая как тестовые, так и производственные конечные точки.
Запрос HTTP-01: Cert-Manager временно обслуживает токен по адресу http://<domain>/.well-known/acme-challenge/<token>. Для этого требуется, чтобы домен разрешался в публично доступный IP-адрес на порту 80. Работает для сертификатов с одним доменом и SAN, но не может выдавать wildcard-сертификаты.
Запрос DNS-01: Cert-Manager создаёт TXT-запись _acme-challenge.<domain> через API DNS-провайдера. Работает за брандмауэрами, поддерживает wildcard-сертификаты (*.example.com) и требуется для любого кластера, не имеющего прямого доступа к интернету. Поддерживаемые DNS-провайдеры включают Cloudflare, Route53, Google Cloud DNS, Azure DNS и многие другие через webhook-решатели.
HashiCorp Vault
Издатель Vault интегрируется с движком секретов PKI в Vault. Это предпочтительный выбор для:
- Внутреннего mTLS микросервисов, где сертификаты должны быть краткосрочными (часы, а не месяцы).
- Сред со строгими требованиями к хранению ключей, где закрытые ключи никогда не должны покидать Vault.
- Автоматической ротации сертификатов, привязанной к системе обновления аренды Vault.
Самоподписанные и CA-издатели
Издатель SelfSigned генерирует сертификаты, подписанные собственным закрытым ключом сертификата — полезно для начальной загрузки корневого CA внутри кластера. Издатель CA использует Kubernetes Secret, содержащий пару ключей CA, для подписи сертификатов, что делает его подходящим для внутренних сред разработки и PKI сервисной сети.
Venafi
Интеграция с Venafi ориентирована на корпоративные среды с централизованным применением политик сертификатов, аудитом соответствия требованиям и интеграцией с аппаратными модулями безопасности (HSM).
Cert-Manager в сравнении с альтернативными подходами к автоматизации TLS
| Подход | Поддержка Wildcard | Нативность для Kubernetes | Несколько CA | Автообновление | Сложность |
|---|---|---|---|---|---|
| — | — | — | — | — | — |
| Cert-Manager | Да (DNS-01) | Да (CRDs) | Да | Да | Средняя |
| Ручной Certbot | Нет (только HTTP-01) | Нет | Ограниченно | По скрипту | Низкая–Средняя |
| Завершение TLS на облачном балансировщике нагрузки | Зависит от провайдера | Нет | Нет | Да | Низкая |
| Istio / CA сервисной сети | Только внутренние | Да | Нет | Да | Высокая |
| HashiCorp Vault (автономный) | Да | Нет | Да | Вручную | Высокая |
Для команд, запускающих Kubernetes на Выделенном сервере или VPS, Cert-Manager — единственный подход, который одновременно является нативным для Kubernetes, поддерживает все основные CA и не требует никакого постоянного ручного вмешательства.
Установка Cert-Manager: готовая к производству настройка
Предварительные требования
- Kubernetes 1.22+ (рекомендуется 1.26+ для полной стабильности CRD)
kubectlнастроен с привилегиями cluster-admin- Установлен Helm 3.x
- Зарегистрированный домен с доступом к управлению DNS (для DNS-01) или публично доступный IP-адрес ingress (для HTTP-01)
Если вы управляете собственным доменом, настоятельно рекомендуется Регистрация домена через провайдера, предоставляющего API — это позволяет полностью автоматизировать решение DNS-01 запросов без ручного вмешательства.
Шаг 1: Установка CRDs и контроллера Cert-Manager
Рекомендуемый метод производственной установки использует Helm с CRDs, управляемыми отдельно, чтобы избежать конфликтов при обновлении Helm:
# Add the Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io
helm repo update
# Install Cert-Manager with CRDs included
helm install cert-manager jetstack/cert-manager
--namespace cert-manager
--create-namespace
--version v1.14.5
--set installCRDs=true
--set global.leaderElection.namespace=cert-managerУбедитесь, что все три основных пода запущены, прежде чем продолжить:
kubectl get pods --namespace cert-managerОжидаемый вывод:
NAME READY STATUS RESTARTS AGE
cert-manager-xxxxxxxxx-xxxxx 1/1 Running 0 60s
cert-manager-cainjector-xxxxxxxxx-xxxxx 1/1 Running 0 60s
cert-manager-webhook-xxxxxxxxx-xxxxx 1/1 Running 0 60scainjector внедряет данные пакета CA в конфигурации webhook. webhook проверяет и изменяет объекты CRD Cert-Manager — если он не запущен, все операции kubectl apply с ресурсами Cert-Manager завершатся ошибкой.
Шаг 2: Настройка ClusterIssuer для Let’s Encrypt
Всегда начинайте с тестовой среды Let’s Encrypt, чтобы избежать превышения производственных ограничений на количество запросов (50 сертификатов на зарегистрированный домен в неделю):
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: ops@example.com
privateKeySecretRef:
name: letsencrypt-staging-account-key
solvers:
- http01:
ingress:
class: nginxПосле успешной выдачи тестовых сертификатов создайте производственный издатель:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: ops@example.com
privateKeySecretRef:
name: letsencrypt-prod-account-key
solvers:
- http01:
ingress:
class: nginxПримените оба манифеста:
kubectl apply -f clusterissuer-staging.yaml
kubectl apply -f clusterissuer-prod.yamlПроверьте готовность издателя:
kubectl describe clusterissuer letsencrypt-prodПоле Status.Conditions должно отображать Ready: True. Если отображается False, регистрация учётной записи ACME завершилась неудачей — проверьте адрес электронной почты и сетевое подключение из пода cert-manager.
Шаг 3: Явный запрос сертификата
Вы можете запрашивать сертификаты либо путём непосредственного создания ресурса Certificate, либо путём аннотирования ресурса Ingress. Явный подход с Certificate даёт вам больше контроля:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com-tls
namespace: production
spec:
secretName: example-com-tls-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
commonName: example.com
dnsNames:
- example.com
- www.example.com
duration: 2160h # 90 days (Let's Encrypt default)
renewBefore: 720h # Renew 30 days before expiryПримените и отслеживайте выдачу:
kubectl apply -f certificate.yaml
kubectl describe certificate example-com-tls -n productionОтслеживайте объекты CertificateRequest и Order для получения подробного статуса:
kubectl get certificaterequest -n production
kubectl describe order -n productionШаг 4: Метод аннотации Ingress (упрощённый)
Для команд, использующих NGINX Ingress Controller, Cert-Manager может быть запущен автоматически через аннотацию — отдельный манифест Certificate не требуется:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: production
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- example.com
- www.example.com
secretName: example-com-tls-secret
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: example-service
port:
number: 80Cert-Manager обнаруживает аннотацию и автоматически создаёт соответствующий ресурс Certificate. Это наиболее распространённый шаблон в рабочих процессах GitOps.
Расширенные шаблоны конфигурации
Wildcard-сертификаты с DNS-01 (пример Cloudflare)
Wildcard-сертификаты требуют валидации DNS-01. Сначала создайте Secret, содержащий ваш API-токен Cloudflare:
kubectl create secret generic cloudflare-api-token
--from-literal=api-token=<YOUR_CLOUDFLARE_API_TOKEN>
--namespace cert-managerНастройте ClusterIssuer с решателем DNS-01:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod-dns
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: ops@example.com
privateKeySecretRef:
name: letsencrypt-prod-dns-account-key
solvers:
- dns01:
cloudflare:
apiTokenSecretRef:
name: cloudflare-api-token
key: api-tokenЗапросите wildcard-сертификат:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wildcard-example-com
namespace: production
spec:
secretName: wildcard-example-com-tls
issuerRef:
name: letsencrypt-prod-dns
kind: ClusterIssuer
dnsNames:
- "*.example.com"
- example.comКритическая ошибка: Secret, содержащий учётные данные DNS-провайдера, должен находиться в пространстве имён cert-manager при ссылке из ClusterIssuer. Если вы разместите его в другом пространстве имён, контроллер не сможет его прочитать, и выдача молча завершится неудачей. Проверьте журналы контроллера cert-manager с помощью kubectl logs -n cert-manager deploy/cert-manager, если запросы зависают.
Внутренняя PKI с CA-издателем
Для mTLS между сервисами внутри кластера издатель CA, основанный на самоподписанном корневом CA, более подходит, чем ACME:
# Step 1: Create a self-signed root CA certificate
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned-root
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: internal-root-ca
namespace: cert-manager
spec:
isCA: true
commonName: internal-root-ca
secretName: internal-root-ca-secret
issuerRef:
name: selfsigned-root
kind: ClusterIssuer
---
# Step 2: Create a CA issuer backed by the root certificate
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: internal-ca-issuer
spec:
ca:
secretName: internal-root-ca-secretТеперь сервисы могут запрашивать краткосрочные сертификаты у internal-ca-issuer для mTLS без какой-либо зависимости от внешнего CA.
Настройка renewBefore для высокозащищённых сред
Значение renewBefore по умолчанию в 30 дней подходит для 90-дневных сертификатов Let’s Encrypt. Для краткосрочных внутренних сертификатов (например, со сроком действия 24 часа) установите renewBefore равным доле от общей продолжительности:
spec:
duration: 24h
renewBefore: 8hCert-Manager начнёт обновление за 8 часов до истечения срока, предоставляя контроллеру три окна обновления в течение 24-часового срока действия сертификата — критически важный запас безопасности на случай, если кластер испытывает временную недоступность API-сервера.
Отладка распространённых сбоев Cert-Manager
Сертификат завис в состоянии «Issuing»
# Check the Certificate status
kubectl describe certificate <name> -n <namespace>
# Check the associated CertificateRequest
kubectl describe certificaterequest -n <namespace>
# Check the ACME Order
kubectl describe order -n <namespace>
# Check the Challenge
kubectl describe challenge -n <namespace>
# Check controller logs
kubectl logs -n cert-manager deploy/cert-manager --tail=100Распространённые первопричины:
- Сбой HTTP-01: контроллер Ingress неправильно маршрутизирует трафик
/.well-known/acme-challenge/. Убедитесь, что объектIngressзапроса был создан и что порт 80 доступен из интернета. Брандмауэры на хосте должны разрешать входящий TCP/80. - Сбой DNS-01: API-токен DNS-провайдера имеет недостаточные разрешения, или распространение DNS ещё не завершено. Серверы валидации Let’s Encrypt могут запрашивать другие резолверы, чем ваш локальный DNS — задержки распространения в 60–120 секунд являются нормой.
- Превышен лимит запросов: Let’s Encrypt применяет ограничение в 5 неудачных попыток валидации на домен в час. После достижения этого лимита необходимо подождать перед повторной попыткой. Всегда сначала тестируйте с тестовой конечной точкой.
- Webhook не готов: если под webhook cert-manager не запущен, все операции с CRD завершатся ошибкой отказа в соединении. Убедитесь, что служба webhook имеет действительную конечную точку.
Проверка развёрнутого сертификата
# Check the Secret contents
kubectl get secret example-com-tls-secret -n production -o jsonpath='{.data.tls.crt}' | base64 -d | openssl x509 -noout -text
# Check expiry date specifically
kubectl get secret example-com-tls-secret -n production -o jsonpath='{.data.tls.crt}' | base64 -d | openssl x509 -noout -enddateКонтрольный список для усиления защиты в производственной среде
Развёртывание Cert-Manager в производственной среде требует большего, чем стандартная установка через Helm. Примените эти меры по усилению защиты перед запуском в эксплуатацию:
- Ограничения ресурсов: установите
requestsиlimitsCPU и памяти для всех трёх подов Cert-Manager, чтобы предотвратить конкуренцию за ресурсы на общих узлах. - Аудит RBAC: Cert-Manager требует широких разрешений RBAC. Проверьте установленные объекты
ClusterRoleи ограничьте их до минимально необходимого для ваших типов издателей. - Отдельное пространство имён: всегда развёртывайте Cert-Manager в собственном пространстве имён
cert-manager, изолированном от рабочих нагрузок приложений. - Мониторинг: откройте конечную точку метрик Prometheus Cert-Manager (
--metrics-listen-address) и настройте оповещения наcertmanager_certificate_expiration_timestamp_seconds, чтобы выявлять сбои обновления до того, как они повлияют на сервисы. - Резервное копирование состояния CRD: включите объекты
Certificate,ClusterIssuerиIssuerв стратегию резервного копирования кластера. Потеря этих манифестов после события аварийного восстановления означает необходимость вручную воссоздавать все конфигурации сертификатов. - Тестовая валидация: никогда не выдавайте первый сертификат через производственную конечную точку ACME. Нарушения ограничений на количество запросов могут заблокировать ваш домен на срок до недели.
Если вы управляете несколькими кластерами Kubernetes — например, разделяя тестовые и производственные рабочие нагрузки — Панели управления VPS могут упростить управление жизненным циклом кластеров и предоставить вам единый интерфейс для подготовки базовой инфраструктуры, на которой работает каждый кластер.
Для рабочих нагрузок, требующих GPU-ускоренного инференса или обслуживания ML за TLS-терминированными конечными точками, те же шаблоны Cert-Manager применяются на инфраструктуре GPU Хостинга, где автоматизированное управление сертификатами не менее критично для защиты конечных точек API моделей.
Практическая матрица решений: выбор правильного издателя
| Сценарий | Рекомендуемый издатель | Тип запроса | Wildcard |
|---|---|---|---|
| — | — | — | — |
| Публичное веб-приложение, один домен | `letsencrypt-prod` | HTTP-01 | Нет |
| Публичное веб-приложение, несколько поддоменов | `letsencrypt-prod` | DNS-01 | Да |
| Изолированный / частный кластер | `CA` или `Vault` | Н/Д (внутренний) | Да |
| Корпоративная среда с требованиями соответствия | `Venafi` | Н/Д | Да |
| mTLS сервисной сети (краткосрочные сертификаты) | `Vault` или `CA` | Н/Д (внутренний) | Да |
| Разработка / локальный кластер | `SelfSigned` или `CA` | Н/Д | Да |
Ключевые выводы
- Устанавливайте Cert-Manager с помощью Helm с
installCRDs=trueи всегда выполняйте валидацию с тестовой конечной точкой ACME перед переключением на производственную. - Используйте
ClusterIssuerдля кластеров с несколькими пространствами имён; используйтеIssuerс областью видимости пространства имён только тогда, когда вам нужна изоляция CA на уровне команды. - DNS-01 строго обязателен для wildcard-сертификатов и для кластеров, не доступных напрямую из интернета на порту 80.
- Поле
renewBeforeне является необязательным в производственной среде — установите его не менее чем в одну треть от общегоdurationсертификата. - Когда выдача зависает, путь отладки всегда следующий:
Certificate→CertificateRequest→Order→Challenge→ журналы контроллера. - Учётные данные API DNS-провайдера, на которые ссылается
ClusterIssuer, должны находиться в пространстве имёнcert-manager, а не в пространствах имён приложений. - Отслеживайте
certmanager_certificate_expiration_timestamp_secondsв Prometheus и настройте оповещения — молчаливые сбои обновления являются наиболее опасным режимом отказа. - Включите манифесты
CertificateиClusterIssuerв план аварийного восстановления.
Часто задаваемые вопросы
В чём разница между Issuer и ClusterIssuer в Cert-Manager?
Issuer ограничен пространством имён и может выдавать сертификаты только в том пространстве имён, где он определён. ClusterIssuer действует в масштабе всего кластера и может быть указан ресурсами Certificate в любом пространстве имён. Для большинства производственных кластеров ClusterIssuer является правильным выбором, если только вам не нужна строгая изоляция CA на уровне пространства имён.
Почему мой сертификат Cert-Manager завис в состоянии «Issuing»?
Проверьте объекты Order и Challenge в том же пространстве имён с помощью kubectl describe. Наиболее распространённые причины: порт 80 заблокирован брандмауэром (HTTP-01), неверные учётные данные DNS API или задержка распространения (DNS-01), превышены ограничения на количество запросов Let’s Encrypt, или под webhook cert-manager не запущен. Всегда проверяйте журналы контроллера с помощью kubectl logs -n cert-manager deploy/cert-manager.
Может ли Cert-Manager выдавать wildcard-сертификаты от Let’s Encrypt?
Да, но только с использованием типа запроса DNS-01. HTTP-01 не может валидировать wildcard-домены. Вы должны настроить интеграцию с DNS-провайдером (Cloudflare, Route53 и т.д.) в конфигурации решателя ClusterIssuer и убедиться, что учётные данные API имеют разрешение на создание TXT-записей для целевого домена.
Как Cert-Manager автоматически обрабатывает обновление сертификатов?
Контроллер Cert-Manager непрерывно сравнивает срок истечения каждого объекта Certificate с текущим временем. Когда оставшийся срок действия опускается ниже порога renewBefore (по умолчанию: 30 дней), контроллер создаёт новый CertificateRequest, выполняет ACME-запрос и атомарно заменяет содержимое целевого Secret — всё это без перезапуска подов, использующих сертификат. Поды, монтирующие Secret как том, увидят обновлённый сертификат при следующем цикле синхронизации kubelet.
Подходит ли Cert-Manager для защиты внутреннего взаимодействия между сервисами, а не только для публичного HTTPS?
Да. Используя издатель CA или издатель HashiCorp Vault, Cert-Manager может выдавать краткосрочные сертификаты для внутреннего mTLS между микросервисами. Это распространённый шаблон в развёртываниях сервисных сетей, где каждая рабочая нагрузка нуждается в уникальном сертификате идентификации. Поля duration и renewBefore позволяют сертификатам иметь срок действия от нескольких минут с полностью автоматизированной ротацией.
