新機能: プロジェクトの最新情報については、TwitterMastodonでご確認いただけます。

Google Kubernetes Engine (GKE)へのcert-managerのデプロイと、Let's Encryptを使用したIngressへのSSL証明書の生成

最終検証日: 2022年7月15日

このチュートリアルでは、Google Kubernetes Engine (GKE)へのcert-managerのデプロイと設定方法を学習します。Let's Encryptから署名されたSSL証明書を取得し、HTTP-01チャレンジを使用してcert-managerを設定する方法を学習します。最後に、その証明書を使用してパブリックドメイン名を持つHTTPSウェブサイトを運用する方法を学習します。

Google Cloud: Googleによるクラウドコンピューティングサービスのスイートです。
Kubernetes: サーバー上で動作します。コンテナ化されたアプリケーションのデプロイ、スケーリング、および管理を自動化します。
cert-manager: Kubernetes内で動作します。TLS/SSL証明書を取得し、証明書が有効で最新の状態であることを保証します。
Let’s Encrypt: インターネットサービスです。無料の短期間有効なSSL証明書の生成を可能にします。

まず、Kubernetes (GKE)クラスタを作成し、サンプルウェブサーバーをデプロイします。次に、ウェブサイトのパブリックIPアドレスとパブリックドメイン名を作成します。IngressとGoogle Cloudロードバランサーを設定して、インターネットクライアントがHTTPを使用してウェブサーバーに接続できるようにします。最後に、cert-managerを使用してLet's EncryptからSSL証明書を取得し、ロードバランサーがその証明書を使用するように設定します。このチュートリアルの最後には、https:// URLを使用してインターネットからウェブサイトに接続できるようになります。

前提条件

💻 Google Cloudアカウント

Google Cloudアカウントが必要です。登録にはクレジットカードまたは銀行口座の情報が必要です。Google Cloudの開始方法ページにアクセスして、手順に従ってください。

💵 Google Cloudを初めて使用する場合は、Google Cloud無料プログラムを利用できる場合があります。これは、Google Cloudを探索して評価するための300ドルの無料クラウド請求クレジットを含む90日間のトライアル期間を提供します。

💻 ドメイン名

ドメイン名と、そのドメインでDNSレコードを作成する機能が必要です。Google Domainsから12ドルのドメイン名を取得します。Google Domainsは、多くの可能な「ドメイン名レジストラ」の1つです。NameCheapとGoDaddyは、他の2つのよく知られたレジストラです。

💵 ドメイン名を購入したくない場合は、このチュートリアルをIPアドレスを使用してウェブサイトとSSL証明書を提供するように適応させることも可能です。

💻 ソフトウェア

また、ラップトップに次のソフトウェアをインストールする必要があります。

  1. gcloud: Google Cloudリソースの作成と管理のためのツールセットです。
  2. kubectl: Kubernetesクラスタを設定できるKubernetesコマンドラインツールです。
  3. curl: HTTPおよびHTTPSを使用してウェブサーバーに接続するためのコマンドラインツールです。

ℹ️ gcloud components install kubectl を実行して kubectl を迅速にインストールしてみてください。

0. Google Cloudプロジェクトでgcloud を設定する

Google Cloudアカウントを持っていない場合、以下のコマンドでアカウントを作成します。

gcloud init

次の質問に「yes」と答える必要があります。

Do you want to configure a default Compute Region and Zone? (Y/n)? Y

コマンドを実行した後、プロジェクト名、デフォルトリージョン、デフォルトゾーンが表示されます。

出力例

* Commands that require authentication will use firstname.lastname@example.com by default
* Commands will reference project `your-project` by default
* Compute Engine commands will use region `europe-west1` by default
* Compute Engine commands will use zone `europe-west1-b` by default

このチュートリアルでは、gcloud init の実行時に選択されたプロジェクト名を PROJECT 変数で参照します。$PROJECT がコマンドに表示される場合は、(1) コマンドを実行する前に変数を手動で置き換えるか、(2) シェルセッションで変数をエクスポートする必要があります。これは、このチュートリアルに記載されているコマンドで発生するすべての環境変数に適用されます。

(2) の方法を使用するため、gcloud init で出力された情報を使用して環境変数をエクスポートしてから続行する必要があります。

export PROJECT=your-project # Your Google Cloud project ID.
export REGION=europe-west1 # Your Google Cloud region.

1. Kubernetesクラスタの作成

