ACME / Let's Encrypt 証明書の問題のトラブルシューティング
cert-manager が ACME / Let's Encrypt 証明書の更新に失敗した場合の問題を診断する方法を説明します。
概要
ACME 証明書をリクエストすると、cert-manager はリクエストを完了するために Order
と Challenges
を作成します。そのため、プロセス中に問題が発生した場合、調査およびデバッグするリソースが増えます。これらのリソースの詳細については、コンセプトページを参照してください。
ここから始める前に、一般的なトラブルシューティングガイドを確認することをお勧めします。
1. (Cluster)Issuer のトラブルシューティング
まず、使用している (Cluster)Issuer が準備完了状態であるかどうかを確認します。
$ kubectl get issuer$ kubectl get clusterissuerNAME READY AGEletsencrypt True 38mletsencrypt-http False 32m
False
と表示された場合は、kubectl describe
を使用してステータスを確認します。例:
$ kubectl describe issuer letsencrypt-http$ kubectl describe clusterissuer letsencrypt-httpName: letsencryptAPI Version: cert-manager.io/v1Kind: IssuerSpec:Acme:Email: cert-manager@example.comPrivate Key Secret Ref:Name: letsencryptServer: https://acme-staging-v02.api.letsencrypt.org/directoryStatus: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 forbiddenReason: ErrUpdateACMEAccountStatus: FalseType: ReadyEvents: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
: Issuer 構成で指定したメールアドレスが無効です。Error initializing issuer: Failed to register ACME account: secrets "acme-key" already exists
: 無効になった以前の Issuer からのアカウントが残っている可能性があります。再作成できるようにシークレットを削除する必要があります。Error accepting challenge: 400 urn:ietf:params:acme:error:malformed: Unable to update challenge :: authorization must be pending
: これは、cert-manager がチャレンジを受け入れるリクエストを ACME サーバーに送信した時点で、認証が「保留中」状態ではなかったことを示唆しています。これは、ドメイン検証が既に失敗し、認証が「無効」とマークされているためである可能性があります。Order
またはChallenge
のステータスの認証 URL を確認して、認証のステータスと追加情報を確認してください。
2. オーダーのトラブルシューティング
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 インスタンスへのリクエストです。特定のオーダーで kubectl describe order
を実行すると、プロセス内の失敗に関する情報を収集できます
$ kubectl describe order example-com-2745722290-439160286...Reason:State: pendingURL: https://acme-v02.api.letsencrypt.org/acme/order/41123272/265506123Events: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 が、署名付き証明書を取得するための ACME オーダーの要件である、特定のドメインを制御していることを検証するために 2 つの Challenge リソースを作成したことがわかります。
次に、kubectl describe challenge example-com-2745722290-439160286-0
を実行して、オーダーの進行状況をさらにデバッグできます。
オーダーが正常に完了すると、次のようなイベントが表示されるはずです
$ kubectl describe order example-com-2745722290-439160286...Reason:State: validURL: https://acme-v02.api.letsencrypt.org/acme/order/41123272/265506123Events: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}'
オーダーが正常に完了しない場合は、次の手順で説明するように、Challenge
リソースで kubectl describe
を実行して、オーダーのチャレンジをデバッグできます。
3. チャレンジのトラブルシューティング
ACME オーダーが完了しない理由を特定するために、cert-manager が作成した Challenge
リソースを使用してデバッグできます。
どの Challenge
が失敗しているかを特定するには、kubectl get challenges
を実行します
$ kubectl get challenges...NAME STATE DOMAIN REASON AGEexample-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: trueProcessing: trueReason: Waiting for dns-01 challenge propagationState: pendingEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Started 19s cert-manager Challenge scheduled for processingNormal 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: trueProcessing: trueReason: 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 failureState: pending[...]
この例では、ネットワークの問題により HTTP01 チェックが失敗しています。ここには、DNS プロバイダーからのエラーも表示されます。
Challenge
のステータスからの認証 URL を使用して、チャレンジが検証する必要がある ACME 認証の状態に関する追加情報も確認できます
$ kubectl get challenge <challenge-name> -ojsonpath='{.spec.authorizationURL}'
HTTP01 のトラブルシューティング
まず、パブリックインターネットからチャレンジ URL を確認できるかどうかを確認します。これが機能しない場合は、Ingress およびファイアウォール構成と、ACME チャレンジを解決するために cert-manager が作成したサービスとポッドを確認してください。これが機能する場合は、クラスターもそれを確認できるかどうかを確認します。これはポッド内からテストすることが重要です。接続エラーが発生した場合は、クラスターのネットワーク構成を確認することをお勧めします。tls: handshake failure
を受信した場合は、Ingress または Certificate リソースでアノテーション cert-manager.io/issue-temporary-certificate: "true"
を設定してみてください。これにより、実際の証明書が発行される前に、イングレスコントローラーが使用するための一時的な自己署名証明書が発行されます。それでも問題が解決しない場合は、イングレスコントローラーが同じホスト名に対して複数のリソースを処理することに問題がある可能性があります。この場合、アノテーション acme.cert-manager.io/http01-edit-in-place: "true"
が必要になる可能性があります。
たとえば、Google Cloud Loadbalancer で GKE を使用する場合は、次の設定をお勧めします
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 がチャレンジエンドポイントに 2 番目の IP アドレスを割り当てるのを防ぎます。
404 ステータスコードを取得した場合
チャレンジの自己チェックが 404 Not Found エラーで失敗した場合。次の点を確認してください
- パブリックインターネットから URL にアクセスできる
- ACME ソルバーポッドが起動して実行されている
kubectl describe ingress
を使用して、HTTP01 ソルバーイングレスのステータスを確認します。(acme.cert-manager.io/http01-edit-in-place
を使用している場合は、ドメインと同じイングレスを確認してください)
DNS01 のトラブルシューティング
DNS プロバイダーに関するエラーイベントが表示されない場合は、次の点を確認できます。パブリックインターネットまたは DNS プロバイダーのインターフェースから _acme_challenge.domain
TXT DNS レコードが表示されるかどうかを確認します。cert-manager は、クラスターの DNS ソルバーにクエリを実行して、DNS レコードが伝播されたかどうかを確認します。パブリックインターネットからは確認できるが、クラスター内からは確認できない場合は、一部のクラウドプロバイダーが内部で DNS を上書きするため、自己チェック用の DNS サーバーを変更することをお勧めします。
cert-manager がドメイン名のゾーンを誤って識別する
cert-manager はデフォルトで SOA (Start of Authority) レコードを使用して、DNS プロバイダーで使用するゾーン名を決定します。一部の DNS リゾルバーはこの情報をフィルタリングします。この場合、cert-manager はゾーンを決定できず、DNS01 自己チェック用の DNS サーバーを変更することをお勧めします。
DNSサーバーとしてdnsmasq
を使用している場合、--filterwin2k
フラグを使用していると、この問題が発生する可能性があります。 OpenWRTにはfilterwin2k
という設定オプションがあります。また、LuCIには「Filter useless」オプションがあります。このフラグを有効にすると、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。