新消息:在TwitterMastodon取得專案更新

ACME / Let's Encrypt 憑證疑難排解

了解當 cert-manager 無法更新 ACME / Let's Encrypt 憑證時,如何診斷問題。

概觀

當請求 ACME 憑證時,cert-manager 會建立 OrderChallenges 來完成請求。因此,如果過程中出現問題,會有更多資源需要調查和除錯。您可以在概念頁面中閱讀更多關於這些資源的資訊。

在您開始之前,您應該先看看我們的一般疑難排解指南

1. 疑難排解 (叢集)簽發者

首先,檢查您正在使用的 (叢集)簽發者是否處於就緒狀態

$ kubectl get issuer
$ kubectl get clusterissuer
NAME READY AGE
letsencrypt True 38m
letsencrypt-http False 32m

如果您看到 False,請使用 kubectl describe 檢查狀態。例如

$ kubectl describe issuer letsencrypt-http
$ kubectl describe clusterissuer letsencrypt-http
Name: letsencrypt
API Version: cert-manager.io/v1
Kind: Issuer
Spec:
Acme:
Email: cert-manager@example.com
Private Key Secret Ref:
Name: letsencrypt
Server: https://acme-staging-v02.api.letsencrypt.org/directory
Status:
Acme:
Conditions:
Message: Failed to update ACME account:400 urn:ietf:params:acme:error:invalidEmail: Unable to update account :: invalid contact domain. Contact emails @example.com are forbidden
Reason: ErrUpdateACMEAccount
Status: False
Type: Ready
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning ErrUpdateACMEAccount 101s (x3 over 106s) cert-manager Failed to update ACME account:400 urn:ietf:params:acme:error:invalidEmail: Unable to update account :: invalid contact domain. Contact emails @example.com are forbidden

常見錯誤

  • Failed to update ACME account:400 urn:ietf:params:acme:error:invalidEmail:您在簽發者設定中指定的電子郵件無效。
  • Error initializing issuer: Failed to register ACME account: secrets "acme-key" already exists:可能存在先前不再有效的簽發者的殘留帳戶,您應該移除該密鑰,以便重新建立。
  • Error accepting challenge: 400 urn:ietf:params:acme:error:malformed: Unable to update challenge :: authorization must be pending:這表示當 cert-manager 向 ACME 伺服器發送請求以接受挑戰時,授權並未處於「pending」狀態。這可能是因為網域驗證已失敗,並且授權已被標記為「invalid」。請查看 OrderChallenge 的狀態上的授權 URL,以查看授權的狀態和任何其他資訊。

2. 疑難排解 Order

當我們在 CertificateRequest 資源上執行 describe 時,我們可以看到已建立 Order

$ kubectl describe certificaterequest example-com-2745722290
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal OrderCreated 5s cert-manager Created Order resource default/example-com-2745722290-439160286

Order 是向 ACME 實例發出憑證的請求。藉由在特定 order 上執行 kubectl describe order,可以收集有關過程中失敗的資訊

$ kubectl describe order example-com-2745722290-439160286
...
Reason:
State: pending
URL: https://acme-v02.api.letsencrypt.org/acme/order/41123272/265506123
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Created 1m cert-manager Created Challenge resource "example-com-2745722290-439160286-0" for domain "test1.example.com"
Normal Created 1m cert-manager Created Challenge resource "example-com-2745722290-439160286-1" for domain "test2.example.com"

在這裡,我們可以看見 cert-manager 已建立兩個 Challenge 資源,以驗證我們控制特定網域,這是 ACME order 取得簽署憑證的要求。

然後,您可以繼續執行 kubectl describe challenge example-com-2745722290-439160286-0,以進一步除錯 Order 的進度。

一旦 Order 成功,您應該會看到類似以下的事件

$ kubectl describe order example-com-2745722290-439160286
...
Reason:
State: valid
URL: https://acme-v02.api.letsencrypt.org/acme/order/41123272/265506123
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Created 72s cert-manager Created Challenge resource "example-com-2745722290-439160286-0" for domain "test1.example.com"
Normal Created 72s cert-manager Created Challenge resource "example-com-2745722290-439160286-1" for domain "test2.example.com"
Normal OrderValid 4s cert-manager Order completed successfully

您可以使用 Order 狀態中的授權 URL,查看更多關於需要驗證的ACME 授權狀態的額外資訊。

$ kubectl get order <order-name> -ojsonpath='{.status.authorizations[x].url}'

如果 Order 未成功完成,您可以執行 kubectl describe 來除錯 Order 的挑戰,這在以下步驟中說明。

3. 疑難排解 Challenges

為了判斷 ACME Order 未完成的原因,我們可以使用 cert-manager 已建立的 Challenge 資源進行除錯。

為了判斷哪個 Challenge 失敗,您可以執行 kubectl get challenges

$ kubectl get challenges
...
NAME STATE DOMAIN REASON AGE
example-com-2745722290-4391602865-0 pending example.com Waiting for dns-01 challenge propagation 22s

這表示挑戰已使用 DNS01 解算器成功呈現,現在 cert-manager 正在等待「自我檢查」通過。

您可以使用 kubectl describe 取得更多關於挑戰及其生命週期的資訊