開始するには、Google CloudにKubernetesクラスタを作成します。クラスタの名前を選択する必要があります。ここでは「test-cluster-1」を使用します。環境変数に保存しましょう。

export CLUSTER=test-cluster-1

次に、次のコマンドを使用してクラスタを作成します。

gcloud container clusters create $CLUSTER --preemptible --num-nodes=1

kubectlのGoogle Kubernetes Engine認証プラグインを設定します。

gcloud components install gke-gcloud-auth-plugin
export USE_GKE_GCLOUD_AUTH_PLUGIN=True
gcloud container clusters get-credentials $CLUSTER

クラスタに接続できることを確認します。

kubectl get nodes -o wide

⏲ クラスタの作成には4〜5分かかります。

💵 クラウド料金を最小限に抑えるために、このコマンドは、通常の仮想マシンよりも安価なプリエンプティブ仮想マシンを使用する1ノードクラスタを作成します。

2. サンプルウェブサーバーのデプロイ

「hello world!」でHTTPリクエストに応答する非常にシンプルなウェブサーバーをデプロイします。

kubectl create deployment web --image=gcr.io/google-samples/hello-app:1.0

また、接続をウェブサーバーPodにルーティングできるように、Kubernetesサービスを作成する必要があります。

kubectl expose deployment web --port=8080

ℹ️ これらのkubectl命令型コマンドは、可読性と簡潔さのために使用されています。YAMLマニフェストとkubectl apply -f を代わりに使用しても構いません。

ℹ️ kubectl expose で作成されたサービスは、ClusterIP タイプ(デフォルト)になり、クラスタ内のコンポーネントからのみアクセスできます。後で、クラスタ外部のクライアントがサービスを利用できるようにするIngressを作成します。

🔰 サービスを使用してアプリケーションを公開する方法の詳細を参照してください。

3. 静的外部IPアドレスの作成

このチュートリアルは、HTTP01チャレンジメカニズムを使用してLet's Encrypt SSL証明書を持つパブリックにアクセスできるHTTPSウェブサイトを作成する方法について説明しているため、Let's Encryptと他のインターネットクライアントの両方がウェブサイトに接続できるように、パブリックIPアドレスが必要です。

Google CloudでパブリックIPアドレスを作成するのは簡単で、後でそれをウェブサイトのドメイン名とGoogle Cloudロードバランサーに関連付けます。ロードバランサーは、インターネットクライアントからのHTTP(S)接続を受け入れ、クラスタ内で実行されているウェブサーバーにリクエストをプロキシします。

グローバル静的IPアドレスを次のように作成します。

gcloud compute addresses create web-ip --global

新しいIPアドレスがリストされていることを確認する必要があります。

gcloud compute addresses list

⚠️ 本チュートリアルで使用している外部HTTP(S)ロードバランサーの前提条件として、グローバルIPアドレスを作成する必要があります。

💵 グローバル静的IPアドレスは、プレミアムネットワークサービスティアでのみ利用可能であり、エフェメラルおよび標準パブリックIPアドレスよりも高価です。

🔰 Google Cloudのネットワークサービスティアの詳細については、こちらをご覧ください。

🔰 Google Cloudでの静的外部IPアドレスのリザーブの詳細については、こちらをご覧ください。

最後に、IPアドレスを環境変数に保存して、後で使用します。以下のコマンドでIPアドレスを表示します。

gcloud compute addresses describe web-ip --format='value(address)' --global

次に、出力をコピーして環境変数に保存します。

export IP_ADDRESS=198.51.100.1 # Replace with your IP address

4. ウェブサイトのドメイン名を作成する

ウェブサイトにはドメイン名が必要であり、Let's EncryptはSSL証明書に署名する前にドメインを確認するため、ドメイン名はインターネットからアクセス可能である必要があります。

クレジットカードを使用して安価なドメイン名を購入します。https://domains.google.comにアクセスし、検索ボックスに何かを入力します。例として、デプロイする例となるコンテナの名前がhello-appであるため、hello-app.comを検索しました。最も重要なのは、ドメイン名を価格でソートすることです。

hello-app.comは2,800ドルと高価なので選択せず、最上位のheyapp.netを選択します。良さそうですね!次に、カートボタンをクリックします。次の画面で、自動更新を無効にします。毎年このドメインの料金を支払いたくないからです。

ドメイン名が分かったら、それを環境変数に保存します。

