Kubernetes環境での証明書管理を自動化する

原著者: Jason Schmidt - F5 NGINX ソリューション アーキテクト

元のリンク: Kubernetes 環境での証明書管理の自動化

転載元:NGINX中国語公式サイト


NGINX の唯一の公式中国語コミュニティ (すべてnginx.org.cn )

有効な SSL/TLS 証明書は、最新のアプリケーション環境の中核となる要件です。残念ながら、証明書の更新管理は、アプリケーションを展開する際に見落とされがちです。証明書の有効期間は制限されており、長さも異なります。DigiCert証明書は約 13 か月、Let's Encrypt 証明書は 90 日間有効です安全なアクセスを確保するには、これらの証明書は有効期限が切れる前に更新/再発行する必要があります。ほとんどの運用チームの負荷が高いため、証明書の更新が保留されることがあり、証明書の有効期限が近づくと (またはさらに悪いことに)、証明書の管理に追われることになります。

実際、そうである必要はありません。証明書の管理は、少しの計画と準備で簡素化および自動化できます。ここでは、次の 3 つのテクノロジーを使用した Kubernetes 環境向けのソリューションを紹介します。

この記事では、自動的に更新される証明書をエンドポイントに提供することで証明書管理を簡素化する方法を説明します。

Kubernetes 環境での証明書

技術的な詳細について説明する前に、いくつかの用語を定義する必要があります。「TLS 証明書」とは、Ingress コントローラーで HTTPS 接続を有効にするために必要な 2 つのコンポーネントを指します。

  1. 証明書

  2. 秘密鍵

証明書と秘密鍵は両方ともLet's Encryptによって発行されます。TLS 証明書の仕組みの詳細については、DigiCert の記事「TLS/SSL 証明書の仕組み」を参照してください。

Kubernetes では、これら 2 つのコンポーネントはSecretとして保存されます。NGINX Ingress Controllercert-managerなどの Kubernetes ワークロードは、これらのシークレットの書き込みと読み取りが可能であり、Kubernetes インストールへのアクセス権を持つユーザーが管理することもできます。

証明書マネージャーの概要

cert-managerプロジェクトは、Kubernetes および OpenShift で動作する証明書コントローラーです。Kubernetes にデプロイされると、cert-manager は Ingress コントローラーに必要な証明書を自動的に発行し、それらが有効で最新であることを確認します。さらに、証明書の有効期限を追跡し、設定された間隔で更新を試みます。これは多数の公的および民間の認証局と連携しますが、ここでは Let's Encrypt との統合についてのみ説明します。

2つのチャレンジタイプ

Let's Encrypt を使用すると、すべての証明書管理を自動化できます。これは非常に便利ですが、サービスは完全修飾ドメイン名 (FQDN) をどのようにして確保するのでしょうか?という疑問も生じます。

この問題は、特定のドメイン名の DNS レコードにアクセスできるユーザーのみが開始できる検証リクエストに答える必要があるチャレンジを使用して解決できます。チャレンジは次の 2 つの形式のいずれかをとります。

  1. HTTP-01 : この課題は、証明書の発行先となる FQDN の DNS レコードを作成することで解決できます。たとえば、サーバーの IP が www.xxx.yyy.zzz で、FQDN が cert.example.com の場合、チャレンジ メカニズムにより www.xxx.yyy.zzz のサーバー上のトークンが公開されます。Let's The Encryptサーバーは cert.example.com を通じてトークンへのアクセスを試みます。成功した場合、チャレンジは成功し、証明書が発行されます。

HTTP-01 は、DNS プロバイダーに直接アクセスする必要がないため、証明書を生成する最も簡単な方法です。このタイプのチャレンジは、常に HTTP 80 でサポートされる DNS ポート経由で実行されます。HTTP-01 チャレンジを使用する場合、cert-manager は Ingress コントローラーを利用してチャレンジ トークンを提供することに注意してください。

  1. DNS-01 : このチャレンジでは、トークンを使用して DNS TXT レコードを作成し、その後、当局によって検証されます。トークンが認識されると、ドメイン名の所有権があることが証明され、その記録用の証明書がすぐに発行されます。HTTP-01 チャレンジとは異なり、DNS-01 チャレンジを使用する場合、FQDN はサーバーの IP アドレスに解決される必要はありません (存在すらしません)。さらに、ポート 80 がブロックされている場合は、DNS-01 を使用できます。不便な点は、cert-manager によってインストールされた API トークンへのアクセスを通じて DNS インフラストラクチャへのアクセスを提供する必要があることです。