$ kubectl describe challenge example-com-2745722290-4391602865-0
...
Status:
Presented: true
Processing: true
Reason: Waiting for dns-01 challenge propagation
State: pending
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Started 19s cert-manager Challenge scheduled for processing
Normal Presented 16s cert-manager Presented challenge using dns-01 challenge mechanism

每個挑戰的狀態進度將記錄為事件或挑戰的 status 區塊(如上所示)。

在 DNS01 的情況下,您會在此處找到來自 DNS 提供者的任何錯誤。

HTTP01 和 DNS01 都會先經過「自我檢查」,然後 cert-manager 才會向 ACME 提供者呈現挑戰。這樣做是為了避免因 DNS 或負載平衡器傳播而導致失敗的挑戰使 ACME 提供者超載。此狀態可以在 describe 的 Status 區塊中找到

$ kubectl describe challenge
[...]
Status:
Presented: true
Processing: true
Reason: Waiting for http-01 challenge propagation: failed to perform self check GET request 'http://example.com/.well-known/acme-challenge/_fgdLz0i3TFiZW4LBjuhjgd5nTOkaMBhxYmTY': Get "http://example.com/.well-known/acme-challenge/_fgdLz0i3TFiZW4LBjuhjgd5nTOkaMBhxYmTY: remote error: tls: handshake failure
State: pending
[...]

在此範例中,我們的 HTTP01 檢查因網路問題而失敗。您也會在此處看到來自 DNS 提供者的任何錯誤。

您可以使用 Challenge 狀態中的授權 URL,查看更多關於挑戰應驗證的ACME 授權狀態的額外資訊。

$ kubectl get challenge <challenge-name> -ojsonpath='{.spec.authorizationURL}'

HTTP01 疑難排解

首先,檢查您是否可以從公共網際網路看到挑戰 URL,如果這不起作用,請檢查您的 Ingress 和防火牆設定,以及 cert-manager 建立來解決 ACME 挑戰的服務和 pod。如果這確實有效,請檢查您的叢集是否也能看到它。從 Pod 內部進行測試非常重要。如果您收到連線錯誤,建議檢查叢集的網路設定。如果您收到 tls: handshake failure,請嘗試在 Ingress 或憑證資源上設定註釋 cert-manager.io/issue-temporary-certificate: "true"。這將在發出實際憑證之前,為 Ingress 控制器發出臨時的自我簽署憑證以供使用。如果您仍然遇到問題,則可能是您的 Ingress 控制器在處理相同主機名稱的多個資源時出現問題,在這種情況下,可能需要註釋 acme.cert-manager.io/http01-edit-in-place: "true"

例如,當在 GKE 中使用 Google Cloud Loadbalancer 時,建議設定

cert-manager.io/issue-temporary-certificate: "true"
acme.cert-manager.io/http01-edit-in-place: "true"

這將允許 Google Cloud Loadbalancer 使用臨時憑證正確傳播 HTTPS 端點,http01-edit-in-place 部分將防止 GKE 為挑戰端點分配第二個 IP 位址。

取得 404 狀態碼

如果您的挑戰自我檢查失敗,並出現 404 找不到錯誤。請務必檢查以下項目

  • 您可以從公共網際網路存取 URL
  • ACME 解算器 pod 已啟動並執行
  • 使用 kubectl describe ingress 檢查 HTTP01 解算器 Ingress 的狀態。(除非您使用 acme.cert-manager.io/http01-edit-in-place,然後檢查與您網域相同的 Ingress)

DNS01 疑難排解

如果您沒有看到關於 DNS 提供者的錯誤事件,您可以檢查以下項目:檢查您是否可以從公共網際網路或在 DNS 提供者的介面中看到 _acme_challenge.domain TXT DNS 記錄。cert-manager 會透過查詢叢集的 DNS 解算器來檢查 DNS 記錄是否已傳播。如果您可以從公共網際網路看到它,但從叢集內部看不到,您可能需要變更用於自我檢查的 DNS 伺服器,因為某些雲端提供者會在內部覆寫 DNS。

cert-manager 為您的網域名稱識別錯誤的區域

cert-manager 預設會使用 SOA (授權開始) 記錄來判斷在您的 DNS 提供者處使用的區域名稱。某些 DNS 解析器會篩選此資訊,如果發生這種情況,cert-manager 將無法判斷區域,建議變更用於 DNS01 自我檢查的 DNS 伺服器

如果您使用 dnsmasq 作為您的 DNS 伺服器,如果您使用了 --filterwin2k 旗標,則可能會發生此情況。在 OpenWRT 中有一個 filterwin2k 設定選項。而在 LuCI 中有一個「過濾無用」選項。透過啟用此旗標,dnsmasq 會捨棄所有 SOA 記錄。

2020 年 3 月 Let's Encrypt CAA 重新檢查錯誤

3 月 4 日的公告,Let's Encrypt 將因驗證 CAA 記錄的方式存在錯誤而撤銷許多憑證,我們建立了一個工具來分析您現有的 cert-manager 管理的憑證,並將其序號與已發布的撤銷憑證列表進行比較。建議 Let's Encrypt 和 cert-manager 的所有使用者都使用此工具執行檢查,以確保他們在叢集中不會遇到任何無效的憑證錯誤。您可以在這裡找到檢查工具的副本:https://github.com/jetstack/letsencrypt-caa-bug-checker