Kubernetes无法获取Let's Encrypt证书:ACME挑战路由异常
已部署microk8s、traefik与cert-manager,尝试获取Let's Encrypt证书时,ACME挑战Pod已创建,但Let's Encrypt服务器的请求未送达该Pod,反而被转发至网站服务Pod。观察发现,将流量路由至Web Pod的IngressRoute优先级高于路由/.well-known/acme-challenge/...请求至挑战Pod的Ingress,请问缺失了哪些配置?
相关配置文件
ClusterIssuer配置(letsencrypt-prod)
kind: ClusterIssuer metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"cert-manager.io/v1","kind":"ClusterIssuer","metadata":{"annotations":{},"name":"letsencrypt-prod"},"spec":{"acme":{"email":"office@mydomain.com","privateKeySecretRef":{"name":"letsencrypt-prod"},"server":"https://acme-v02.api.letsencrypt.org/directory","solvers":[{"http01":{"ingress":{"class":"traefik"}}}]}}} creationTimestamp: "2022-07-11T14:32:15Z" generation: 11 name: letsencrypt-prod resourceVersion: "49979842" uid: 40c4e26d-9c94-4cda-aa3a-357491bdb25a spec: acme: email: office@mydomain.com preferredChain: "" privateKeySecretRef: name: letsencrypt-prod server: https://acme-v02.api.letsencrypt.org/directory solvers: - http01: ingress: {} status: acme: lastRegisteredEmail: office@mydomain.com uri: https://acme-v02.api.letsencrypt.org/acme/acct/627190636 conditions: - lastTransitionTime: "2022-07-11T14:32:17Z" message: The ACME account was registered with the ACME server observedGeneration: 11 reason: ACMEAccountRegistered status: "True" type: Ready
Web服务IngressRoute配置(webspace1-tls)
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"traefik.containo.us/v1alpha1","kind":"IngressRoute","metadata":{"annotations":{},"name":"w271a19-tls","namespace":"default"},"spec":{"entryPoints":["websecure"],"routes":[{"kind":"Rule","match":"Host(`test1.mydomain.com`)"},{"middlewares":[{"name":"test-compress"}],"priority":10,"services":[{"name":"w271a19","port":80}]}],"tls":{"secretName":"test1.mydomain.com-tls"}}} creationTimestamp: "2022-10-05T20:01:38Z" generation: 7 name: w271a19-tls namespace: default resourceVersion: "45151920" uid: 77e9b7ac-33e7-4810-9baf-579f00e2db6b spec: entryPoints: - websecure routes: - kind: Rule match: Host(`test1.mydomain.com`) middlewares: - name: test-compress priority: 10 services: - name: w271a19 port: 80 tls: secretName: test1.mydomain.com-tls
ACME挑战Ingress配置(cm-acme-http-solver-rz9mm)
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0,::/0 creationTimestamp: "2023-03-22T13:00:18Z" generateName: cm-acme-http-solver- generation: 1 labels: acme.cert-manager.io/http-domain: "2306410973" acme.cert-manager.io/http-token: "1038683769" acme.cert-manager.io/http01-solver: "true" name: cm-acme-http-solver-rz9mm namespace: default ownerReferences: - apiVersion: acme.cert-manager.io/v1 blockOwnerDeletion: true controller: true kind: Challenge name: test1.mydomain.com-glnrn-2096762198-4162956557 uid: db8b5c78-8549-4f13-b43d-c6c7bba7468d resourceVersion: "52806119" uid: 6b27e02a-ee65-4809-b391-95c03f9ebb36 spec: ingressClassName: traefik rules: - host: test1.mydomain.com http: paths: - backend: service: name: cm-acme-http-solver-ll2zr port: number: 8089 path: /.well-known/acme-challenge/9qtVY8FjfMIWd_wBNhP3PEPJZo4lFTw8WfWLMucRqAQ pathType: ImplementationSpecific status: loadBalancer: {}
Certificate配置(get_cert.yaml)
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: test1.mydomain.com namespace: default spec: secretName: test1.mydomain.com-tls issuerRef: name: letsencrypt-prod kind: ClusterIssuer commonName: test1.mydomain.com dnsNames: - test1.mydomain.com
补充:Web Pod的服务器日志中可见
/.well-known/...的请求记录,说明请求确实被转发到了Web服务而非挑战Pod。
问题原因与修复方案
核心原因
Traefik对自定义CRD IngressRoute 的路由优先级默认高于Kubernetes标准Ingress资源。你的Web服务使用IngressRoute且设置了priority:10,而cert-manager默认创建的ACME挑战路由是标准Ingress,导致挑战请求被优先级更高的Web服务路由拦截。
修复方案1:让cert-manager创建Traefik IngressRoute处理ACME挑战
修改ClusterIssuer,将http01 solver的配置从ingress改为ingressRoute,这样cert-manager会生成Traefik原生的IngressRoute来处理挑战,其优先级默认会比Web服务的IngressRoute更高(因为路径匹配更具体,且IngressRoute的优先级规则中,更具体的匹配会优先):
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: email: office@mydomain.com privateKeySecretRef: name: letsencrypt-prod server: https://acme-v02.api.letsencrypt.org/directory solvers: - http01: ingressRoute: {} # 替换原有的ingress配置
修复方案2:降低Web服务IngressRoute的优先级
将Web服务IngressRoute的priority值调低(比如设为5),让ACME挑战的路由(无论标准Ingress还是IngressRoute)能够优先匹配:
apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: w271a19-tls namespace: default spec: entryPoints: - websecure routes: - kind: Rule match: Host(`test1.mydomain.com`) middlewares: - name: test-compress priority: 5 # 降低优先级 services: - name: w271a19 port: 80 tls: secretName: test1.mydomain.com-tls
额外建议
推荐使用方案1,因为Traefik的IngressRoute是原生CRD,路由匹配和优先级处理更可靠,且cert-manager对其支持完善。如果坚持使用标准Ingress,需确保Traefik配置中启用了Kubernetes Ingress provider,不过优先级问题仍可能出现。
内容的提问来源于stack exchange,提问作者Peter