イングレスコントローラー

Ingress コントローラーは Kubernetes のサービスであり、クラスターの外部からのトラフィックの導入、内部ポッド(単一または複数のコンテナーのグループ) へのトラフィックの負荷分散、および送信アウトバウンド トラフィックの管理に特に使用されます。さらに、Ingress コントローラーは Kubernetes API を通じて制御され、ポッドが追加、削除されるか、ポッドが失敗すると、ロード バランシング設定を監視して更新します。

Ingress コントローラーの詳細については、次のブログを参照してください。

次の例では、F5 NGINX によって開発および保守されている NGINX Ingress コントローラーを使用します。

証明書管理例

これらの例では、外部 IP アドレス (Kubernetes LoadBalancer オブジェクト) を割り当てることができる、テスト用に動作する Kubernetes インストールがあることを前提としています。さらに、ポート 80 と 443 (HTTP-01 チャレンジを使用する場合)、またはポート 443 のみ (DNS-01 チャレンジを使用する場合) でトラフィックを受信できることを前提としています。これらの例は Mac OS X を使用して示されていますが、Linux または WSL も使用できます。

A レコードを調整できるようにする DNS プロバイダーと FQDN も必要です。HTTP-01 チャレンジを使用する場合、必要なのは A レコードを追加することだけです (または、代わりに誰かに A レコードを追加してもらいます)。DNS-01 チャレンジを使用する場合は、サポートされている DNS プロバイダーまたはサポートされているWebhook プロバイダーへのAPI アクセスが必要です。

NGINX Ingress コントローラーをデプロイする

最も簡単な方法は、Helm経由でデプロイすることです。このデプロイメントにより、Kubernetes Ingress と NGINX 仮想サーバー CRD を同時に使用できるようになります。

  1. NGINX リポジトリを追加します。

$ helm repo add nginx-stable https://helm.nginx.com/stable
  "nginx-stable" has been added to your repositories 

2. ウェアハウスを更新します。

$ helm repo update
  Hang tight while we grab the latest from your chart repositories...
  ...Successfully got an update from the "nginx-stable" chart repository
  Update Complete. ⎈Happy Helming!⎈ 

3. Ingress コントローラーをデプロイします。

$ helm install nginx-kic nginx-stable/nginx-ingress \
  --namespace nginx-ingress  --set controller.enableCustomResources=true \ 
  --create-namespace  --set controller.enableCertManager=true 
  NAME: nginx-kic
  LAST DEPLOYED: Thu Sep  1 15:58:15 2022
  NAMESPACE: nginx-ingress
  STATUS: deployed
  REVISION: 1
  TEST SUITE: None
  NOTES:
  The NGINX Ingress Controller has been installed. 

4. 導入を確認し、Ingress コントローラーに接続されている出力の IP アドレスを取得します。有効な IP アドレスがないと続行できないことに注意してください。

$ kubectl get deployments --namespace nginx-ingress
  NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
  nginx-kic-nginx-ingress   1/1     1            1           23s
  $ kubectl get services --namespace nginx-ingress
  NAME                      TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)                      AGE
  nginx-kic-nginx-ingress   LoadBalancer   10.128.60.190   www.xxx.yyy.zzz   80:31526/TCP,443:32058/TCP   30s 

DNS Aレコードを追加する

正確なプロセスは DNS プロバイダーによって異なります。この DNS 名は Let's Encrypt サーバーから解決できる必要があり、レコードが伝播されるまで待つ必要がある場合があります。これについての詳細は、SiteGround の記事「DNS 伝播とは何か、そしてなぜそんなに時間がかかるのか?」を参照してください。

 

