Cloud Key Management Service(Cloud KMS)で管理する鍵を使用して、アプリケーション レイヤで Kubernetes の Secret を暗号化する方法について説明します。この機能は Cloud KMS の機能に依存しているため、暗号鍵のローテーションとエンベロープ暗号化について理解しておく必要があります。
このタスクを Google Cloud コンソールで直接行う際の順を追ったガイダンスについては、「ガイドを表示」をクリックしてください。
概要
デフォルトでは、Google Kubernetes Engine(GKE)は Secret を含め起動時に保管されている顧客コンテンツを暗号化します。GKE では、こうした暗号化の処理と管理が自動的に行われるため、ユーザー側での操作は不要です。
アプリケーション レイヤで Secret を暗号化すると、機密データ(etcd に格納されている Secret など)に対するセキュリティをさらに強化できます。Cloud KMS で管理されている鍵を使用して、アプリケーション レイヤでデータを暗号化します。この暗号化により、攻撃者が etcd のオフライン コピーにアクセスした場合でもデータの内容が読み取られることはありません。
アプリケーション レイヤでの Secret の暗号化を使用するには、まず Cloud KMS 鍵を作成し、GKE サービス アカウントにその鍵へのアクセス権を付与する必要があります。Cloud KMS でサポートされている保護レベルを持つ鍵を使用できます。
レイテンシを減らすため、またリソースが複数の障害発生ドメイン間のサービスに依存することを防ぐために、鍵はクラスタと同じロケーションに存在するようにします。鍵を作成した後、使用する鍵を指定して新規または既存のクラスタでこの機能を有効にできます。この機能を有効にすると、GKE は暗号鍵を使用して、新しい Secret と既存の Secret をすべて暗号化します。
エンベロープ暗号化
Kubernetes の KMS プロバイダは、Secret のエンベロープ暗号化機能を提供します。具体的には、一般的にデータ暗号鍵(DEK)と呼ばれるローカル鍵が Secret の暗号化に使用されます。DEK 自体は、鍵暗号鍵(KEK)という別の鍵で暗号化されています。Kubernetes は KEK を保存しません。
エンベロープ暗号化には、次のような利点があります。
- 公開鍵による暗号化と比較してパフォーマンスが向上: GKE は、Cloud KMS API を使用して KEK で新しい DEK を暗号化します。また、ローカル キャッシュが空のときに DEK を復号します。
- 大規模な鍵管理の改善: 単一の KEK で複数の DEK を暗号化できます。Cloud KMS サービスに保存する必要がある鍵の数は、データを暗号化する鍵の数よりもはるかに少なくなります。
- 中央のルート オブ トラストを使用: Kubernetes に保存されている Secret は、外部のルート オブ トラストを使用できます。つまり、すべての Secret にハードウェア セキュリティ モジュールなどの中央のルート オブ トラストを使用できます。攻撃者がオフラインでコンテナにアクセスしても、Secret を取得することはできません。
GKE のアプリケーション レイヤでの Secret の暗号化により、GKE はローカル DEK と AES-CBC プロバイダを使用して Secret を暗号化します。GKE は、Cloud KMS で管理する KEK を使用して DEK を暗号化します。
エンベロープ暗号化の詳細については、エンベロープ暗号化をご覧ください。
シークレットを作成した場合
新しい Secret を作成すると、次のようになります。
Kubernetes API サーバーは乱数生成ツールを使用して、Secret のための一意の DEK を生成します。
Kubernetes API サーバーは、DEK をローカルで使用して、Secret を暗号化します。
KMS プラグインは暗号化のために DEK を Cloud KMS に送信します。KMS プラグインはプロジェクトの GKE サービス アカウントを使用して、Cloud KMS への認証を行います。
Cloud KMS は、KEK を使用して暗号化した DEK を KMS プラグインに返します。
Kubernetes API サーバーが、暗号化された Secret と DEK を保存します。平文の DEK は API サーバーのメモリにのみ保存されます。ディスクには保存されません。
Kubernetes API サーバーは、暗号化された DEK をメモリ内の平文の DEK にマッピングするキャッシュ エントリを作成します。これにより、API サーバーは Cloud KMS を使用せずに Secret を復号できます。
クライアントが Kubernetes API サーバーから Secret をリクエストすると、次の処理が実行されます。
Kubernetes API サーバーが、暗号化された Secret と DEK を取得します。
Kubernetes API サーバーは、既存のマッピング エントリのキャッシュをチェックし、Cloud KMS を使用せずに Secret を復号します。
キャッシュ エントリが見つからない場合、KMS プラグインは KEK を使用して復号するために DEK を Cloud KMS に送信します。復号された DEK を使用して Secret が復号されます。
Kubernetes API サーバーは、復号された Secret をクライアントに返します。
鍵を破棄した場合
GKE で Secret の暗号化に使用された Cloud KMS で KEK を破棄すると、新しい KEK を使用するようにクラスタを更新しない限り、Secret は使用できなくなります。
鍵のローテーションの後に古い KEK バージョンを破棄する場合は、先に新しい KEK バージョンを使用して Secret を再暗号化してください。必要に応じて、以前の KEK バージョンを保持して、Secrets の再暗号化を回避できます。ただし、Cloud KMS のすべてのアクティブな KEK に対して引き続き料金が発生します。料金の詳細については、Cloud KMS の料金をご覧ください。
サービス アカウント トークン ボリューム プロジェクションを使用しない場合、GKE のワークロードで使用されるサービス アカウントも Secret を使用します。鍵が破壊されると、これらのアカウントも使用できなくなります。アカウントにアクセスできないため、ワークロードは失敗します。
次の点が異なります。
マウントされたボリュームまたは環境変数として Secret へのアクセス権を持つ Pod は、そのアクセス権を保持します。
KEK を破棄した後も、Kubernetes API サーバーはキャッシュ内の DEK マッピング エントリを使用して Secret を復号できます。これにより、Pod を再起動または再スケジューリングすると Secret にアクセスできます。ただし、次の場合を除きます。
- クラスタ コントロール プレーンが再起動された。
- Kubernetes API サーバー Pod が再起動された。
- Secret の DEK マッピング エントリが Kubernetes API サーバーのキャッシュ内に存在しない。
KEK を破棄する前に、クラスタで使用されているかどうかを確認してください。Cloud KMS での鍵の破棄に関するアラート ポリシーを作成することもできます。
始める前に
このトピックの演習を行うには、2 つの Google Cloud プロジェクトが必要です。
鍵プロジェクト: KEK を作成するプロジェクト。
クラスタ プロジェクト: アプリケーション レイヤでの Secret の暗号化を有効にするクラスタの作成先。
鍵プロジェクトで、Cloud KMS API が有効になっていることを確認します。
鍵プロジェクトで、キーリングと鍵を作成するユーザーには次の IAM 権限が必要になります。
cloudkms.keyRings.getIamPolicy
cloudkms.keyRings.setIamPolicy
これらの権限(および他の権限)は、
roles/cloudkms.admin
Identity and Access Management 事前定義ロールに付与されています。鍵を管理するための権限の付与に関する詳細については、Cloud KMS のドキュメントをご覧ください。クラスタ プロジェクトで、Google Kubernetes Engine API が有効になっていることを確認します。
Google Cloud CLI がインストールされていることを確認します。
gcloud
を最新バージョンに更新します。gcloud components update
Cloud KMS 鍵を作成する
Cloud KMS 鍵を作成するには、まず、キーリングを作成する必要があります。鍵とキーリングはリージョン リソースです。キーリングを作成するときは、GKE クラスタのロケーションと一致するロケーションを指定します。
ゾーンクラスタは、スーパーセット リージョンからのキーリングを使用する必要があります。たとえば、
us-central1-a
ゾーンのクラスタは、us-central1
リージョンの鍵のみを使用できます。リージョン クラスタは、同じロケーションからのキーリングを使用する必要があります。たとえば、
asia-northeast1
リージョンのクラスタは、asia-northeast1
リージョンのキーリングで保護する必要があります。
gcloud CLI または Google Cloud コンソールを使用できます。
コンソール
鍵プロジェクトでキーリングを作成します。
Google Cloud コンソールで、[鍵管理] ページに移動します。
[キーリングを作成] をクリックします。
[キーリング名] フィールドに、キーリングの名前を入力します。
[ロケーション] プルダウンで、Kubernetes クラスタのロケーションを選択します。
[作成] をクリックします。
次に、鍵を作成します。
Google Cloud コンソールで、[鍵管理] ページに移動します。
鍵を作成するキーリングの名前をクリックします。
[鍵を作成] をクリックします。
[キー名] フィールドに、鍵の名前を入力します。
[ローテーション期間] と [開始日] に鍵のローテーション期間と開始時間を設定します。デフォルト値をそのまま使用することもできます。
(省略可)鍵にラベルを追加する場合は、[ラベル] フィールドで [ラベルを追加] をクリックします。
[作成] をクリックします。
gcloud
鍵プロジェクトでキーリングを作成します。
gcloud kms keyrings create RING_NAME \
--location=LOCATION \
--project=KEY_PROJECT_ID
次のように置き換えます。
RING_NAME
: 新しいキーリングの名前。LOCATION
: キーリングを作成するロケーション。KEY_PROJECT_ID
: 鍵プロジェクト ID。
鍵を作成します。
gcloud kms keys create KEY_NAME \
--location=LOCATION \
--keyring=RING_NAME \
--purpose=encryption \
--project=KEY_PROJECT_ID
次のように置き換えます。
KEY_NAME
: 新しい鍵の名前。LOCATION
: キーリングを作成した Cloud KMS のロケーション。RING_NAME
: キーリングの名前。KEY_PROJECT_ID
: 鍵プロジェクト ID。
鍵を使用する権限を付与する
クラスタ プロジェクトの GKE サービス アカウントの名前は次のとおりです。
service-CLUSTER_PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
CLUSTER_PROJECT_NUMBER
は、クラスタ プロジェクト番号で置き換えます。gcloud CLI を使用してプロジェクト番号を確認するには、次のコマンドを実行します。
gcloud projects describe CLUSTER_PROJECT_ID \
--format="value(projectNumber)"
サービス アカウントへのアクセスを許可するには、Google Cloud コンソールまたは gcloud CLI を使用します。
コンソール
GKE サービス アカウントに Cloud KMS 暗号鍵の暗号化 / 復号のロールを付与します。
- Google Cloud Console で Cloud Key Management Service 鍵ブラウザを開きます。
Cloud KMS 鍵のブラウザを開く 目的の鍵を含むキーリングの名前をクリックします。
使用する鍵のチェックボックスをオンにします。
右側のウィンドウの [権限] タブが有効になります。
[メンバーの追加] ダイアログで、アクセス権を付与する GKE サービス アカウントのメールアドレスを指定します。
[役割を選択] プルダウンで、[クラウド KMS 暗号鍵の暗号化 / 復号] を選択します。
[保存] をクリックします。
gcloud
GKE サービス アカウントに Cloud KMS 暗号鍵の暗号化 / 復号のロールを付与します。
gcloud kms keys add-iam-policy-binding KEY_NAME \
--location=LOCATION \
--keyring=RING_NAME \
--member=serviceAccount:SERVICE_ACCOUNT_NAME \
--role=roles/cloudkms.cryptoKeyEncrypterDecrypter \
--project=KEY_PROJECT_ID
次のように置き換えます。
KEY_NAME
: 鍵の名前。LOCATION
: キーリングを作成した Cloud KMS のロケーション。RING_NAME
: キーリングの名前。SERVICE_ACCOUNT_NAME
: GKE サービス アカウントの名前。KEY_PROJECT_ID
: 鍵プロジェクト ID。
Cloud HSM 鍵に十分な割り当てを設定する
Cloud HSM 鍵を使用する場合、鍵を含む Google Cloud プロジェクトは鍵の割り当てによって制限されます。アプリケーション レイヤでの Secret の暗号化で Cloud HSM 鍵を使用するための十分な割り当てがあることを確認してください。割り当てを使い切ると、ノードがクラスタ コントロール プレーンへの接続を失うことがあります。
アプリケーション レイヤでの Secret の暗号化を有効にする
新規または既存の GKE Standard クラスタと GKE Autopilot クラスタのアプリケーション レイヤで Secret の暗号化を有効にするには、gcloud CLI または Google Cloud コンソールを使用します。
アプリケーション レイヤで Secret の暗号化を有効にしたら、鍵のローテーションを行うことをおすすめします。Cloud KMS では、鍵の自動ローテーションを構成できます。手順については、自動ローテーションの構成をご覧ください。
新しいクラスタの場合
アプリケーション レイヤでの Secret の暗号化を有効にして新しいクラスタを作成するには、Google Cloud コンソールまたは gcloud CLI を使用します。
コンソール - Autopilot
アプリケーション レイヤでの Secret の暗号化を有効にして Autopilot クラスタを作成するには、次の操作を行います。
Google Cloud コンソールで Google Kubernetes Engine のページに移動します。
[add_box 作成] をクリックします。
[Autopilot] セクションで、[構成] をクリックします。
必要に応じてクラスタを構成します。
ナビゲーション パネルで [詳細オプション] をクリックし、[セキュリティ] セクションを開きます。
[アプリケーション レイヤでの Secret の暗号化を有効にする] のチェックボックスをオンにして、Cloud KMS 鍵を作成するで作成した鍵を選択します。
[作成] をクリックします。
コンソール - Standard
アプリケーション レイヤでの Secret の暗号化を有効にした Standard クラスタを作成するには、次の操作を行います。
Google Cloud コンソールで Google Kubernetes Engine のページに移動します。
[add_box 作成] をクリックします。
[Standard] セクションで [構成] をクリックします。
必要に応じてクラスタを構成します。
ナビゲーション パネルの [クラスタ] の下の [セキュリティ] をクリックします。
[アプリケーション レイヤでの Secret の暗号化を有効にする] のチェックボックスをオンにして、Cloud KMS 鍵を作成するで作成した鍵を選択します。
[作成] をクリックします。
gcloud
アプリケーション レイヤでの Secret の暗号化をサポートするクラスタを作成するには、作成コマンドの --database-encryption-key
パラメータに値を指定します。
gcloud container clusters create-auto CLUSTER_NAME \
--cluster-version=latest \
--region=COMPUTE_REGION \
--database-encryption-key=projects/KEY_PROJECT_ID/locations/LOCATION/keyRings/RING_NAME/cryptoKeys/KEY_NAME \
--project=CLUSTER_PROJECT_ID
次のように置き換えます。
CLUSTER_NAME
: 新しいクラスタに付ける名前。COMPUTE_REGION
: クラスタを作成する Compute Engine リージョン。KEY_PROJECT_ID
: 鍵プロジェクト ID。LOCATION
: キーリングを作成した Cloud KMS のロケーション。RING_NAME
: キーリングの名前。KEY_NAME
: 鍵の名前。CLUSTER_PROJECT_ID
: クラスタのプロジェクト ID。
新しい Standard クラスタで、アプリケーション レイヤでの Secret の暗号化を有効にするには、同じフラグを指定して gcloud container clusters create
コマンドを実行します。
既存クラスタの場合
アプリケーション レイヤでの Secret の暗号化を使用するように既存のクラスタを更新するには、gcloud CLI または Google Cloud コンソールを使用します。GKE は、指定された暗号鍵を使用して、既存の Secret と新しい Secret をすべて暗号化します。
Console
アプリケーション レイヤでの Secret の暗号化をサポートするようクラスタを更新するには:
Google Cloud コンソールで Google Kubernetes Engine のページに移動します。
変更するクラスタの名前をクリックします。
[セキュリティ] の [アプリケーション レイヤでの Secret の暗号化] フィールドで、[editアプリケーション レイヤでの Secret の暗号化を編集] をクリックします。
[アプリケーション レイヤでの Secret の暗号化を有効にする] のチェックボックスをオンにして、Cloud KMS 鍵を作成するで作成した鍵を選択します。
[変更を保存] をクリックします。
gcloud
アプリケーション レイヤでの Secret の暗号化を既存のクラスタで有効にするには、次のコマンドを実行します。
gcloud container clusters update CLUSTER_NAME \
--region=COMPUTE_REGION \
--database-encryption-key=projects/KEY_PROJECT_ID/locations/LOCATION/keyRings/RING_NAME/cryptoKeys/KEY_NAME \
--project=CLUSTER_PROJECT_ID
次のように置き換えます。
CLUSTER_NAME
: クラスタの名前。COMPUTE_REGION
: クラスタの Compute Engine のリージョン。KEY_PROJECT_ID
: 鍵プロジェクト ID。LOCATION
: キーリングを作成した Cloud KMS のロケーション。RING_NAME
: キーリングの名前。KEY_NAME
: 鍵の名前。CLUSTER_PROJECT_ID
: クラスタのプロジェクト ID。
Cloud KMS 鍵を更新する
新しい Cloud KMS 鍵を使用するように既存のクラスタを更新するには、gcloud CLI または Google Cloud コンソールを使用します。
Console
新しい Cloud KMS 鍵を使用するようにクラスタを更新するには:
Google Cloud コンソールで Google Kubernetes Engine のページに移動します。
変更するクラスタの名前をクリックします。
[セキュリティ] の [アプリケーション レイヤでの Secret の暗号化] フィールドで、[editアプリケーション レイヤでの Secret の暗号化を編集] をクリックします。
使用する新しい暗号鍵を選択します。
[変更を保存] をクリックします。
gcloud
新しい Cloud KMS 鍵を使用するように既存のクラスタを更新するには:
gcloud container clusters update CLUSTER_NAME \
--region=COMPUTE_REGION \
--database-encryption-key=projects/KEY_PROJECT_ID/locations/LOCATION/keyRings/RING_NAME/cryptoKeys/KEY_NAME \
--project=CLUSTER_PROJECT_ID
次のように置き換えます。
CLUSTER_NAME
: クラスタの名前。COMPUTE_REGION
: クラスタの Compute Engine のリージョン。KEY_PROJECT_ID
: 鍵プロジェクト ID。LOCATION
: キーリングを作成した Cloud KMS のロケーション。RING_NAME
: キーリングの名前。KEY_NAME
: 鍵の名前。CLUSTER_PROJECT_ID
: クラスタのプロジェクト ID。
アプリケーション レイヤでの Secret の暗号化を無効にする
アプリケーション レイヤでの Secret の暗号化を無効にするには、gcloud CLI または Google Cloud コンソールを使用します。
コンソール
Google Cloud コンソールで Google Kubernetes Engine のページに移動します。
変更するクラスタの名前をクリックします。
[セキュリティ] の [アプリケーション レイヤでの Secret の暗号化] フィールドで、[editアプリケーション レイヤでの Secret の暗号化を編集] をクリックします。
[アプリケーション レイヤでの Secret の暗号化を有効にする] チェックボックスをオフにします。
[変更を保存] をクリックします。
gcloud
アプリケーション レイヤでの Secret の暗号化を無効にするには、次のコマンドを実行します。
gcloud container clusters update CLUSTER_NAME \
--region=COMPUTE_REGION \
--disable-database-encryption \
--project=CLUSTER_PROJECT_ID
次のように置き換えます。
CLUSTER_NAME
: クラスタの名前。COMPUTE_REGION
: クラスタの Compute Engine のリージョン。CLUSTER_PROJECT_ID
: クラスタのプロジェクト ID。
アプリケーション レイヤでの Secret の暗号化が有効になっていることを確認する
クラスタがアプリケーション レイヤでの Secret の暗号化を使用しているか調べるには、Google Cloud コンソールまたは gcloud CLI を使用します。
コンソール
Google Cloud コンソールで Google Kubernetes Engine のページに移動します。
変更するクラスタの名前をクリックします。
[セキュリティ] で、[アプリケーション レイヤでの Secret の暗号化] フィールドに「
Enabled
」と正しい鍵が表示されていることを確認します。
gcloud
クラスタがアプリケーション レイヤでの Secret の暗号化を使用しているかどうかを確認します。
gcloud container clusters describe CLUSTER_NAME \
--region=COMPUTE_REGION \
--format='value(databaseEncryption)' \
--project=CLUSTER_PROJECT_ID
次のように置き換えます。
CLUSTER_NAME
: クラスタの名前。COMPUTE_REGION
: クラスタの Compute Engine のリージョン。CLUSTER_PROJECT_ID
: クラスタのプロジェクト ID。
クラスタがアプリケーション レイヤでの Secret の暗号化を使用する場合、出力は次のようになります。
keyName=projects/KEY_PROJECT_ID/locations/LOCATION/keyRings/RING_NAME/cryptoKeys/KEY_NAME;state=ENCRYPTED
鍵をローテーションする
アプリケーション レイヤでの Secret の暗号化を有効にした後も、定期的に鍵のローテーションを行うことをおすすめします。鍵の自動ローテーションを構成する方法や、鍵を手動でローテーションする方法については、鍵のローテーションをご覧ください。
鍵のローテーションを行う場合、既存の Secret は以前の鍵暗号鍵(KEK)で暗号化されます。新しい KEK バージョンが Secret をラップできるようにするには、鍵のローテーション後に Secret を再暗号化します。
たとえば、Secret1
Secret を作成して保存します。この Secret が DEK1
で暗号化されて、さらに KEKv1
でラップされます。
KEK がローテーションした後で、Secret1
を再暗号化すると、DEK2
によってラップされます。さらに、ローテーションされる KEK が KEKv2
でラップされます。
Secret を再暗号化する
鍵のローテーションを行ったら、Secret を再暗号化して、新しいバージョンの KEK でラップする必要があります。gcloud CLI を使用して自動再暗号化を構成することはできませんが、CronJob などを使用して、再暗号化コマンドを定期的に実行することはできます。
鍵のローテーション後に Secret を手動で再暗号化する場合、新しいバージョンが整合性を持つまで少なくとも 3 時間待ちます。その後、すべての Secret に次のようなコマンドを使用して、再暗号化を強制します。
kubectl get secrets --all-namespaces -o json | kubectl annotate --overwrite -f - encryption-key-rotation-time="TIME"
TIME
は、ローテーションのタイミングを示す文字列(20200909-090909
など)に置き換えます。
制限事項
- GKE は、アプリケーション レイヤでの Secret の暗号化でクラスタごとに 30,000 個までの Secret をサポートしています。30,000 を超える Secret を保存すると、アップグレード時にクラスタが不安定になり、ワークロードが停止する可能性があります。
- すべての Namespace で Secret の平均メタデータのサイズが 5 KiB を下回っていることを確認します。メタデータの平均サイズが 5 KiB を超えていると、クラスタが不適切な状態になる可能性があります。たとえば、この機能を有効または無効にすると、暗号化された Secret と復号された Secret が混在する状態になる場合があります。
クラスタと同じリージョン内の鍵を選択する必要があります。たとえば
us-central1-a
内のゾーンクラスタは、us-central1
リージョン内の鍵のみを使用できます。リージョン クラスタでは、レイテンシを減らすため、またリソースが複数の障害発生ドメイン間のサービスに依存することを防ぐため、鍵がクラスタと同じロケーションに存在する必要があります。GKE は Cloud KMS の鍵のみをサポートしています。別の Kubernetes KMS プロバイダや暗号化プロバイダを使用することはできません。
トラブルシューティング
Secret の暗号化の更新が失敗した問題の解決など、アプリケーション レイヤでの Secret の暗号化のトラブルシューティングについては、アプリケーション レイヤでの Secret の暗号化のトラブルシューティングをご覧ください。
Cloud KMS 鍵が無効になっている
GKE のデフォルトのサービス アカウントは、アプリケーション レベルでの Secret の暗号化で無効になっている Cloud KMS 鍵を使用できません。
無効になっている鍵を再度有効にするには、無効な鍵バージョンを有効にするをご覧ください。