export DOMAIN_NAME=heyapp.net

次に、上記で作成したIPアドレスをポイントする新しいAレコードを作成する必要があります。https://domains.google.com/registrarに戻り、ドメイン(ここではheyapp.net)を開き、左側のメニューで「DNS」をクリックします。「カスタムレコード」が表示されます。タイプAの新しいレコードを追加し、「データ」に前の手順のIPアドレスを入力します。最上位ドメイン名を構成しているので、「ホスト名」は空のままにしておく必要があります。

🔰 Cloudflare DNSチュートリアルのDNS Aレコードとは?についてはこちらをご覧ください。

ℹ️ ウェブサイトのドメイン名を作成することは必須ではありません。IPアドレスを使用して接続し、後でドメイン名ではなくIPアドレスのSSL証明書を作成できます。何らかの理由でドメイン名を作成できない場合は、このセクションをスキップして、以下の手順をIPアドレスを使用するように適応できます。

ℹ️ すべてのGoogle Cloudアドレスには、51.159.120.34.bc.googleusercontent.comのような自動生成されたリバースDNS名が付いていますが、親ドメインgoogleusercontent.comにはCAAレコードがあり、Let's Encryptがサブドメインの証明書に署名することを防ぎます。Let's EncryptのドキュメントのCertificate Authority Authorization (CAA)を参照してください。

5. Ingressを作成する

まだウェブサイトにアクセスできません。ウェブサーバーはKubernetesクラスタ内で実行されていますが、インターネットクライアントが接続できるルートまたはプロキシはまだありません!ここで、Kubernetes Ingressオブジェクトを作成します。Google Cloudでは、これにより、インターネットクライアントがKubernetesクラスタ内で実行されているウェブサーバーにアクセスできるようにする、さまざまなサービスが作成されます。

最初に、SSLレイヤーを追加する前に基本的な接続をテストできるように、HTTP(HTTPSではない)Ingressを作成します。

ingress.yamlというファイルに以下のYAMLをコピーして適用します。

# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
annotations:
# This tells Google Cloud to create an External Load Balancer to realize this Ingress
kubernetes.io/ingress.class: gce
# This enables HTTP connections from Internet clients
kubernetes.io/ingress.allow-http: "true"
# This tells Google Cloud to associate the External Load Balancer with the static IP which we created earlier
kubernetes.io/ingress.global-static-ip-name: web-ip
spec:
defaultBackend:
service:
name: web
port:
number: 8080
kubectl apply -f ingress.yaml

これにより、前に作成したIPアドレスに関連付けられたGoogle HTTP(S)ロードバランサーが作成されます。進行状況と作成されているリソースを確認できます。

kubectl describe ingress web-ingress

4〜5分以内に、すべてのロードバランサーコンポーネントの準備が整い、DNS名に接続して、前にデプロイしたhello-worldウェブサーバーからの応答を確認できるようになります。

curl http://$DOMAIN_NAME

出力例

Hello, world!
Version: 1.0.0
Hostname: web-79d88c97d6-t8hj2

この時点で、クラスタ内のPodで実行されているhello-worldウェブサーバーにHTTPトラフィックを転送するGoogleロードバランサーができました。

⏲ ロードバランサーコンポーネントの作成と構成、およびインターネットクライアントへのウェブサーバーのルーティングには、4〜5分かかります。時間がかかる場合は、トラブルシューティングセクションを参照してください。

🔰 Ingressアノテーションを使用したHTTP(S)ロードバランサーへの静的IPアドレスの使用方法についてはこちらをご覧ください。

🔰 GKEの外部Ingressアノテーションの概要についてはこちらをご覧ください。

🔰 GKEでの外部HTTP(S)ロードバランシングによるIngressのトラブルシューティングについてはこちらをご覧ください。

ℹ️ GKE Ingressには、gceクラスとgce-internalクラスの2つのIngressクラスがあります。gceクラスは外部ロードバランサーをデプロイし、gce-internalクラスは内部ロードバランサーをデプロイします。クラスを指定せずにIngressリソースを作成すると、デフォルトでgceになります。

⚠️ Kubernetes Ingressのドキュメントとは異なり、Ingress.Spec.IngressClassNameフィールドではなく、kubernetes.io/ingress.classアノテーションを使用する必要があります。ingress-gce #1301ingress-gce #1337を参照してください。

6. cert-managerをインストールする