選択した FQDN を解決できる場合は、次のステップに進むことができます。

$ host cert.example.com
  cert.example.com has address www.xxx.yyy.zzz

証明書マネージャーをデプロイする

次のステップは、cert-manager の最新バージョンをデプロイすることです。繰り返しますが、デプロイメントには Helm を使用します。

  1. Helm リポジトリを追加します。

$ helm repo add jetstack https://charts.jetstack.io
  "jetstack" has been added to your repositories 

2. ウェアハウスを更新します。

$ helm repo update
  Hang tight while we grab the latest from your chart repositories...
  ...Successfully got an update from the "nginx-stable" chart repository
  ...Successfully got an update from the "jetstack" chart repository
  Update Complete. ⎈Happy Helming!⎈ 

3. 証明書マネージャーをデプロイします。

$ helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager --create-namespace \
  --version v1.9.1  --set installCRDs=true 
  NAME: cert-manager
  LAST DEPLOYED: Thu Sep  1 16:01:52 2022 
  NAMESPACE: cert-manager
  STATUS: deployed
  REVISION: 1 
  TEST SUITE: None
  NOTES:
  cert-manager v1.9.1 has been deployed successfully!
  In order to begin issuing certificates, you will need to set up a ClusterIssuer
  or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer).
  More information on the different types of issuers and how to configure them
  can be found in our documentation:
  Issuer Configuration
  For information on how to configure cert-manager to automatically provision
  Certificates for Ingress resources, take a look at the `ingress-shim`
  documentation:
  Securing Ingress Resources

4. 導入を確認します。

$ kubectl get deployments --namespace cert-manager
  NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
  cert-manager              1/1     1            1           4m30s
  cert-manager-cainjector   1/1     1            1           4m30s
  cert-manager-webhook      1/1     1            1           4m30s 

NGINX Cafe のサンプルをデプロイする

NGINX Cafe サンプルを使用して、バックエンドのデプロイメントとサービスを提供します。この例は、NGINX が提供するドキュメントで非常に一般的です。このプロセスでは、Ingress はデプロイされません。

  1. NGINX Ingress GitHub プロジェクトのクローンを作成します。

$ git clone https://github.com/nginxinc/kubernetes-ingress.git
  Cloning into 'kubernetes-ingress'...
  remote: Enumerating objects: 44979, done.
  remote: Counting objects: 100% (172/172), done.
  remote: Compressing objects: 100% (108/108), done.
  remote: Total 44979 (delta 87), reused 120 (delta 63), pack-reused 44807
  Receiving objects: 100% (44979/44979), 60.27 MiB | 27.33 MiB/s, done.
  Resolving deltas: 100% (26508/26508), done. 

2. サンプルディレクトリを入力します。このディレクトリには、Ingress コントローラーのさまざまな構成を示すいくつかの例が含まれています。ここでは、complete-example ディレクトリにあるサンプルを使用しています。

$ cd ./kubernetes-ingress/examples/ingress-resources/complete-example

3. NGINX Cafe サンプルをデプロイします。

$ kubectl apply -f ./cafe.yaml
  deployment.apps/coffee created
  service/coffee-svc created
  deployment.apps/tea created
  service/tea-svc created

4. kubectl get コマンドを使用して、デプロイメントとサービスを確認します。ポッドが READY と表示され、サービスが実行中と表示されていることを確認する必要があります。以下の例は、代表的なサンプルを示しています。kubernetes サービスはシステム サービスであり、NGINX Cafe の例 (デフォルト) と同じ名前空間で実行されることに注意してください。

$ kubectl get deployments,services  --namespace default
  NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
  deployment.apps/coffee   2/2     2            2           69s
  deployment.apps/tea      3/3     3            3           68s
NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
  service/coffee-svc   ClusterIP   10.128.154.225   <none>        80/TCP    68s
  service/kubernetes   ClusterIP   10.128.0.1       <none>        443/TCP   29m
	service/tea-svc      ClusterIP   10.128.96.145    <none>        80/TCP    68s 

デプロイクラスター発行者

