バージョン 1.23 以降、Kubernetes は証明書の X.509 Common Name(CN)フィールドを使用したサーバー ID 検証をサポートしなくなりました。代わりに、Kubernetes は X.509 サブジェクト代替名(SAN)フィールドの情報のみを使用します。
クラスタへの影響を防ぐには、クラスタを Kubernetes バージョン 1.23 にアップグレードする前に、Webhook のバックエンドと集約 API サーバーの SAN がなく互換性のない証明書を置き換える必要があります。
Kubernetes が SAN なしのバックエンド証明書のサポートを終了した理由
GKE はオープンソースの Kubernetes を運用しています。この Kubernetes は kube-apiserver コンポーネントを使用し、Transport Layer Security(TLS)を使用して Webhook や集約 API サーバー バックエンドに接続します。kube-apiserver コンポーネントは Go プログラミング言語で記述されています。
Go 1.15 より前は、TLS クライアントは 2 段階プロセスを使用して接続先のサーバーの ID を検証していました。
- サーバーの DNS 名(または IP アドレス)が、サーバーの証明書の SAN の 1 つとして存在するかどうかを確認します。
- または、サーバーの DNS 名(または IP アドレス)がサーバーの証明書の CN と等しいかどうかを確認します。
2011 年、CN フィールドに基づくサーバー ID 検証は、RFC 6125 により完全に非推奨になりました。ブラウザやその他のセキュリティ クリティカルなアプリケーションは、このフィールドを使用しません。
より幅広い TLS エコシステムに合わせて、Go 1.15 では検証プロセスからステップ 2 を削除しましたが、デバッグ スイッチ(x509ignoreCN=0
)を残して以前の動作を有効にすることで、移行プロセスが容易になります。Kubernetes バージョン 1.19 は、Go 1.15 を使用してビルドされた最初のバージョンでした。バージョン 1.19 から 1.22 までの GKE クラスタでは、デバッグ スイッチがデフォルトで有効になっているため、影響を受ける Webhook と集約 API サーバー バックエンドの証明書を置き換える時間が長くなりました。
Kubernetes バージョン 1.23 は Go 1.17 でビルドされているため、デバッグ スイッチが削除されています。GKE がクラスタをバージョン 1.23 にアップグレードすると、クラスタのコントロール プレーンから、有効な SAN のある X.509 証明書を提供していない Webhook や集計 API サービスに接続できなくなります。
影響を受けるクラスタの特定
1.21.9 または 1.22.3 以上のパッチ バージョンを実行しているクラスタの場合
Cloud Logging が有効なパッチ バージョン 1.21.9 および 1.22.3 以降のクラスタの場合は、GKE は Cloud Audit Logs のログを提供して、影響を受けるバックエンドへのクラスタからの呼び出しを特定します。次のフィルタを使用してログを検索できます。
logName =~ "projects/.*/logs/cloudaudit.googleapis.com%2Factivity"
resource.type = "k8s_cluster"
operation.producer = "k8s.io"
"invalid-cert.webhook.gke.io"
影響を受ける証明書を使用してクラスタがバックエンドを呼び出していない場合、ログは表示されません。このような監査ログには、影響を受けるバックエンドのホスト名が含まれています。
以下は、デフォルトの名前空間の example-webhook という名前のサービスによってホストされている Webhook バックエンドのログエントリの例です。
{
...
resource {
type: "k8s_cluster",
"labels": {
"location": "us-central1-c",
"cluster_name": "example-cluster",
"project_id": "example-project"
}
},
labels: {
invalid-cert.webhook.gke.io/example-webhook.default.svc: "No subjectAltNames returned from example-webhook.default.svc:8443",
...
},
logName: "projects/example-project/logs/cloudaudit.googleapis.com%2Factivity",
operation: {
...
producer: "k8s.io",
...
},
...
}
影響を受けるサービスのホスト名(example-webhook.default.svc
など)は、invalid-cert.webhook.gke.io/
で始まるラベル名に接尾辞として含まれます。呼び出しを行ったクラスタの名前を resource.labels.cluster_name
ラベルから取得することもできます。この例では、example-cluster
値が設定されています。
非推奨に関する分析情報
互換性のない証明書を使用しているクラスタは、非推奨に関する分析情報で確認できます。分析情報は、バージョン 1.22.6-gke.1000 以降を実行しているクラスタで使用できます。
他のクラスタ バージョン
1.22 マイナー バージョンで 1.22.3 より前のパッチ バージョンまたは 1.21.9 より前のパッチ バージョンにクラスタがある場合、クラスタがサポート終了の影響を受けているかどうか判断するには、次の 2 つの方法があります。
オプション 1(推奨): 影響を受けるログを含む証明書の特定をサポートするパッチ バージョンにクラスタをアップグレードします。クラスタで Cloud Logging が有効になっていることを確認します。クラスタがアップグレードされると、適切な SAN を含む証明書を提供しない Service をクラスタが呼び出すたびに、識別用の Cloud Audit Logs のログが生成されます。ログは呼び出しの試行に対してのみ生成されるため、すべての呼び出しパスを呼び出すために十分な時間を確保できるよう、アップグレード後 30 日間待機することをおすすめします。
影響を受けるサービスを識別するには、ログを使用することをおすすめします。この方法を使用すると、影響を受けるサービスを表示するためのログを自動的に生成することで、手動作業が最小限に抑えられるからです。
オプション 2: クラスタの Webhook または集約 API サーバーで使用される証明書を検査して、SAN がないことが原因で影響を受けるかどうかを確認します。
この方法ですべての証明書を検査するには手動作業が必要となるため、クラスタをバージョン 1.21 にアップグレードする前に、Kubernetes バージョン 1.23 のサポート終了の影響を評価する必要がある場合のみ、この方法を使用してください。クラスタを 1.21 にアップグレードできる場合は、まずクラスタをアップグレードしてから、オプション 1 の手順に沿って手動の作業を回避する必要があります。
検査するバックエンド サービスの特定
サポート終了の影響を受ける可能性があるバックエンドを特定するには、Webhook と集約 API サービスのリストと、クラスタ内の関連するバックエンドを取得します。
クラスタ内の関連する Webhook すべての一覧を表示するには、次の kubectl
コマンドを使用します。
kubectl get mutatingwebhookconfigurations -A # mutating admission webhooks
kubectl get validatingwebhookconfigurations -A # validating admission webhooks
特定の Webhook に関連するバックエンド サービスまたは URL を取得するには、Webhook の構成の clientConfig.service
フィールドまたは webhooks.clientConfig.url
フィールドを調べます。
kubectl get mutatingwebhookconfigurations example-webhook -o yaml
このコマンドの出力は、次のようになります。
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
webhooks:
- admissionReviewVersions:
clientConfig:
service:
name: example-service
namespace: default
port: 443
なお、clientConfig は、バックエンドを Kubernetes Service(clientConfig.service
)または URL(clientConfig.url
)として指定できます。
クラスタ内の関連するすべての集約 API サービスを一覧表示するには、次の kubectl
コマンドを使用します。
kubectl get apiservices -A |grep -v Local # aggregated API services
このコマンドの出力は、次のようになります。
NAME SERVICE AVAILABLE AGE
v1beta1.metrics.k8s.io kube-system/metrics-server True 237d
この例では、kube-system
名前空間から metric-server
Service を返します。
特定の集約 API に関連する Service は、spec.service
フィールドを調べることで取得できます。
kubectl get apiservices v1beta1.metrics.k8s.io -o yaml
このコマンドの出力は、次のようになります。
...
apiVersion: apiregistration.k8s.io/v1
kind: APIService
spec:
service:
name: metrics-server
namespace: kube-system
port: 443
Service の証明書を検査する
検査する関連バックエンド サービスを特定したら、example-service
などの特定の Service の証明書を検査できます。
Service のセレクタとターゲット ポートを確認します。
kubectl describe service example-service
このコマンドの出力は、次のようになります。
Name: example-service Namespace: default Labels: run=nginx Selector: run=nginx Type: ClusterIP IP: 172.21.xxx.xxx Port: 443 TargetPort: 444
この例では、
example-service
にセレクタrun=nginx
とターゲット ポート444
があります。セレクタに一致する Pod を見つけます。
kubectl get pods --selector=run=nginx
コマンドの出力は、次のようになります。
NAME READY STATUS RESTARTS AGE example-pod 1/1 Running 0 21m
-
kubectl
localhost から Pod に設定します。kubectl port-forward pods/example-pod LOCALHOST_PORT:TARGET_PORT # port forwarding in background
コマンドを次のように置き換えます。
LOCALHOST_PORT
: リッスンするアドレス。TARGET_PORT
: ステップ 1 のTargetPort
。
openssl
を使用して、Service が使用する証明書を出力します。openssl s_client -connect localhost:LOCALHOST_PORT </dev/null | openssl x509 -noout -text
次の出力例は、(SAN エントリを含む)有効な証明書を示しています。
Subject: CN = example-service.default.svc X509v3 extensions: X509v3 Subject Alternative Name: DNS:example-service.default.svc
次の出力例は、SAN がない証明書を示しています。
Subject: CN = example-service.default.svc X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Authority Key Identifier: keyid:1A:5F:29:D8:E9:3C:54:3C:35:CC:D8:AB:D1:21:FD:C3:56:25:C0:74
次のコマンドを使用して、ポート転送を削除してバックグラウンドで実行されないようにします。
$ jobs [1]+ Running kubectl port-forward pods/example-pod 8888:444 & $ kill %1 [1]+ Terminated kubectl port-forward pods/example 8888:444
URL バックエンドの証明書を検査する
Webhook が url
バックエンドを使用する場合は、URL で指定されたホスト名に直接接続します。たとえば、URL が https://example.com:123/foo/bar
の場合は、次の openssl
コマンドを使用して、バックエンドで使用される証明書を出力します。
openssl s_client -connect example.com:123 </dev/null | openssl x509 -noout -text
1.23 アップグレードのリスクの軽減
SAN のない証明書を使用して、影響を受けるクラスタとそのバックエンド サービスを特定したら、クラスタをバージョン 1.23 にアップグレードする前に、適切な SAN を持つ証明書を使用するように Webhook と集約 API サーバー バックエンドを更新する必要があります。
証明書を置き換えるか、バージョン 1.22 の標準サポートが終了するまで、GKE はバージョン 1.22.6-gke.1000 以降のクラスタを互換性のない証明書を使用してバックエンドで自動的にアップグレードしません。
クラスタが 1.22.6-gke.1000 より前の GKE バージョンを使用するには、メンテナンスの除外を構成してマイナー アップグレードを回避することで一時的な自動アップグレードを防ぐことができます。
リソース
この変更について詳しくは、次のリソースをご覧ください。
- Kubernetes 1.23 リリースノート
- Kubernetes は Go 1.17 を使用してビルドされています。このバージョンの Go では、
GODEBUG=x509ignoreCN=0
環境設定を使用して、X.509 提供証明書の CN をホスト名として扱う非推奨の従来の動作を再び有効にする機能が削除されています。
- Kubernetes は Go 1.17 を使用してビルドされています。このバージョンの Go では、
- Kubernetes 1.19 と Kubernetes 1.20 のリリースノート
- SAN が存在しない場合に、X.509 の証明書の CN フィールドをホスト名として扱うという従来の非推奨の動作は、デフォルトで無効になりました。
- Go 1.17 リリースノート
- 一時的な
GODEBUG=x509ignoreCN=0
フラグが削除されました。
- 一時的な
- Go 1.15 リリースノート
- SAN が存在しない場合に、X.509 証明書の CN フィールドをホストとして扱うという従来の非推奨動作が、デフォルトで無効になりました。
- RFC 6125
(46 ページ)
- CN 値を使用するのがこれまでの方法でしたが、非推奨になりました。代わりに認証局では
subjectAltName
値を指定することをおすすめします。
- CN 値を使用するのがこれまでの方法でしたが、非推奨になりました。代わりに認証局では
- アドミッション Webhook