cert-manager: wildcard-сертификаты через DNS-01 challenge

Published: 2026-04-01

cert-manager автоматизирует выпуск и обновление TLS-сертификатов. Для wildcard-сертификатов (*.dev.test.antonnovikov.com) HTTP-01 challenge не подходит — нужен DNS-01, который подтверждает владение доменом через DNS TXT-запись.


Установка

cert-manager работает на infra-кластере и выпускает сертификаты для всех окружений. Spoke-кластеры получают их через SealedSecrets.

yamlapiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: cert-manager
  namespace: cert-manager
spec:
  chart:
    spec:
      chart: cert-manager
      version: "v1.14.*"
      sourceRef:
        kind: HelmRepository
        name: jetstack
        namespace: flux-system
  values:
    installCRDs: true
    podDnsPolicy: None
    podDnsConfig:
      nameservers:
        - 8.8.8.8
        - 1.1.1.1

Кастомный DNS важен — поды cert-manager должны опрашивать авторитативный DNS-сервер домена, а не кластерный DNS.


ClusterIssuer с ACME DNS-01

Для доменов на Yandex Cloud DNS:

yamlapiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@antonnovikov.com
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    solvers:
      - dns01:
          webhook:
            groupName: acme.yandex.cloud
            solverName: yandex-cloud-dns
            config:
              folder: "${YC_FOLDER_ID}"
              serviceAccountSecretRef:
                name: yc-dns-sa-key
                key: sa-key.json

Для AWS Route53:

yamlsolvers:
  - dns01:
      route53:
        region: us-east-1
        accessKeyIDSecretRef:
          name: route53-credentials
          key: access-key-id
        secretAccessKeySecretRef:
          name: route53-credentials
          key: secret-access-key

Для Cloudflare:

yamlsolvers:
  - dns01:
      cloudflare:
        email: admin@example.com
        apiTokenSecretRef:
          name: cloudflare-api-token
          key: api-token

Certificate

yamlapiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: dev-wildcard
  namespace: ingress-apisix
spec:
  secretName: dev-test-antonnovikov-com-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  commonName: "*.dev.test.antonnovikov.com"
  dnsNames:
    - "*.dev.test.antonnovikov.com"
    - "dev.test.antonnovikov.com"
  duration: 2160h    # 90 дней (максимум Let's Encrypt)
  renewBefore: 360h  # обновить за 15 дней до истечения

cert-manager создаёт Secret с tls.crt и tls.key. APISIX или Ingress ссылается на этот Secret.


Распространение на spoke-кластеры

cert-manager работает только на infra. Spoke-кластеры получают сертификаты через SealedSecrets:

  1. cert-manager выпускает сертификат → Secret в ingress-apisix на infra
  2. Запечатать: kubeseal --context=dev-k8s -o yaml < secret.yaml > sealed.yaml
  3. Закоммитить в fluxcd/projects/dev/kustomization/spoke/secrets/dev-wildcard-tls.yaml
  4. Flux применяет на spoke при следующей реконсиляции

При обновлении (cert-manager обновляет за 15 дней до истечения) — перезапечатать и закоммитить.


Диагностика

bash# Статус сертификата
kubectl describe certificate dev-wildcard -n ingress-apisix

# Статус CertificateRequest
kubectl describe certificaterequest -n ingress-apisix

# Статус ACME challenge
kubectl describe challenge -n ingress-apisix

# Логи webhook
kubectl logs -n cert-manager -l app=cert-manager-webhook-yandex

# Проверить TXT-запись
dig TXT _acme-challenge.dev.test.antonnovikov.com @8.8.8.8

Самая частая проблема: TXT-запись не успела разойтись по DNS до проверки валидаторами Let's Encrypt. Убедитесь, что запись _acme-challenge.dev.test.antonnovikov.com появляется до истечения таймаута challenge (по умолчанию 60 секунд).


Жизненный цикл сертификата

Certificate → CertificateRequest → Order → Challenge

Если у Certificate условие Ready в состоянии False:

  1. kubectl get challenge — challenge в pending дольше 2 минут означает медленное распространение DNS-записей
  2. kubectl get order — статус ACME order
  3. Логи контроллера: kubectl logs -n cert-manager deploy/cert-manager

Лимиты Let's Encrypt: 50 сертификатов на зарегистрированный домен в неделю. При тестировании используйте letsencrypt-staging.