cert-manager では、ClusterIssuer を使用して証明書を発行できます。これはクラスター全体のオブジェクトであり、任意の名前空間から参照でき、指定された認証局に対して行われる任意の証明書要求によって使用できます。この例では、Let's Encrypt 証明書に対するあらゆるリクエストをこの ClusterIssuer によって処理できます。

選択したチャレンジ タイプの ClusterIssuer をデプロイします。これはこの記事の範囲を超えていますが、高度な構成オプションを使用してClusterIssuer で複数のリゾルバー (セレクター フィールドに基づいて選択) を指定できることについて簡単に説明します。

ACME チャレンジの基本

Automated Certificate Management Environment (ACME) プロトコルを使用すると、ドメイン名を所有しているかどうか、つまり Let's Encrypt 証明書を発行できるかどうかを判断できます。このチャレンジでは、次のパラメータを渡す必要があります。

  • metadata.name: ClusterIssuer 名。Kubernetes インストール内で一意である必要があります。この名前は、後の証明書発行の例で使用します。

  • spec.acme.email: これは、証明書を生成するために Let's Encrypt に登録した電子メール アドレスです。これはあなたのメールアドレスであるはずです。

  • spec.acme.privateKeySecretRef: これは、秘密キーを保存するために使用する Kubernetes シークレットの名前です。spec.acme.solvers: これは変更しないでください。これは、使用しているチャレンジ タイプ (または ACME が呼ぶリゾルバー) (HTTP-01 または DNS-01) と、どのイングレス タイプに適用する必要があるかを示します (この場合、 nginxになります)。

HTTP-01を使用する

この例では、HTTP-01 チャレンジを使用してドメイン所有権を証明し、証明書を受け取るように ClusterIssuer を設定する方法を示します。

  1. ClusterIssuer を作成し、HTTP-01 チャレンジを使用します。

$ cat << EOF | kubectl apply -f 
  apiVersion: cert-manager.io/v1
  kind: ClusterIssuer
  metadata:
    name: prod-issuer
  spec:
    acme:
      email: [email protected]
      server: https://acme-v02.api.letsencrypt.org/directory
      privateKeySecretRef:
        name: prod-issuer-account-key
      solvers:
      - http01:
         ingress:
           class: nginx
  EOF
  clusterissuer.cert-manager.io/prod-issuer created 

2. ClusterIssuer を確認します (Ready と表示されるはずです)。

$ kubectl get clusterissuer
  NAME          READY   AGE
	prod-issuer   True    34s 

DNS-01を使用する

この例では、DNS-01 チャレンジを使用してドメイン名の所有権を確認するように ClusterIssuer を設定する方法を示します。特定の DNS プロバイダーによっては、トークンを保存するために Kubernetes Secret を使用する必要がある場合があります。この例ではCloudflareを使用します。名前空間の使用に注意してください。cert-manager 名前空間にデプロイされた cert-manager アプリケーションは、シークレットにアクセスする必要があります。

この例では、アカウントから作成できるCloudflare API トークン が必要です。これは、以下の <API Token> 行に配置する必要があります。Cloudflare を使用していない場合は、プロバイダーのドキュメントに従う必要があります

  1. API トークンのシークレットを作成します。

$ cat << EOF | kubectl apply -f 
  apiVersion: v1
  kind: Secret
  metadata:
    name: cloudflare-api-token-secret
    namespace: cert-manager
  type: Opaque
  stringData:
    api-token: <API Token> 
  EOF 

2. 発行局を作成し、DNS-01 チャレンジを使用します。

$ cat << EOF | kubectl apply -f 
  apiVersion: cert-manager.io/v1
  kind: ClusterIssuer
  metadata:
    name: prod-issuer
  spec:
    acme:
      email: [email protected]
      server: https://acme-v02.api.letsencrypt.org/directory
      privateKeySecretRef:
        name: prod-issuer-account-key
      solvers:
        - dns01:
            cloudflare:
              apiTokenSecretRef:
                name: cloudflare-api-token-secret
                key: api-token
  EOF 