いよいよ、ウェブサイトのSSL証明書の作成を開始する準備ができました。最初に、cert-managerをインストールする必要があります。以下のようにkubectlを使用して簡単にインストールします。

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.1/cert-manager.yaml

これにより、3つのDeploymentと、cert-managerという新しい名前空間にある多数のServiceとPodが作成されます。また、RBACロールやカスタムリソース定義など、さまざまなクラスタスコープのサポートリソースもインストールされます。

インストールされたリソースの一部は、次のように表示できます。

kubectl -n cert-manager get all

そして、以下のようにkubectl explainを使用して、カスタムリソース定義(cert-managerのAPI)を調べることができます。

kubectl explain Certificate
kubectl explain CertificateRequest
kubectl explain Issuer

🔰 cert-managerのその他のインストール方法についてはこちらをご覧ください。

🔰 証明書と発行者の詳細についてはこちらをご覧ください。

7. Let's Encryptステージング用の発行者を作成する

発行者は、証明書に署名する方法をcert-managerに指示するカスタムリソースです。この場合、発行者はLet's Encryptステージングサーバーに接続するように構成され、ドメイン名のLet's Encrypt証明書のクォータを使い果たすことなく、すべてをテストできます。

ℹ️ Let's Encryptは、Automatic Certificate Management Environment(ACME)プロトコルを使用しているため、以下の構成はacmeというキーの下にあります。

issuer-lets-encrypt-staging.yamlというファイルに以下のコンテンツを保存し、emailフィールドをメールアドレスに変更して適用します。

# issuer-lets-encrypt-staging.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-staging
spec:
acme:
server: https://acme-staging-v02.api.letsencrypt.org/directory
email: <email-address> # ❗ Replace this with your email address
privateKeySecretRef:
name: letsencrypt-staging
solvers:
- http01:
ingress:
name: web-ingress
kubectl apply -f issuer-lets-encrypt-staging.yaml

ℹ️ メールアドレスは、Let's Encryptが期限切れの30日前に証明書の更新を通知するためにのみ使用されます。cert-managerで証明書の更新中に問題が発生した場合にのみ、このメールを受け取ります。

発行者のステータスを確認できます。

kubectl describe issuers.cert-manager.io letsencrypt-staging

出力例

Status:
Acme:
Last Registered Email: firstname.lastname@example.com
Uri: https://acme-staging-v02.api.letsencrypt.org/acme/acct/60706744
Conditions:
Last Transition Time: 2022-07-13T16:13:25Z
Message: The ACME account was registered with the ACME server
Observed Generation: 1
Reason: ACMEAccountRegistered
Status: True
Type: Ready

ℹ️ Let's Encrypt本番発行者には、非常に厳格なレート制限があります。実験や学習をしていると、これらの制限に簡単に達することがあります。そのため、Let's Encryptステージング発行者から始め、問題なく動作することを確認したら、本番発行者に切り替えます。

⚠️ 次の手順では、ステージング発行者から開始するため、信頼されていない証明書に関する警告が表示されますが、これは完全に予想されることです。

🔰 ACME発行者の構成の詳細についてはこちらをご覧ください。

8. SSL用にIngressを再構成する

前にIngressを作成し、HTTPを使用してウェブサーバーに接続できることを確認しました。ここでは、そのIngressをHTTPS用に再構成します。

まず、Google Cloud Ingressコントローラーの問題を回避するための簡単な方法として、SSL証明書の空のシークレットを**Ingressの再構成の前に**作成して適用します。

# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: web-ssl
type: kubernetes.io/tls
stringData:
tls.key: ""
tls.crt: ""
kubectl apply -f secret.yaml

ℹ️ これは、ingress-gceコントローラーが、最終的にSSL証明書を含むシークレットを最初に検出しない限り、転送ルールを更新しないという、鶏と卵の問題に対する回避策です。しかし、Let's Encryptは、cert-managerがIngressに追加し、ingress-gceコントローラーによってGoogle Cloud転送ルールに変換される必要がある特別な.../.well-known/acme-challenge/...URLを取得しない限り、SSL証明書に署名しません。

🔰 Kubernetesシークレットとその使用方法の詳細についてはこちらをご覧ください。

ここで、Ingressに変更を加えて適用します。

