クラスタ メタデータの保護

概要

GKE はインスタンス メタデータを使用してノード VM を構成しますが、このメタデータの一部は潜在的に機密性が高く、クラスタ上で実行されているワークロードから保護する必要があります。

始める前に

作業を始める前に、次のことを確認してください。

次のいずれかの方法で gcloud のデフォルトの設定を指定します。

  • gcloud init。デフォルトの設定全般を確認する場合に使用します。
  • gcloud config。プロジェクト ID、ゾーン、リージョンを個別に設定する場合に使用します。

gcloud init の使用

エラー One of [--zone, --region] must be supplied: Please specify location を受信した場合は、このセクションの内容を実施します。

  1. gcloud init を実行して、次の操作を行います。

    gcloud init

    リモート サーバーで SSH を使用している場合は、--console-only フラグを指定して、コマンドがブラウザを起動しないようにします。

    gcloud init --console-only
  2. 手順に従って gcloud を承認し、Google Cloud アカウントを使用します。
  3. 新しい構成を作成するか、既存の構成を選択します。
  4. Google Cloud プロジェクトを選択します。
  5. デフォルトの Compute Engine ゾーンを選択します。

gcloud config の使用

  • デフォルトのプロジェクト ID を設定します。
    gcloud config set project project-id
  • ゾーンクラスタを使用する場合は、デフォルトのコンピューティング ゾーンを設定します。
    gcloud config set compute/zone compute-zone
  • リージョン クラスタを使用する場合は、デフォルトのコンピューティング リージョンを設定します。
    gcloud config set compute/region compute-region
  • gcloud を最新バージョンに更新します。
    gcloud components update

ノードのサービス アカウントの構成

各ノードのサービス アカウント認証情報は引き続きワークロードに公開されるため、必要最小限の権限でサービス アカウントが構成されていることを確認してください。次に、このサービス アカウントをノードに接続して、攻撃者が Compute Engine API を使用してノード インスタンスに直接アクセスすることで GKE のメタデータ保護を回避することができないようにします。

compute.instances.get 権限、Compute インスタンス管理者の役割、またはその他の同様の権限を持つサービス アカウントを使用しないでください。これは、潜在的な攻撃者がこれらの権限を利用して、Compute Engine API 経由でインスタンス メタデータを取得可能になるためです。アクセス スコープではなく、サービス アカウント権限を使用して、ノード VM の権限を制限することをおすすめします。詳細については、Compute Engine のサービス アカウントのドキュメントをご覧ください。

ノードサービス アカウントを持っていない場合は、次のコマンドを使用してノードサービス アカウントを作成できます。

export NODE_SA_NAME=gke-node-sa
gcloud iam service-accounts create $NODE_SA_NAME \
  --display-name "Node Service Account"
export NODE_SA_EMAIL=$(gcloud iam service-accounts list --format='value(email)' \
  --filter='displayName:Node Service Account')

必要な役割と権限でサービス アカウントを構成するには、次のコマンドを実行します。PROJECT は自分のプロジェクト ID です。

export PROJECT=$(gcloud config get-value project)

gcloud projects add-iam-policy-binding $PROJECT \
  --member serviceAccount:$NODE_SA_EMAIL \
  --role roles/monitoring.metricWriter
gcloud projects add-iam-policy-binding $PROJECT \
  --member serviceAccount:$NODE_SA_EMAIL \
  --role roles/monitoring.viewer
gcloud projects add-iam-policy-binding $PROJECT \
  --member serviceAccount:$NODE_SA_EMAIL \
  --role roles/logging.logWriter

さらに、クラスタが Container Registry から非公開イメージを pull する場合は、storage.objectViewer 役割を追加します。

gcloud projects add-iam-policy-binding $PROJECT \
  --member serviceAccount:$NODE_SA_EMAIL \
  --role roles/storage.objectViewer

以前のメタデータ API の無効化と移行

Compute Engine v1beta1 と v0.1 メタデータ サーバーのエンドポイントはサポート終了となり、停止が予定されています。v1 エンドポイントを使用するすべてのリクエストを必ず更新してください。

Compute Engine のインスタンス メタデータ サーバーが公開する以前の v0.1 と v1beta1 エンドポイントは、メタデータ クエリヘッダーを適用しません。これは v1 API の機能であり、これにより潜在的な攻撃者はインスタンス メタデータを取得することがより困難になります。特に必要とされる場合を除き、こうした以前の API を無効にすることをおすすめします。

以降のセクションでは、次の方法について説明します。

  • 廃止予定のエンドポイントにアクセスしているエンドポイントを特定する方法。ノードが廃止予定のエンドポイントを使用している場合は、これらのノードを移行する必要があります。

  • 特定したノードに対して以前のメタデータ サーバーのエンドポイントを無効にして、新しいクラスタまたはノードプールを作成する方法。

以前のメタデータ サーバーのエンドポイントを使用してノードを特定する

check-legacy-endpoint-access ツール を使用すると、以前のメタデータ サーバーのエンドポイントを使用している Kubernetes Engine ノードを特定できます。このツールをお使いのクラスタに適用すると、5 分ごとに各ノードの v0.1 エンドポイントと v1beta1 エンドポイントへのリクエストをすべて記録します。このツールは、Kubernetes Engine で以前のエンドポイントの使用状況を確認し、デバッグと検証を行い場合にも使用できます。

check-legacy-endpoint-access ツールは次の手順で設定します。

  1. 各クラスタで、次のコマンドを実行します。

    kubectl apply -f \
    https://raw.githubusercontent.com/GoogleCloudPlatform\
    /k8s-node-tools/master/check-legacy-endpoint-access/check-legacy-endpoint-access.yaml
  2. 収集されたログをクエリし、以前のエンドポイントの使用状況に関する情報を参照します。各クラスタでログをクエリするには、次のコマンドを実行します。

    kubectl -n kube-system logs -l \
    app=check-legacy-endpoint-access | grep "access count"