3. 権限を確認します (準備完了と表示されるはずです)。

$ kubectl get clusterissuer
  NAME          READY   AGE
	prod-issuer   True    31m 

Ingress のデプロイ

上記の手順を完了すると、アプリケーションの Ingress リソースをデプロイできます。これにより、前にデプロイした NGINX Cafe アプリケーションにトラフィックがルーティングされます。

Kubernetes Ingress の使用

標準の Kubernetes Ingress リソースを使用する場合は、次のデプロイメント YAML を使用して Ingress を構成し、証明書を要求します。

apiVersion: networking.k8s.io/v1 
  kind: Ingress 
  metadata: 
    name: cafe-ingress 
    annotations: 
      cert-manager.io/cluster-issuer: prod-issuer 
      acme.cert-manager.io/http01-edit-in-place: "true" 
  spec: 
    ingressClassName: nginx 
    tls: 
    - hosts: 
      - cert.example.com 
      secretName: cafe-secret 
    rules: 
    - host: cert.example.com 
      http: 
        paths: 
        - path: /tea 
          pathType: Prefix 
          backend: 
            service: 
              name: tea-svc 
              port: 
                number: 80 
        - path: /coffee 
          pathType: Prefix 
          backend: 
            service: 
              name: coffee-svc 
              port: 
number: 80 

チェックリストの重要な部分をいくつか確認してください。

  • 呼び出される API は標準の Kubernetes Ingress です。

  • この構成の重要な部分は、metadata.annotations の下にあり、ここで acme.cert-manager.io/http01-edit-in-place を「true」に設定できます。この値は必須であり、課題の解決策を調整できます。詳細については、サポートされているアノテーションのドキュメントを参照してください。これは、マスター/ミニオンのセットアップを使用して処理することもできます

  • spec.ingressClassName は、インストールして使用する NGINX Ingress コントローラーを指します。

  • spec.tls.secret Kubernetes Secret リソースには、Let's Encrypt が証明書を発行するときに返される証明書キーが保存されます。

  • ホスト名 cert.example.com は spec.tls.hosts および spec.rules.host に指定されています。ClusterIssuer は、このホスト名の証明書を発行します。

  • spec.rules.http セクションでは、パスと、それらのパス上のリクエストを満たすバックエンド サービスを定義します。たとえば、/tea へのトラフィックは tea-svc のポート 80 に送信されます。

1. インストールに応じて上記のリストを変更します。少なくとも、spec.rules.host と spec.tls.hosts の値を変更する必要がありますが、構成内のすべてのパラメーターを確認することをお勧めします。

2. アプリケーションリスト。

$  kubectl apply -f ./cafe-virtual-server.yaml
  virtualserver.k8s.nginx.org/cafe created 

3. 証明書が発行されるまで待つと、READY フィールドの値が「True」に変わります。

$ kubectl get certificates
  NAME                                      READY   SECRET        AGE
  certificate.cert-manager.io/cafe-secret   True    cafe-secret   37m 

NGINX仮想サーバー/仮想ルーティングの使用

NGINX CRD を使用する場合は、次のデプロイメント YAML を使用して Ingress を構成する必要があります。

より実用的なコードについては、 NGINX コミュニティの公式 Web サイトをクリックして表示してください。

ビューの証明書

 

Kubernetes API を通じて証明書を表示できます。これにより、サイズや関連する秘密キーなど、証明書に関する詳細が表示されます。

$ kubectl describe secret cafe-secret
  Name:         cafe-secret
  Namespace:    default
  Labels:       <none>
  Annotations:  cert-manager.io/alt-names: cert.example.com
                cert-manager.io/certificate-name: cafe-secret
                cert-manager.io/common-name: cert.example.com
                cert-manager.io/ip-sans:
                cert-manager.io/issuer-group:
                cert-manager.io/issuer-kind: ClusterIssuer
                cert-manager.io/issuer-name: prod-issuer
                cert-manager.io/uri-sans:Type:  404 Page not found
  ====
  tls.crt:  5607 bytes
  tls.key:  1675 bytes 