--- a/ingress.yaml
+++ b/ingress.yaml
@@ -7,7 +7,12 @@ metadata:
kubernetes.io/ingress.class: gce
kubernetes.io/ingress.allow-http: "true"
kubernetes.io/ingress.global-static-ip-name: web-ip
+ cert-manager.io/issuer: letsencrypt-staging
spec:
+ tls:
+ - secretName: web-ssl
+ hosts:
+ - $DOMAIN_NAME
defaultBackend:
service:
name: web
kubectl apply -f ingress.yaml

これにより、完了までに数分かかる可能性のある複雑な一連の操作がトリガーされます。これらの手順の一部は2〜3分かかりますが、最初は失敗する可能性があります。cert-managerとingress-gce(Google Cloud Ingressコントローラー)は定期的に再調整されるため、最終的にはすべて成功するはずです。

最終的に、すべてのピースが揃ったら、curl を使用してウェブサイトへの HTTPS 接続を確認できるようになります。

curl -v --insecure https://$DOMAIN_NAME

HTTPS接続が確立されているが、SSL証明書が信頼されていないことがわかります。そのため、この段階では--insecureフラグを使用します。

出力例

* Server certificate:
* subject: CN=www.example.com
* start date: Jul 14 08:52:29 2022 GMT
* expire date: Oct 12 08:52:28 2022 GMT
* issuer: C=US; O=(STAGING) Let's Encrypt; CN=(STAGING) Artificial Apricot R3
* SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.

⏲ SSL証明書が署名され、Google Cloudロードバランサーによって読み込まれるまで、5~10分待つ必要があります。時間がかかる場合は、トラブルシューティングセクションを参照してください。

ℹ️ アノテーションcert-manager.io/issuer: letsencrypt-stagingを追加すると、cert-manager ingress-shimの注意を引くIngressに印が付けられ、以前に作成した発行者を参照する新しい証明書が作成されます。

🔰 詳細については、Ingressリソースの保護をお読みください。

🔰 GKEでIngressに証明書を指定する方法については、こちらをご覧ください。

9. 本番環境対応のSSL証明書の作成

Let's Encryptステージングサーバーで全てが動作するようになったので、本番サーバーに切り替えて、信頼できるSSL証明書を取得できます。

Let's Encrypt本番発行者を作成して適用します。

# issuer-lets-encrypt-production.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-production
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: <email-address> # ❗ Replace this with your email address
privateKeySecretRef:
name: letsencrypt-production
solvers:
- http01:
ingress:
name: web-ingress
kubectl apply -f issuer-lets-encrypt-production.yaml

次に、本番発行者を使用するようにIngressアノテーションを更新します。

kubectl annotate ingress web-ingress cert-manager.io/issuer=letsencrypt-production --overwrite

これにより、cert-managerはLet's Encrypt本番CAによって署名された新しいSSL証明書を取得し、web-sslシークレットに格納します。約10分以内に、この新しい証明書がGoogle Cloudロードバランサーに同期され、安全なHTTPSを使用してウェブサイトに接続できるようになります。

curl -v https://$DOMAIN_NAME

出力例

...
* Server certificate:
* subject: CN=www.example.com
* start date: Jul 14 09:44:29 2022 GMT
* expire date: Oct 12 09:44:28 2022 GMT
* subjectAltName: host "www.example.com" matched cert's "www.example.com"
* issuer: C=US; O=Let's Encrypt; CN=R3
* SSL certificate verify ok.
...
Hello, world!
Version: 1.0.0
Hostname: web-79d88c97d6-t8hj2

また、エラーや警告なしに、ウェブブラウザでhttps://$DOMAIN_NAMEにアクセスすることもできます。

これでチュートリアルは終了です。cert-managerがKubernetes IngressとクラウドIngressコントローラーとどのように統合されるかを理解しました。cert-managerを使用して無料のLet's Encrypt SSL証明書を取得する方法を学びました。そして、証明書がクラウドベースのロードバランサーによってどのように使用され、インターネットクライアントからのSSL接続を終了し、HTTPSリクエストをKubernetesクラスタで実行されているウェブサーバーに転送するかを確認しました。

💵 このチュートリアルで作成したすべてのリソースを削除し、クラウド料金を削減する方法については、クリーンアップセクションをお読みください。

🔰 このチュートリアルで説明されている手順で問題が発生した場合は、トラブルシューティングセクションをお読みください。

クリーンアップ

チュートリアルを完了したら、次の手順に従って、クラスタ、ドメイン名、静的IPアドレスを削除してクリーンアップできます。

