Другое

Проблемы с выдачей сертификатов cert-manager в Kubernetes

Решение проблем с cert-manager: сертификаты переходят в состояние 'invalid'. Проверка сетевой связности, настройка HTTP01 solver и альтернативные методы для Kubernetes с MetallB.

Почему не получается выдать сертификаты с помощью cert-manager в Kubernetes?

Я пытаюсь выдать сертификаты для домена tourshop.online, зарегистрированного в reg.ru. Все DNS-записи настроены на внешний адрес кластера, предоставленный metallb. Установил cert-manager через helm с командами:

bash
helm repo add jetstack https://charts.jetstack.io
helm repo update
kubectl create namespace cert-manager
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --version v1.14.4 \
  --set installCRDs=true

Применяю ClusterIssuer:

yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: тутМояПочта
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx

Создаю Ingress для получения сертификатов:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tourshop-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  rules:
  - host: tourshop.online
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: tourshop-service
            port:
              number: 80
  tls:
  - hosts:
    - tourshop.online
    secretName: tourshop-online-tls

Проблема: процесс получения сертификатов начинается, но в итоге Order и Challenge переходят в состояние ‘invalid’, а solver-ingress исчезает. Мониторинг показывает:

  1. Сначала Certificate, Order и Challenge находятся в состоянии ‘pending’
  2. Ingress получает IP-адрес (141.105.71.240)
  3. Затем Order и Challenge переходят в ‘invalid’
  4. Solver-ingress исчезает

Что может вызывать такую проблему и как ее исправить?

Сертификаты не выдаются из-за проблем с самопроверкой HTTP01-вызова и сетевыми связями. Это распространенная проблема при использовании cert-manager с внешними IP-адресами, особенно в средах с MetallB. Процесс самопроверки cert-manager не может достучаться до вашего внешнего IP изнутри кластера, что приводит к состоянию “invalid”.

Содержание

Основные причины и решения

Проблема самопроверки (self-check)

Cert-manager выполняет самопроверку для подтверждения, что вызов ACME доступен извне. Если проверка не проходит, вызов переходит в состояние “invalid”.

Решение:

bash
kubectl describe challenges <имя-вызова> -n <namespace>

В выводе вы увидите ошибку типа:

Reason: Error accepting authorization: acme: authorization error for tourshop.online: 400 urn:ietf:params:acme:error:connection: Fetching http://tourshop.online/.well-known/acme-challenge/...: Timeout after connect (your server may be slow or overloaded)

Настройка решателя HTTP01

Добавление аннотаций для Ingress

Добавьте аннотации в ваш Ingress для лучшей совместимости:

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tourshop-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    nginx.ingress.kubernetes.io/rewrite-target: /
    # Это предотвратит перенаправление на HTTPS для путей ACME
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  ingressClassName: nginx
  rules:
  - host: tourshop.online
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: tourshop-service
            port:
              number: 80
  tls:
  - hosts:
    - tourshop.online
    secretName: tourshop-online-tls

Использование edit-in-place

Для некоторых ingress-контроллеров требуется специальная аннотация:

yaml
metadata:
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    acme.cert-manager.io/http01-edit-in-place: "true"

Проверка сетевой связности

Проблема с двойным NAT

Ваши узлы могут не иметь прямого доступа к внешнему IP MetallB из-за ограничений сетевой связности.

Диагностика:

bash
kubectl run -it --rm --restart=Never --image=busybox test-pod -- wget -O - http://tourshop.online/.well-known/acme-challenge/<токен>

Если команда возвращает ошибку подключения, это подтверждает проблему с сетевой связностью.

Обходной путь с использованием NodePort

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tourshop-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  rules:
  - host: tourshop.online
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: tourshop-service
            port:
              number: 80
  tls:
  - hosts:
    - tourshop.online
    secretName: tourshop-online-tls

И создайте отдельный сервис для решателя ACME:

yaml
apiVersion: v1
kind: Service
metadata:
  name: acme-solver-service
spec:
  selector:
    app: tourshop-app
  ports:
  - port: 80
    targetPort: 8080

Отладка и мониторинг

Проверка состояния вызовов

bash
kubectl get challenges -A
kubectl get orders -A
kubectl get certificates -A

Логи cert-manager

bash
kubectl logs -n cert-manager deploy/cert-manager -f
kubectl logs -n cert-manager deploy/cert-manager-cainjector -f
kubectl logs -n cert-manager deploy/cert-manager-webhook -f

Проверка solver pod

bash
kubectl get pods -n cert-manager | grep acme-http-solver
kubectl logs -n cert-manager <имя-pod>

Мониторинг ingress

bash
kubectl describe ingress tourshop-ingress
kubectl get ingress tourshop-ingress -o yaml

Альтернативные подходы

DNS01 решатель

Если HTTP01 продолжает не работать, используйте DNS01:

yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: тутМояПочта
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - dns01:
        cloudflare:
          email: тутМояПочта
          apiTokenSecretRef:
            name: cloudflare-api-token-secret
            key: api-token

Временное отключение самопроверки

Можно отключить строгую самопроверку (но это не рекомендуется для продакшена):

yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    email: тутМояПочта
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx
          # Добавьте эту опцию если она доступна в вашей версии
          disableIngressClassAnnotation: true

Восстановление из состояния invalid

Очистка ресурсов

bash
kubectl delete order <имя-order>
kubectl delete challenge <имя-challenge>
kubectl delete certificaterequest <имя-request>

Удаление сертификата и повторное создание

bash
kubectl delete secret tourshop-online-tls
kubectl delete certificate tourshop-online-tls

После очистки удалите Certificate и создайте его заново:

yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: tourshop-online-tls
  namespace: default
spec:
  secretName: tourshop-online-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  commonName: tourshop.online
  dnsNames:
  - tourshop.online

Источники

  1. Troubleshooting Problems with ACME / Let’s Encrypt Certificates - cert-manager Documentation
  2. HTTP01 - cert-manager Documentation
  3. Cert-manager HTTP01 challenge fails, solver pod short-lived · Issue #4726
  4. HTTP01 solver POD returns an empty 200 OK response instead of the expected key · Issue #2826
  5. Letsencrypt acme cert challenges no longer working on AKS · Issue #2955
  6. Waiting for http-01 challenge propagation: failed to perform self check GET request · Issue #3238
  7. Kubernetes: Why are my acme challenges getting EOF/no response? - Stack Overflow
  8. Cert Manager With Http01 Challeges · Juanjo’s blog

Заключение

  1. Основная проблема - cert-manager не может выполнить самопроверку HTTP01 вызова из-за сетевых ограничений при использовании MetallB
  2. Ключевые решения: Добавьте аннотации для ingress, настройте edit-in-place, проверьте сетевую связность
  3. Альтернативы: Используйте DNS01 решатель или временно отключите строгую самопроверку
  4. Восстановление: Очистите ресурсы в состоянии invalid и повторите процесс issuance
  5. Профилактика: Всегда проверяйте сетевую связность перед настройкой cert-manager и используйте staging среду для тестирования

Для вашего случая с tourshop.online рекомендуется сначала проверить сетевую связность с помощью команды wget из пода, затем добавить необходимые аннотации в ingress и попробовать повторно создать сертификат. Если это не поможет, рассмотрите переход на DNS01 решатель.

Авторы
Проверено модерацией
Модерация