Stackdriver Logging で収集されたログを表示することもできます。

  1. Cloud Console の [Cloud Logging] > [ログ](ログビューア)ページに移動します。

    ログビューア ページに移動

  2. 次のフィルタを適用します。

    resource.type="container"
    resource.labels.namespace_id="kube-system"
    logName:"/check-legacy-endpoint-access"

    フィルタリングしたビューに移動

  3. ノードを特定したら、これらのエンドポイントを使用しているプロセスを特定する必要があります。これらのプロセスを特定する手順については、プロセスの特定をご覧ください。

  4. v1 メタデータ サーバーのエンドポイントを使用するために、これらのプロセスを移行します。エンドポイントの Compute Engine ノードと差分を移行する方法については、v1 メタデータ サーバーのエンドポイントへの移行をご覧ください。

  5. check-legacy-endpoint-access DaemonSet を削除します。

    kubectl delete daemonset check-legacy-endpoint-access -n kube-system

以前のメタデータ API を無効にして新しいノードプールを作成する

サービス アカウントの作成後、gcloud コマンドライン ツールで以前のメタデータ API を無効にして、新しいノードプールまたは(新しいクラスタのデフォルトのノードプール)を作成できます。

以前のメタデータ API を無効にして新しいノードプールを作成するには、--metadata disable-legacy-endpoints=true フラグを使用します。例:

gcloud container node-pools create pool-name \
  --service-account=$NODE_SA_EMAIL \
  --metadata disable-legacy-endpoints=true

以前のメタデータ API を無効にした状態で新しいクラスタをデフォルトのノードプールに作成するには、同じフラグを使用します。例:

gcloud container clusters create cluster-name \
  --service-account=$NODE_SA_EMAIL \
  --metadata disable-legacy-endpoints=true

既存のクラスタを更新して以前のメタデータ API を無効にする

以前のメタデータ API を無効にした状態で新しいノードプールを作成した後に、既存のクラスタを更新してそのノードプールを使用するには、ノードプールの移行ガイドに従ってください。

以前のメタデータ API が無効であることを確認する

以前のインスタンス メタデータ API が無効になっていると、/0.1/ および /v1beta1/ メタデータ サーバー エンドポイントに対するリクエストで 403 Forbidden が返されます。

以前のメタデータ API が無効になっていることを確認するには、ポッド内から curl コマンドを実行します。

root@pod-name# curl -H 'Metadata-Flavor: Google' \
'http://metadata.google.internal/computeMetadata/v1/instance/attributes/disable-legacy-endpoints'
true
root@pod-name# curl 'http://metadata.google.internal/computeMetadata/v1beta1/instance/id'
... Error 403 (Forbidden) ... Legacy metadata endpoint accessed: /computeMetadata/v1beta1/instance/id Legacy metadata endpoints are disabled. Please use the /v1/ endpoint. ...

メタデータ隠蔽

GKE のメタデータ隠蔽は、一部の潜在的に機密性が高いシステム メタデータを、クラスタ上で実行されているユーザー ワークロードから保護します。

Kubernetes v1.9.3 以降では、メタデータ隠蔽を有効にして、ユーザーのポッドがクラスタのノードの特定の VM メタデータ(Kubelet 認証情報や VM インスタンス情報など)にアクセスすることを防止できます。 具体的には、メタデータ隠蔽は、kube-env(Kubelet 認証情報を含む)と VM のインスタンス ID トークンへのアクセスを保護します。

メタデータ隠蔽は、ユーザーポッド(HostNetwork 上で実行されていないポッド)からクラスタ メタデータ サーバーへのトラフィックをファイアウォール制御し、安全なクエリのみを許可します。ファイアウォールは、ユーザーポッドが、特権エスカレーション攻撃に Kubelet 認証情報を使用するのを防ぎます。また、インスタンス エスカレーション攻撃に VM ID を使用するのも防ぎます。

制限事項

  • メタデータ隠蔽は、kube-env とノードのインスタンス ID トークンへのアクセスだけを保護します。
  • メタデータ隠蔽は、ノードのサービス アカウントへのアクセスを制限しません。
  • メタデータ隠蔽は、他の関連するインスタンス メタデータへのアクセスを制限しません。
  • メタデータ隠蔽は、その他の以前のメタデータ API へのアクセスを制限しません。

メタデータ隠蔽を使用した新しいクラスタまたはノードプールの作成

サービス アカウントの作成後、gcloud コマンドライン ツールを使用して新しいクラスタを作成し、メタデータ隠蔽を有効にできます。

メタデータ隠蔽が有効になっているクラスタを作成するには、シェルまたはターミナル ウィンドウで次のコマンドを実行します。

gcloud beta container clusters create cluster-name \
  --workload-metadata-from-node=SECURE \
  --service-account=$NODE_SA_EMAIL \
  --metadata disable-legacy-endpoints=true \
  [additional parameters and flags omitted]

ここで

  • cluster-name は作成するクラスタの名前です。
  • --workload-metadata-from-node は、SECURE に設定されています。フラグを EXPOSED または UNSPECIFIED に設定すると、メタデータ隠蔽が無効になります。

ID トークン メタデータがクラスタのワークロードから隠蔽されていることを確認する

メタデータを隠蔽するときは、ノードのインスタンス ID トークンを介して署名をリクエストできないようにする必要があります。リクエストが隠蔽されているメタデータをユーザーに明示的に通知することを確認するには、ポッド内から次の curl コマンドを実行します。

root@pod-name# curl -H "Metadata-Flavor: Google" \
'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://www.example.com'
This metadata endpoint is concealed.