# Delete the cluster and all the Google Cloud resources related to the Ingress that it contains
gcloud container clusters delete $CLUSTER
# Delete the domain name
gcloud dns record-sets delete $DOMAIN_NAME --zone $ZONE --type A
# Delete the static IP address
gcloud compute addresses delete web-ip --global

トラブルシューティング

このチュートリアルでIngressオブジェクトを作成または更新すると、多くの時間がかかる可能性のある一連の複雑な操作がトリガーされます。これらの手順の中には、2〜3分かかり、最初は失敗するものの、cert-managerまたはGoogle Ingressコントローラーが再調整されると、後で成功するものもあります。簡単に言うと、Ingressを作成または変更した後5〜10分待って、kubectl describe ingress web-ingressを実行したときにいくつかのエラーや警告が表示されることを期待する必要があります。

cert-managerとingress-gce(Google Cloud Ingressコントローラー)によって実行される操作の概要を次に示します。

  • cert-managerはLet's Encryptに接続し、SSL証明書の署名要求を送信します。
  • Let's Encryptは、「チャレンジ」で応答します。これは、cert-managerがターゲットウェブサイトの既知の場所に利用可能にする必要がある一意のトークンです。これは、そのウェブサイトとドメイン名の管理者であることを証明します。
  • cert-managerは、Let's Encryptチャレンジトークンを提供する一時的なWebサーバーを含むPodをデプロイします。
  • cert-managerは、Let's Encryptからのリクエストをその一時的なWebサーバーにルーティングするruleを追加して、Ingressを再構成します。
  • Google Cloud Ingressコントローラーはその新しいルールを使用して外部HTTPロードバランサーを再構成します。
  • Let's Encryptは接続し、期待されるチャレンジトークンを受信し、SSL証明書に署名してcert-managerに戻します。
  • cert-managerは、署名されたSSL証明書をweb-sslという名前のKubernetesシークレットに格納します。
  • Google Cloud Ingressコントローラーは、署名された証明書と関連する秘密鍵をGoogle Cloud証明書にアップロードします。
  • Google Cloud Ingressコントローラーは、アップロードされたSSL証明書を提供するように外部ロードバランサーを再構成します。

Ingressと関連イベントの確認

kubectl describeを使用して、Ingress構成と関連するすべてのイベントを表示します。IPアドレスが正しいこと、TLSとHostのエントリがウェブサイトに選択したドメイン名と一致することを確認します。ingress-gceは、管理するGoogle Cloudコンポーネントごとにイベントを作成することに注意してください。また、これらのコンポーネントのIDを参照するアノテーションを追加することもあります。cert-managerも、Ingressオブジェクトを調整するときにイベントを作成し、作成したIngressのCertificateオブジェクトの詳細を含めます。

$ kubectl describe ingress web-ingress
Name: web-ingress
Labels: <none>
Namespace: default
Address: 34.120.159.51
Ingress Class: <none>
Default backend: web:8080 (10.52.0.13:8080)
TLS:
web-ssl terminates www.example.com
Rules:
Host Path Backends
---- ---- --------
* * web:8080 (10.52.0.13:8080)
Annotations: cert-manager.io/issuer: letsencrypt-staging
ingress.kubernetes.io/backends: {"k8s1-01784147-default-web-8080-1647ccd2":"HEALTHY"}
ingress.kubernetes.io/forwarding-rule: k8s2-fr-1lt9dzcy-default-web-ingress-yteotwe4
ingress.kubernetes.io/https-forwarding-rule: k8s2-fs-1lt9dzcy-default-web-ingress-yteotwe4
ingress.kubernetes.io/https-target-proxy: k8s2-ts-1lt9dzcy-default-web-ingress-yteotwe4
ingress.kubernetes.io/ssl-cert: k8s2-cr-1lt9dzcy-4gjeakdb9n7k6ls7-a257650b5fefd174
ingress.kubernetes.io/target-proxy: k8s2-tp-1lt9dzcy-default-web-ingress-yteotwe4
ingress.kubernetes.io/url-map: k8s2-um-1lt9dzcy-default-web-ingress-yteotwe4
kubernetes.io/ingress.allow-http: true
kubernetes.io/ingress.class: gce
kubernetes.io/ingress.global-static-ip-name: web-ip
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CreateCertificate 28m cert-manager-ingress-shim Successfully created Certificate "web-ssl"
Normal Sync 28m loadbalancer-controller UrlMap "k8s2-um-1lt9dzcy-default-web-ingress-yteotwe4" updated
Warning Sync 24m (x16 over 28m) loadbalancer-controller Error syncing to GCP: error running load balancer syncing routine: loadbalancer 1lt9dzcy-default-web-ingress-yteotwe4 does not exist: googleapi: Error 404: The resource 'projects/your-project/global/sslCertificates/k8s2-cr-1lt9dzcy-4gjeakdb9n7k6ls7-e3b0c44298fc1c14' was not found, notFound
Normal Sync 34s (x16 over 65m) loadbalancer-controller Scheduled for sync

