原著者: Jason Schmidt - F5 NGINX ソリューション アーキテクト
元のリンク: Kubernetes 環境での証明書管理の自動化
転載元:NGINX中国語公式サイト
NGINX の唯一の公式中国語コミュニティ (すべてnginx.org.cn )
有効な SSL/TLS 証明書は、最新のアプリケーション環境の中核となる要件です。残念ながら、証明書の更新管理は、アプリケーションを展開する際に見落とされがちです。証明書の有効期間は制限されており、長さも異なります。DigiCert証明書は約 13 か月、Let's Encrypt 証明書は 90 日間有効です。安全なアクセスを確保するには、これらの証明書は有効期限が切れる前に更新/再発行する必要があります。ほとんどの運用チームの負荷が高いため、証明書の更新が保留されることがあり、証明書の有効期限が近づくと (またはさらに悪いことに)、証明書の管理に追われることになります。
実際、そうである必要はありません。証明書の管理は、少しの計画と準備で簡素化および自動化できます。ここでは、次の 3 つのテクノロジーを使用した Kubernetes 環境向けのソリューションを紹介します。
-
Jetstack の証明書マネージャー
この記事では、自動的に更新される証明書をエンドポイントに提供することで証明書管理を簡素化する方法を説明します。
Kubernetes 環境での証明書
技術的な詳細について説明する前に、いくつかの用語を定義する必要があります。「TLS 証明書」とは、Ingress コントローラーで HTTPS 接続を有効にするために必要な 2 つのコンポーネントを指します。
-
証明書
-
秘密鍵
証明書と秘密鍵は両方ともLet's Encryptによって発行されます。TLS 証明書の仕組みの詳細については、DigiCert の記事「TLS/SSL 証明書の仕組み」を参照してください。
Kubernetes では、これら 2 つのコンポーネントはSecretとして保存されます。NGINX Ingress Controllerやcert-managerなどの Kubernetes ワークロードは、これらのシークレットの書き込みと読み取りが可能であり、Kubernetes インストールへのアクセス権を持つユーザーが管理することもできます。
証明書マネージャーの概要
cert-managerプロジェクトは、Kubernetes および OpenShift で動作する証明書コントローラーです。Kubernetes にデプロイされると、cert-manager は Ingress コントローラーに必要な証明書を自動的に発行し、それらが有効で最新であることを確認します。さらに、証明書の有効期限を追跡し、設定された間隔で更新を試みます。これは多数の公的および民間の認証局と連携しますが、ここでは Let's Encrypt との統合についてのみ説明します。
2つのチャレンジタイプ
Let's Encrypt を使用すると、すべての証明書管理を自動化できます。これは非常に便利ですが、サービスは完全修飾ドメイン名 (FQDN) をどのようにして確保するのでしょうか?という疑問も生じます。
この問題は、特定のドメイン名の DNS レコードにアクセスできるユーザーのみが開始できる検証リクエストに答える必要があるチャレンジを使用して解決できます。チャレンジは次の 2 つの形式のいずれかをとります。
-
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 コントローラーを利用してチャレンジ トークンを提供することに注意してください。
-
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 を同時に使用できるようになります。
-
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 を使用します。
-
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 はデプロイされません。
-
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 を設定する方法を示します。
-
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 を使用していない場合は、プロバイダーのドキュメントに従う必要があります。
-
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が書いた「コンピュータウイルス判定エキスパートシステムの原理と設計」