Проблемы с выдачей сертификатов cert-manager в Kubernetes
Решение проблем с cert-manager: сертификаты переходят в состояние 'invalid'. Проверка сетевой связности, настройка HTTP01 solver и альтернативные методы для Kubernetes с MetallB.
Почему не получается выдать сертификаты с помощью cert-manager в Kubernetes?
Я пытаюсь выдать сертификаты для домена tourshop.online, зарегистрированного в reg.ru. Все DNS-записи настроены на внешний адрес кластера, предоставленный metallb. Установил cert-manager через helm с командами:
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:
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 для получения сертификатов:
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 исчезает. Мониторинг показывает:
- Сначала Certificate, Order и Challenge находятся в состоянии ‘pending’
- Ingress получает IP-адрес (141.105.71.240)
- Затем Order и Challenge переходят в ‘invalid’
- Solver-ingress исчезает
Что может вызывать такую проблему и как ее исправить?
Сертификаты не выдаются из-за проблем с самопроверкой HTTP01-вызова и сетевыми связями. Это распространенная проблема при использовании cert-manager с внешними IP-адресами, особенно в средах с MetallB. Процесс самопроверки cert-manager не может достучаться до вашего внешнего IP изнутри кластера, что приводит к состоянию “invalid”.
Содержание
- Основные причины и решения
- Настройка решателя HTTP01
- Проверка сетевой связности
- Отладка и мониторинг
- Альтернативные подходы
- Восстановление из состояния invalid
Основные причины и решения
Проблема самопроверки (self-check)
Cert-manager выполняет самопроверку для подтверждения, что вызов ACME доступен извне. Если проверка не проходит, вызов переходит в состояние “invalid”.
Решение:
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 для лучшей совместимости:
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-контроллеров требуется специальная аннотация:
metadata:
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
acme.cert-manager.io/http01-edit-in-place: "true"
Проверка сетевой связности
Проблема с двойным NAT
Ваши узлы могут не иметь прямого доступа к внешнему IP MetallB из-за ограничений сетевой связности.
Диагностика:
kubectl run -it --rm --restart=Never --image=busybox test-pod -- wget -O - http://tourshop.online/.well-known/acme-challenge/<токен>
Если команда возвращает ошибку подключения, это подтверждает проблему с сетевой связностью.
Обходной путь с использованием NodePort
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:
apiVersion: v1
kind: Service
metadata:
name: acme-solver-service
spec:
selector:
app: tourshop-app
ports:
- port: 80
targetPort: 8080
Отладка и мониторинг
Проверка состояния вызовов
kubectl get challenges -A kubectl get orders -A kubectl get certificates -A
Логи cert-manager
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
kubectl get pods -n cert-manager | grep acme-http-solver kubectl logs -n cert-manager <имя-pod>
Мониторинг ingress
kubectl describe ingress tourshop-ingress kubectl get ingress tourshop-ingress -o yaml
Альтернативные подходы
DNS01 решатель
Если HTTP01 продолжает не работать, используйте DNS01:
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
Временное отключение самопроверки
Можно отключить строгую самопроверку (но это не рекомендуется для продакшена):
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
Очистка ресурсов
kubectl delete order <имя-order> kubectl delete challenge <имя-challenge> kubectl delete certificaterequest <имя-request>
Удаление сертификата и повторное создание
kubectl delete secret tourshop-online-tls kubectl delete certificate tourshop-online-tls
После очистки удалите Certificate и создайте его заново:
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
Источники
- Troubleshooting Problems with ACME / Let’s Encrypt Certificates - cert-manager Documentation
- HTTP01 - cert-manager Documentation
- Cert-manager HTTP01 challenge fails, solver pod short-lived · Issue #4726
- HTTP01 solver POD returns an empty 200 OK response instead of the expected key · Issue #2826
- Letsencrypt acme cert challenges no longer working on AKS · Issue #2955
- Waiting for http-01 challenge propagation: failed to perform self check GET request · Issue #3238
- Kubernetes: Why are my acme challenges getting EOF/no response? - Stack Overflow
- Cert Manager With Http01 Challeges · Juanjo’s blog
Заключение
- Основная проблема - cert-manager не может выполнить самопроверку HTTP01 вызова из-за сетевых ограничений при использовании MetallB
- Ключевые решения: Добавьте аннотации для ingress, настройте edit-in-place, проверьте сетевую связность
- Альтернативы: Используйте DNS01 решатель или временно отключите строгую самопроверку
- Восстановление: Очистите ресурсы в состоянии invalid и повторите процесс issuance
- Профилактика: Всегда проверяйте сетевую связность перед настройкой cert-manager и используйте staging среду для тестирования
Для вашего случая с tourshop.online рекомендуется сначала проверить сетевую связность с помощью команды wget из пода, затем добавить необходимые аннотации в ingress и попробовать повторно создать сертификат. Если это не поможет, рассмотрите переход на DNS01 решатель.