cmctlを使用して、証明書とその関連リソースの状態を表示する

ℹ️ まだインストールしていない場合は、 cmctlをインストールしてください。

証明書を作成すると、cert-managerは、それぞれに証明書の署名プロセスの状態に関する情報が含まれている一時的なリソースのコレクションを作成します。これらについては、証明書ライフサイクルセクションで詳しく説明しています。cmctl statusコマンドを使用して、これらのすべてのリソースと関連するすべてのイベントとエラーメッセージの詳細を表示します。

次のような一時的なエラーが表示される場合があります。

$ cmctl status certificate web-ssl
Name: web-ssl
Namespace: default
Created at: 2022-07-14T17:30:06+01:00
Conditions:
Ready: False, Reason: MissingData, Message: Issuing certificate as Secret does not contain a private key
Issuing: True, Reason: MissingData, Message: Issuing certificate as Secret does not contain a private key
DNS Names:
- www.example.com
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Issuing 4m37s cert-manager-certificates-trigger Issuing certificate as Secret does not contain a private key
Normal Generated 4m37s cert-manager-certificates-key-manager Stored new private key in temporary Secret resource "web-ssl-8gsqc"
Normal Requested 4m37s cert-manager-certificates-request-manager Created new CertificateRequest resource "web-ssl-dblrj"
Issuer:
Name: letsencrypt-staging
Kind: Issuer
Conditions:
Ready: True, Reason: ACMEAccountRegistered, Message: The ACME account was registered with the ACME server
Events: <none>
error: 'tls.crt' of Secret "web-ssl" is not set
Not Before: <none>
Not After: <none>
Renewal Time: <none>
CertificateRequest:
Name: web-ssl-dblrj
Namespace: default
Conditions:
Approved: True, Reason: cert-manager.io, Message: Certificate request has been approved by cert-manager.io
Ready: False, Reason: Pending, Message: Waiting on certificate issuance from order default/web-ssl-dblrj-327645514: "pending"
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal cert-manager.io 4m37s cert-manager-certificaterequests-approver Certificate request has been approved by cert-manager.io
Normal OrderCreated 4m37s cert-manager-certificaterequests-issuer-acme Created Order resource default/web-ssl-dblrj-327645514
Normal OrderPending 4m37s cert-manager-certificaterequests-issuer-acme Waiting on certificate issuance from order default/web-ssl-dblrj-327645514: ""
Order:
Name: web-ssl-dblrj-327645514
State: pending, Reason:
Authorizations:
URL: https://acme-staging-v02.api.letsencrypt.org/acme/authz-v3/3008789144, Identifier: www.example.com, Initial State: pending, Wildcard: false
Challenges:
- Name: web-ssl-dblrj-327645514-2671694319, Type: HTTP-01, Token: TKspp86xMjQzTvMVXWkezEA2sE2GSWjnld5Lt4X13ro, Key: TKspp86xMjQzTvMVXWkezEA2sE2GSWjnld5Lt4X13ro.f4bppCOm-jXasFGMKjpBE5aQlhiQBeTPIs0Lx822xao, State: pending, Reason: Waiting for HTTP-01 challenge propagation: did not get expected response when querying endpoint, expected "TKspp86xMjQzTvMVXWkezEA2sE2GSWjnld5Lt4X13ro.f4bppCOm-jXasFGMKjpBE5aQlhiQBeTPIs0Lx822xao" but got: Hello, world!
Version: 1... (truncated), Processing: true, Presented: true

これは、cert-managerが、一時的なチャレンジWebサーバーが予想されるURLで到達可能かどうかを確認するための事前チェックを実行しているためです。最初は到達できません。cert-managerは一時的なWebサーバーのデプロイに時間がかかり、Ingressコントローラーは新しいHTTPルーティングルールの設定に時間がかかるためです。最終的には、証明書が準備完了になり、署名されていることがわかります。