実際の証明書とキーを確認するには、次のコマンドを実行します。(注: これにより、Kubernetes Secret の弱点が明らかになります。つまり、必要なアクセス権を持つ誰でも読み取ることができます)。

$ kubectl get secret cafe-secret -o yaml

テストイングレス

テスト証明書。ここでは任意の方法を使用できます。以下の例では cURL を使用しています。成功すると、サーバー名、サーバーの内部アドレス、日付、選択した URI (ルート) (コーヒーまたは紅茶)、リクエスト ID を含む、前に示したものと同様のコードが表示されます。失敗すると、HTTP エラー コード (おそらく 400 または 301) が生成されます。

$ curl https://cert.example.com/tea
  Server address: 10.2.0.6:8080
  Server name: tea-5c457db9-l4pvq
  Date: 02/Sep/2022:15:21:06 +0000
  URI: /tea
  Request ID: d736db9f696423c6212ffc70cd7ebecf
  $ curl https://cert.example.com/coffee
  Server address: 10.2.2.6:8080
  Server name: coffee-7c86d7d67c-kjddk
  Date: 02/Sep/2022:15:21:10 +0000
  URI: /coffee
Request ID: 4ea3aa1c87d2f1d80a706dde91f31d54 

証明書の更新

冒頭で、このアプローチにより証明書の更新を管理する必要がなくなると述べました。ただし、これを行う方法についてはまだ説明していません。なぜ?これは、cert-manager のコア組み込み部分であるためです。この自動プロセス中に、証明書が存在しないこと、期限切れになったこと、または 15 日以内に期限切れになりそうなことを認識した場合、またはユーザーが CLI 経由で新しい証明書を要求した場合、cert-manager は自動的に新しい証明書を要求します極めてシンプル。

よくある問題

どのチャレンジ タイプを使用すればよいですか?

これは主にユースケースによって異なります。

HTTP-01 チャレンジ方式では、ポート 80 がインターネットに対して開いており、DNS A レコードが Ingress コントローラーの IP アドレスに基づいて正しく構成されている必要があります。この方法では、A レコードの作成以外に DNS プロバイダーにアクセスする必要はありません。

ポート 80 をインターネットに公開できない場合は、DNS-01 チャレンジ方式を使用できます。この方式では、cert-manager に DNS プロバイダーへの出力アクセスが必要なだけです。ただし、この方法では DNS プロバイダーの API にアクセスできる必要があり、必要なアクセスのレベルは特定のプロバイダーによって異なります。

トラブルシューティングの方法は?

Kubernetes は複雑であるため、的を絞ったトラブルシューティング情報を提供することが難しい場合があります。問題が発生した場合は、 NGINX コミュニティの公式 WeChat グループでお問い合わせください(NGINX Plus ユーザーは通常のサポート オプションを使用できます)。


NGINX の唯一の公式中国語コミュニティ (すべてnginx.org.cn )

NGINX 関連のその他の技術情報、インタラクティブな Q&A、一連のコース、およびイベント リソース:オープンソース コミュニティ公式 Web サイト| WeChat 公式アカウント

IntelliJ IDEA 2023.3 と JetBrains Family Bucket の年次メジャー バージョン アップデート 新しいコンセプト「防御型プログラミング」: 安定した仕事に就く GitHub.com では 1,200 を超える MySQL ホストが稼働していますが、8.0 にシームレスにアップグレードするにはどうすればよいですか? Stephen Chow の Web3 チームは来月、独立したアプリをリリースする予定ですが、 Firefox は廃止されるのでしょうか? Visual Studio Code 1.85 がリリース、フローティング ウィンドウ 米国 CISA、メモリ セキュリティの脆弱性を排除するために C/C++ の放棄を推奨 余成東 : ファーウェイは来年破壊的製品を発売し、業界の歴史を書き換える TIOBE 12 月: C# は今年のプログラミング言語になると期待される 論文30年前にLei Junが書いた「コンピュータウイルス判定エキスパートシステムの原理と設計」
{{名前}}
{{名前}}

おすすめ

転載: my.oschina.net/u/5246775/blog/10114538