$ cmctl status certificate web-ssl
Name: web-ssl
Namespace: default
Created at: 2022-07-14T17:30:06+01:00
Conditions:
Ready: True, Reason: Ready, Message: Certificate is up to date and has not expired
DNS Names:
- www.example.com
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Issuing 31m cert-manager-certificates-trigger Issuing certificate as Secret does not contain a private key
Normal Generated 31m cert-manager-certificates-key-manager Stored new private key in temporary Secret resource "web-ssl-8gsqc"
Normal Requested 31m cert-manager-certificates-request-manager Created new CertificateRequest resource "web-ssl-dblrj"
Normal Issuing 26m cert-manager-certificates-issuing The certificate has been successfully issued
Issuer:
Name: letsencrypt-staging
Kind: Issuer
Conditions:
Ready: True, Reason: ACMEAccountRegistered, Message: The ACME account was registered with the ACME server
Events: <none>
Secret:
Name: web-ssl
Issuer Country: US
Issuer Organisation: (STAGING) Let's Encrypt
Issuer Common Name: (STAGING) Artificial Apricot R3
Key Usage: Digital Signature, Key Encipherment
Extended Key Usages: Server Authentication, Client Authentication
Public Key Algorithm: RSA
Signature Algorithm: SHA256-RSA
Subject Key ID: a51e3621f5c1138947810f27dce425b33c88cb16
Authority Key ID: de727a48df31c3a650df9f8523df57374b5d2e65
Serial Number: fa8bb0b603ca2cdbfdfb2872d05ee52cda10
Events: <none>
Not Before: 2022-07-14T16:34:52+01:00
Not After: 2022-10-12T16:34:51+01:00
Renewal Time: 2022-09-12T16:34:51+01:00

SSL証明書がGoogle Cloudにコピーされていることを確認する

cert-managerが署名された証明書を受け取ると、web-sslシークレットに格納され、これによりGoogle Cloud IngressコントローラーがそのSSL証明書をGoogle Cloudにコピーするようにトリガーされます。gcloudコマンドを使用して、証明書を確認できます。

$ gcloud compute ssl-certificates list
NAME TYPE CREATION_TIMESTAMP EXPIRE_TIME MANAGED_STATUS
k8s2-cr-1lt9dzcy-4gjeakdb9n7k6ls7-a257650b5fefd174 SELF_MANAGED 2022-07-14T09:37:06.920-07:00 2022-10-12T08:34:51.000-07:00

そして、その内容を表示し、属性を確認することができます。

$ gcloud compute ssl-certificates describe k8s2-cr-1lt9dzcy-4gjeakdb9n7k6ls7-a257650b5fefd174 --format='value(certificate)' \
| openssl x509 -in - -noout -text
...
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
04:9f:47:f1:cb:25:37:9b:86:a3:ef:bf:2e:77:3b:45:fc:1a
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, O = Let's Encrypt, CN = R3
Validity
Not Before: Jul 14 17:11:15 2022 GMT
Not After : Oct 12 17:11:14 2022 GMT
Subject: CN = www.example.com

Google Cloud転送ルールの確認

IngressオブジェクトにTLS節を追加した後、最終的にSSL接続の転送ルールが表示されます。

$ gcloud compute forwarding-rules describe k8s2-fs-1lt9dzcy-default-web-ingress-yteotwe4 --global
IPAddress: 34.120.159.51
IPProtocol: TCP
creationTimestamp: '2022-07-14T09:37:12.362-07:00'
description: '{"kubernetes.io/ingress-name": "default/web-ingress"}'
fingerprint: oBTg7dRaIqI=
id: '2303318464959215831'
kind: compute#forwardingRule
labelFingerprint: 42WmSpB8rSM=
loadBalancingScheme: EXTERNAL
name: k8s2-fs-1lt9dzcy-default-web-ingress-yteotwe4
networkTier: PREMIUM
portRange: 443-443
selfLink: https://www.googleapis.com/compute/v1/projects/your-project/global/forwardingRules/k8s2-fs-1lt9dzcy-default-web-ingress-yteotwe4
target: https://www.googleapis.com/compute/v1/projects/your-project/global/targetHttpsProxies/k8s2-ts-1lt9dzcy-default-web-ingress-yteotwe4