クラスタのセキュリティを強化する


このページでは、Google Kubernetes Engine(GKE)クラスタを強化するための最新のベスト プラクティスを実装する方法について説明します。このガイドでは、クラスタの作成時にお客様の操作が必要となる価値のあるセキュリティ対策を優先します。重要性の低い機能、デフォルトでセキュアな設定、作成後に有効にできる項目についてはドキュメントの後半でご説明します。

このドキュメントは、組織のデータを不正アクセスから保護するためのポリシーと手順を定義、管理、実装するセキュリティ スペシャリストを対象としています。Google Cloud のコンテンツで参照する一般的なロールとタスク例の詳細については、一般的な GKE Enterprise ユーザーロールとタスクをご覧ください。

このページを読む前に、次のことをよく理解しておいてください。

GKE で新しいクラスタを作成する場合、こうした保護の大部分がデフォルトで有効になっています。既存のクラスタをアップグレードする場合は、この強化ガイドを定期的に確認し、新しい機能を有効にしてください。

Autopilot モードで作成されたクラスタは、デフォルトで多くの GKE 強化機能を実装しています。

セキュリティ状況の分析を使用すると、こうした推奨事項の多く、またその他構成の誤りが自動的に確認されます。

GKE インフラストラクチャを適切なタイミングでアップグレードする

CIS GKE ベンチマークの推奨事項: 6.5.3。ノードの自動アップグレードが GKE ノードに対して有効になっていることを確認する

セキュリティを向上させる最も簡単な方法の 1 つに、Kubernetes のバージョンを最新の状態に保つことがあります。Kubernetes は頻繁に新しいセキュリティ機能を導入し、セキュリティ パッチを提供しています。

セキュリティ パッチの詳細については、GKE セキュリティに関する情報を参照してください。

Google Kubernetes Engine では、コントロール プレーンへのパッチやアップグレードが自動的に行われます。ノードの自動アップグレードでも、クラスタ内のノードが自動的にアップグレードされます。

ノードの自動アップグレードは、Google Cloud コンソールを使用して作成されたクラスタに対しては 2019 年 6 月から、API を使用して作成されたクラスタに対しては 2019 年 11 月 11 日からデフォルトで有効になっています。

ノードの自動アップグレードを無効にする場合は、自身の都合に合わせて、毎月アップグレードすることを推奨します。古いクラスタでは、ノードの自動アップグレードを有効にする設定にしたうえで、重要なパッチについて GKE セキュリティ情報に厳密に従ってください。

詳細は、ノードの自動アップグレードをご覧ください。

コントロール プレーンとノードへのネットワーク アクセスを制限する

CIS GKE ベンチマークの推奨事項: 6.6.2. VPC ネイティブ クラスタを優先する、6.6.3. 認証ネットワークが有効であることを確認する、6.6.4.クラスタが非公開エンドポイント有効と公開アクセス無効で作成されていることを確認する、6.6.5. クラスタがプライベート ノードで作成されていることを確認する

GKE のクラスタ コントロール プレーンとノードには、任意の IP アドレスからアクセスできる、インターネット上でルーティング可能なアドレスがデフォルトで付与されています。

ベスト プラクティス:

クラスタ コントロール プレーンとノードのインターネットへの公開を制限します。

コントロール プレーンへのアクセスを制限する

GKE クラスタ コントロール プレーンへのアクセスを制限するには、コントロール プレーン アクセスを構成するをご覧ください。ネットワーク レベルの保護には、次のオプションがあります。

  • DNS ベースのエンドポイントが有効(推奨): VPC Service Controls を使用して、DNS ベースのエンドポイントにアクセスできるユーザーを制御できます。VPC Service Controls を使用すると、ネットワーク送信元などのコンテキスト対応属性を使用して、プロジェクト内のすべての Google API に 1 つのセキュリティ パラメータを定義できます。これらの設定は、すべての Google API でプロジェクトに対して一元的に制御できるため、アクセスルールを構成する場所の数を減らすことができます。

  • 外部 IP ベースのエンドポイントと内部 IP ベースのエンドポイントへのアクセスが無効: IP ベースのエンドポイントを介したコントロール プレーンへのすべてのアクセスがブロックされます。

  • 外部 IP ベースのエンドポイント アクセスが無効: 両方のコントロール プレーンへのすべてのインターネット アクセスがブロックされます。Cloud InterconnectCloud VPN を使用してオンプレミス ネットワークから Google Cloud への接続を構成している場合に適しています。これらを用いれば、企業ネットワークとクラウド VPC を効率的に接続できます。

  • 外部 IP ベースのエンドポイント アクセスが有効、承認済みネットワークが有効: このオプションでは、定義するソース IP アドレスからコントロール プレーンへのアクセスが制限されます。これは、既存の VPN インフラストラクチャがない場合や、リモート ユーザーや支社が企業 VPN や Cloud Interconnect / Cloud VPN を使用せずに公共のインターネット経由で接続する場合に適しています。

  • 外部エンドポイント アクセスが有効、承認済みネットワークが無効: インターネット上の誰でもコントロール プレーンにネットワーク接続できるようになります。

IP ベースのエンドポイントを使用する場合は、クラスタで承認済みネットワークを使用することをおすすめします。

これにより、以下がコントロール プレーンにアクセス可能になります。

  • 承認済みネットワークで許可された CIDR。
  • クラスタの VPC 内のノード。
  • クラスタ管理用に Google が予約した IP アドレス。

ノードへのアクセスを制限する

ベスト プラクティス:

クラスタでプライベート ノードを有効にして、外部クライアントがノードにアクセスできないようにします。

ノードへの直接的なインターネット アクセスを無効にするには、クラスタの作成時に gcloud CLI オプション --enable-private-nodes を指定します。

これにより GKE が内部 IP アドレスを持つノードをプロビジョニングするように指示するため、公共のインターネット経由でノードに直接アクセスすることはできません。

最小権限のファイアウォール ルールを使用する

ファイアウォール ルールには最小権限の原則を使用することで、意図しないアクセスのリスクを最小限に抑える

GKE は、システム機能を有効にし、適切なセキュリティ対策を適用するために、デフォルトの VPC ファイアウォール ルールを作成します。自動作成されるファイアウォール ルールの一覧については、自動的に作成されるファイアウォール ルールをご覧ください。

GKE は、これらのデフォルトのファイアウォール ルールを優先度 1000 で作成します。デバッグ用の allow-all ファイアウォール ルールなど、優先度の高く制限の緩いファイアウォール ルールを作成すると、クラスタが意図しないアクセスを受けるリスクがあります。

グループ認証

CIS GKE ベンチマークの推奨事項: 6.8.3. RBAC 向け Google グループで Kubernetes RBAC ユーザーを管理することを検討する

グループを使用してユーザーを管理する必要があります。グループを使用すると、ID 管理システムと ID 管理者を使用して ID を制御できます。グループ メンバーシップを調整するだけで、メンバーをグループに追加または削除するたびに RBAC の構成を更新する必要がなくなります。

Google グループを使用してユーザー権限を管理するには、クラスタで RBAC 用 Google グループを有効にする必要があります。これにより、同じ権限を持つユーザーを簡単に管理でき、ID 管理者は、ユーザーの一貫した一元管理ができるようになります。

RBAC 向け Google グループを有効にする手順については、RBAC の Google グループをご覧ください。

コンテナノードを選択する

次のセクションでは、安全なノード構成の選択について説明します。

シールドされた GKE ノードを有効にする

CIS GKE ベンチマークの推奨事項: 6.5.5。シールドされた GKE ノードが有効になっていることを確認する

シールドされた GKE ノードは強固で検証可能なノード ID と完全性を備え、GKE ノードのセキュリティが高められているので、すべての GKE クラスタでこれを有効にすることをおすすめしています。

シールドされた GKE ノードは、クラスタの作成時または更新時に有効にできます。シールドされた GKE ノードを有効にするときは、セキュアブートも有効にしてください。サードパーティの未署名のカーネル モジュールが必要な場合は、セキュアブートを使用しないでください。シールドされた GKE ノードを有効にする方法と、シールドされた GKE ノードを使用してセキュアブートを有効にする方法については、シールドされた GKE ノードの使用をご覧ください。

containerd ランタイムで強化されたノードイメージを選択する

containerd を含む Container-Optimized OS(cos_containerd)イメージは、containerd を含む Container-Optimized OS イメージのバリアントであり、メインのコンテナ ランタイムとして Kubernetes に直接統合されています。

containerd は Docker のコアランタイム コンポーネントで、Kubernetes Container Runtime Interface(CRI)にコアコンテナ機能を提供するように設計されています。完全な Docker デーモンよりもはるかに簡潔なので、攻撃対象領域が小さくなります。

クラスタで cos_containerd イメージを使用するには、コンテナ イメージをご覧ください。

cos_containerd イメージは、コンテナを実行するためにカスタムビルドされ、最適化され、強化されていることから、GKE の推奨イメージです。

Workload Identity Federation for GKE を有効にする

CIS GKE ベンチマークの推奨事項: 6.2.2。専用の Google Cloud サービス アカウントと Workload Identity を優先的に使用する

Google Cloud APIs に対する認証に推奨される方法は、GKE 用 Workload Identity 連携です。

GKE 用 Workload Identity 連携は、メタデータ隠蔽機能の使用に代わるものであるため、この 2 つのアプローチに互換性はありません。メタデータ隠蔽機能によって保護される機密メタデータは、GKE 用 Workload Identity 連携によっても保護されます。

GKE Sandbox によるワークロード分離の強化

CIS GKE ベンチマークの推奨事項: 6.10.4。信頼できないワークロードの場合は特に、ワークロードの分離を強化するために GKE Sandbox の使用を検討する

GKE Sandbox は、セキュリティに新たなレイヤを追加し、悪意のあるコードからクラスタノードのホストカーネルを保護します。

サンドボックス環境でコンテナを実行すると、ほとんどのコンテナ エスケープ攻撃(ローカル権限昇格攻撃とも呼ばれる)を軽減できます。過去のコンテナ エスケープの脆弱性については、セキュリティに関する公開情報をご覧ください。このタイプの攻撃では、攻撃者はコンテナのホスト VM にアクセスします。このため、同じ VM 上の他のコンテナにもアクセスされる可能性があります。GKE Sandbox などのサンドボックスは、このような攻撃の影響を抑えるのに役立ちます。

次のような状況では、ワークロードのサンドボックス化を検討する必要があります。

  • ワークロードが信頼できないコードを実行する
  • ワークロード内のコンテナが攻撃者によって不正使用された場合の影響を制限する必要がある。

GKE Sandbox の使用方法については、GKE Sandbox によるワークロード分離の強化をご覧ください。

セキュリティ情報の通知を有効にする

クラスタに関連するセキュリティ情報が利用可能になると、GKE はそれらのイベントに関する通知を構成済みの Pub/Sub トピックにメッセージとして公開します。これらの通知を Pub/Sub サブスクリプションで受信し、サードパーティ サービスと統合して、受信したい通知タイプをフィルタできます。

GKE クラスタ通知を使用したセキュリティ情報の受信の詳細については、クラスタ通知をご覧ください。

安全でない kubelet 読み取り専用ポートを無効にする

kubelet 読み取り専用ポートを無効にし、ポート 10255 を使用するワークロードがより安全なポート 10250 を使用するように切り替えます。

ノードで実行されている kubelet プロセスは、安全でないポート 10255 を使用して読み取り専用 API を提供します。Kubernetes では、このポートに対して認証や承認のチェックが行われません。kubelet は、より安全な認証済みのポート 10250 で同じエンドポイントにサービスを提供します。

手順については、GKE クラスタで kubelet の読み取り専用ポートを無効にするをご覧ください。

権限

最小権限の IAM サービス アカウントを使用する

CIS GKE ベンチマークの推奨事項: 6.2.1. GKE クラスタの実行時に Compute Engine のデフォルト サービス アカウントを使用しないようにする

GKE は、ノードに接続されている IAM サービス アカウントを使用して、ロギングやモニタリングなどのシステムタスクを実行します。少なくとも、これらのノード サービス アカウントには、プロジェクトに対する Kubernetes Engine デフォルト ノード サービス アカウントroles/container.defaultNodeServiceAccount)ロールが必要です。デフォルトでは、GKE はプロジェクトで自動的に作成される Compute Engine のデフォルトのサービス アカウントをノード サービス アカウントとして使用します。

プロジェクトまたは組織内の他の機能に Compute Engine のデフォルトのサービス アカウントを使用すると、サービス アカウントに GKE が必要とする以上の権限が付与され、セキュリティ リスクにさらされる可能性があります。

ノードに接続されているサービス アカウントは、ロギングやモニタリングなどのタスクを実行するシステム ワークロードでのみ使用する必要があります。独自のワークロードの場合は、Workload Identity Federation for GKE を使用して ID をプロビジョニングします。

カスタム サービス アカウントを作成して GKE に必要なロールを付与する手順は次のとおりです。

console

  1. Google Cloud コンソールで、Cloud Resource Manager API を有効にします。

    Enable the API

  2. [サービス アカウント] ページに移動します。

    [サービス アカウント] に移動

  3. [ サービス アカウントを作成] をクリックします。
  4. サービス アカウントの名前を入力します。[サービス アカウント ID] フィールドには、名前に基づいてサービス アカウントの一意の ID が自動的に生成されます。
  5. [作成して続行] をクリックします。
  6. [ロールを選択] メニューで、[Kubernetes Engine のデフォルト ノードサービス アカウント] ロールを選択します。
  7. [完了] をクリックします。

gcloud

  1. Cloud Resource Manager API を有効にします。
    gcloud services enable cloudresourcemanager.googleapis.com
  2. サービス アカウントを作成します。
    gcloud iam service-accounts create SERVICE_ACCOUNT_ID \
        --display-name=DISPLAY_NAME

    次のように置き換えます。

    • SERVICE_ACCOUNT_ID: サービス アカウントの一意の ID。
    • DISPLAY_NAME: サービス アカウントの表示名。
  3. サービス アカウントに Kubernetes Engine デフォルト ノード サービス アカウントroles/container.defaultNodeServiceAccount)のロールを付与します。
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member="serviceAccount:SERVICE_ACCOUNT_ID@PROJECT_ID.iam.gserviceaccount.com" \
        --role=roles/container.defaultNodeServiceAccount

    次のように置き換えます。

    • PROJECT_ID: Google Cloud プロジェクト ID
    • SERVICE_ACCOUNT_ID: 作成したサービス アカウント ID。

Config Connector

注: この手順には Config Connector が必要です。Config Connector をクラスタにインストールするには、インストール手順を実施してください。

  1. サービス アカウントを作成するには、次のリソースを service-account.yaml としてダウンロードします。
    apiVersion: iam.cnrm.cloud.google.com/v1beta1
    kind: IAMServiceAccount
    metadata:
      name: [SA_NAME]
    spec:
      displayName: [DISPLAY_NAME]

    次のように置き換えます。

    • [SA_NAME]: 新しいサービス アカウントの名前。
    • [DISPLAY_NAME]: サービス アカウントの表示名。
  2. サービス アカウントを作成します。
    kubectl apply -f service-account.yaml
  3. サービス アカウントに roles/logging.logWriter ロールを適用します。
    1. 次のリソースを policy-logging.yaml としてダウンロードします。
      apiVersion: iam.cnrm.cloud.google.com/v1beta1
      kind: IAMPolicyMember
      metadata:
        name: policy-logging
      spec:
        member: serviceAccount:[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com
        role: roles/logging.logWriter
        resourceRef:
          kind: Project
          name: [PROJECT_ID]

      次のように置き換えます。

      • [SA_NAME]: サービス アカウントの名前。
      • [PROJECT_ID]: Google Cloud プロジェクト ID
    2. ロールをサービス アカウントに適用します。
      kubectl apply -f policy-logging.yaml
  4. サービス アカウントに roles/monitoring.metricWriter ロールを適用します。
    1. 次のリソースを policy-metrics-writer.yaml としてダウンロードします。[SA_NAME][PROJECT_ID] はお客様自身の情報に置き換えてください。
      apiVersion: iam.cnrm.cloud.google.com/v1beta1
      kind: IAMPolicyMember
      metadata:
        name: policy-metrics-writer
      spec:
        member: serviceAccount:[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com
        role: roles/monitoring.metricWriter
        resourceRef:
          kind: Project
          name: [PROJECT_ID]

      次のように置き換えます。

      • [SA_NAME]: サービス アカウントの名前。
      • [PROJECT_ID]: Google Cloud プロジェクト ID
    2. ロールをサービス アカウントに適用します。
      kubectl apply -f policy-metrics-writer.yaml
  5. サービス アカウントに roles/monitoring.viewer ロールを適用します。
    1. 次のリソースを policy-monitoring.yaml としてダウンロードします。
      apiVersion: iam.cnrm.cloud.google.com/v1beta1
      kind: IAMPolicyMember
      metadata:
        name: policy-monitoring
      spec:
        member: serviceAccount:[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com
        role: roles/monitoring.viewer
        resourceRef:
          kind: Project
          name: [PROJECT_ID]

      次のように置き換えます。

      • [SA_NAME]: サービス アカウントの名前。
      • [PROJECT_ID]: Google Cloud プロジェクト ID
    2. ロールをサービス アカウントに適用します。
      kubectl apply -f policy-monitoring.yaml
  6. サービス アカウントに roles/autoscaling.metricsWriter ロールを適用します。
    1. 次のリソースを policy-autoscaling-metrics-writer.yaml としてダウンロードします。
      apiVersion: iam.cnrm.cloud.google.com/v1beta1
      kind: IAMPolicyMember
      metadata:
        name: policy-autoscaling-metrics-writer
      spec:
        member: serviceAccount:[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com
        role: roles/autoscaling.metricsWriter
        resourceRef:
          kind: Project
          name: [PROJECT_ID]

      次のように置き換えます。

      • [SA_NAME]: サービス アカウントの名前。
      • [PROJECT_ID]: Google Cloud プロジェクト ID
    2. ロールをサービス アカウントに適用します。
      kubectl apply -f policy-autoscaling-metrics-writer.yaml

このサービス アカウントは、他のプロジェクトのリソースにも使用できます。手順については、プロジェクト間でのサービス アカウントの権限借用を有効にするをご覧ください。

限定公開イメージ リポジトリへのアクセス権を付与する

Artifact Registry で非公開イメージを使用するには、サービス アカウントに Artifact Registry 読み取りロールroles/artifactregistry.reader)を付与します。

gcloud

gcloud artifacts repositories add-iam-policy-binding REPOSITORY_NAME \
    --member=serviceAccount:SA_NAME@PROJECT_ID.iam.gserviceaccount.com \
    --role=roles/artifactregistry.reader

REPOSITORY_NAME を Artifact Registry リポジトリの名前に置き換えます。

Config Connector

注: この手順には Config Connector が必要です。Config Connector をクラスタにインストールするには、インストール手順を実施してください。

  1. 次のマニフェストを policy-artifact-registry-reader.yaml として保存します。

    apiVersion: iam.cnrm.cloud.google.com/v1beta1
    kind: IAMPolicyMember
    metadata:
      name: policy-artifact-registry-reader
    spec:
      member: serviceAccount:"SA_NAME"@"PROJECT_ID".iam.gserviceaccount.com
      role: roles/artifactregistry.reader
      resourceRef:
        apiVersion: artifactregistry.cnrm.cloud.google.com/v1beta1
        kind: ArtifactRegistryRepository
        name: "REPOSITORY_NAME"

    次のように置き換えます。

    • SA_NAME: IAM サービス アカウントの名前。
    • PROJECT_ID: Google Cloud プロジェクト ID。
    • REPOSITORY_NAME: Artifact Registry リポジトリの名前。
  2. Artifact Registry 読み取りロールをサービス アカウントに付与します。

    kubectl apply -f policy-artifact-registry-reader.yaml
    

Container Registry の限定公開イメージを使用する場合は、それらのイメージに対するアクセス権も付与する必要があります。

gcloud

gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME \
  --member=serviceAccount:SA_NAME@PROJECT_ID.iam.gserviceaccount.com \
  --role=roles/storage.objectViewer

イメージを保存するバケットには、次の形式の名前 BUCKET_NAME が付いています。

  • artifacts.PROJECT_ID.appspot.comgcr.io ホスト内のレジストリに push されたイメージの場合。
  • STORAGE_REGION.artifacts.PROJECT_ID.appspot.com

次のように置き換えます。

  • PROJECT_ID: Google Cloud コンソール プロジェクト ID。
  • STORAGE_REGION: ストレージ バケットの場所。
    • us: us.gcr.io ホストのレジストリの場合
    • eu: eu.gcr.io ホストのレジストリの場合
    • asiaasia.gcr.io ホストのレジストリの場合

コマンドの詳細については、gcloud storage buckets add-iam-policy-binding のドキュメントをご覧ください。

Config Connector

注: この手順には Config Connector が必要です。Config Connector をクラスタにインストールするには、インストール手順に従ってください。

storage.objectViewer ロールをサービス アカウントに適用します。次のリソースを policy-object-viewer.yaml としてダウンロードします。[SA_NAME][PROJECT_ID] はお客様自身の情報に置き換えてください。

apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
  name: policy-object-viewer
spec:
  member: serviceAccount:[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com
  role: roles/storage.objectViewer
  resourceRef:
    kind: Project
    name: [PROJECT_ID]
kubectl apply -f policy-object-viewer.yaml

他のユーザーがこのサービス アカウントで新しいクラスタまたはノードプールを作成できるようにするには、そのサービス アカウントのユーザーにサービス アカウント ユーザーロールを付与します。

gcloud

gcloud iam service-accounts add-iam-policy-binding \
    SA_NAME@PROJECT_ID.iam.gserviceaccount.com \
    --member=user:USER \
    --role=roles/iam.serviceAccountUser

Config Connector

注: この手順には Config Connector が必要です。Config Connector をクラスタにインストールするには、インストール手順に従ってください。

iam.serviceAccountUser ロールをサービス アカウントに適用します。次のリソースを policy-service-account-user.yaml としてダウンロードします。[SA_NAME][PROJECT_ID] はお客様自身の情報に置き換えてください。

apiVersion: iam.cnrm.cloud.google.com/v1beta1
kind: IAMPolicyMember
metadata:
  name: policy-service-account-user
spec:
  member: serviceAccount:[SA_NAME]@[PROJECT_ID].iam.gserviceaccount.com
  role: roles/iam.serviceAccountUser
  resourceRef:
    kind: Project
    name: [PROJECT_ID]
kubectl apply -f policy-service-account-user.yaml

既存の Standard クラスタの場合、この新しいサービス アカウントを使用して新しいノードプールを作成できるようになりました。Autopilot クラスタの場合は、このサービス アカウントを使用して新しいクラスタを作成する必要があります。手順については、Autopilot クラスタを作成するをご覧ください。

  • 新しいサービス アカウントを使用するノードプールを作成します。

    gcloud container node-pools create NODE_POOL_NAME \
    --service-account=SA_NAME@PROJECT_ID.iam.gserviceaccount.com \
    --cluster=CLUSTER_NAME

GKE クラスタが他の Google Cloud サービスにアクセスする必要がある場合は、GKE 用 Workload Identity 連携を使用する必要があります。

クラスタ API 検出へのアクセスを制限する

Kubernetes はデフォルトで、CustomResourceDefinitions の API など、クラスタの API に関する情報に幅広くアクセスできる、制約の緩いディスカバリ ClusterRoleBindings のセットでクラスタをブート ストラップします。

system:discoverysystem:basic-user の ClusterRoleBindings のサブジェクトにある system:authenticated グループには、認証済みユーザーなら誰でも含めることができ(Google アカウントを持つユーザーもこれに含まれます)、そのためこのグループは GKE のクラスタのセキュリティにとってむしろ無意味なレベルに相当することに留意する必要があります。詳細については、デフォルトのロールとグループを使用しないをご覧ください。

クラスタのディスカバリ API を強化する場合は、次のうち 1 つ以上を実施することを検討してください。

  • コントロール プレーンへのアクセスに DNS ベースのエンドポイントのみを有効にします。
  • 設定済みの IP 範囲へのアクセスを制限するように承認済みネットワークを構成します。
  • コントロール プレーンへのアクセスを制限し、プライベート ノードを有効にします。

これらのオプションが GKE のユースケースに適していない場合、すべての API 検出情報(CustomResources のスキーマ、APIService の定義、拡張 API サーバーでホストされている検出情報)を一般公開として扱います。

Namespace とロールベース アクセス制御を使用してクラスタ リソースへのアクセスを制限する

CIS GKE ベンチマークの推奨事項: 5.6.1。Namespace を使用してリソース間の管理境界を作成する

各チームと環境に個別の Namespace またはクラスタを作成して、チームに付与する Kubernetes へのアクセス権限を最低限に抑えます。アカウンタビリティとチャージバックに基づいて各名前空間にコストセンターと適切なラベルを割り当てます。開発者に付与する名前空間へのアクセス権は(特に本番環境において)、アプリケーションのデプロイと管理に必要なレベルのみに制限します。ユーザーがクラスタに対して行う必要があるタスクをマッピングし、各タスクの実行に必要な権限を定義します。

Namespace の作成について詳しくは、Kubernetes のドキュメントをご覧ください。RBAC 構成を計画する際のベスト プラクティスについては、GKE RBAC のベスト プラクティスをご覧ください。

IAMロールベースのアクセス制御(RBAC) は相互に連携するため、クラスタ内のリソースを操作するには、エンティティに双方のレベルで十分な権限を与える必要があります。

GKE に適した IAM ロールをグループやユーザーに割り当て、プロジェクト レベルで権限を提供します。RBAC を使ってクラスタと Namespace レベルで権限を付与します。詳細については、アクセス制御をご覧ください。

IAM と RBAC の権限を名前空間と併用すると、Google Cloud コンソールのクラスタ リソースに対するユーザー操作を制限できます。詳細については、アクセスを有効にしてクラスタ リソースを名前空間ごとに表示するをご覧ください。

Pod 間のトラフィックをネットワーク ポリシーで制限する

CIS GKE ベンチマークの推奨事項: 6.6.7。ネットワーク ポリシーが有効であることを確認し、必要に応じて設定する

デフォルトでは、クラスタ内のすべてのポッドが相互通信できます。ポッド間通信は、ワークロードのニーズに応じて制御してください。

サービスへのネットワーク アクセスを制限することで、攻撃者によるクラスタ内移動の難易度を大幅に上げることができ、偶発的または意図的な DoS 攻撃に対してサービスをある程度は保護できます。トラフィックを制御する 2 つの推奨方法は次のとおりです。

  1. Istio を使用します。負荷分散、サービス許可、スロットリング、割り当て、指標などの詳細については、Google Kubernetes Engine に Istio をインストールするをご覧ください。
  2. Kubernetes ネットワーク ポリシーを使用します。クラスタ ネットワーク ポリシーの作成をご覧ください。Kubernetes で公開されている基本的なアクセス制御機能をお探しの場合は、これを選択します。ネットワーク ポリシーを使用してトラフィックを制限する一般的なアプローチを実装するには、GKE Enterprise セキュリティ ブループリントの実装ガイドに従ってください。Kubernetes のドキュメントには簡単な nginx デプロイに関する優れたチュートリアルがあります。ネットワーク ポリシー ロギングを使用して、ネットワーク ポリシーが期待どおりに動作していることを確認します。

Istio とネットワーク ポリシーは、必要に応じて併用できます。

Secret 管理

CIS GKE ベンチマークの推奨事項: 6.3.1. Cloud KMS で管理されている鍵を使用して Kubernetes Secrets を暗号化する

Secret を etcd に保存するなど、機密データを保護するために追加の層を設けることをおすすめします。これを行うには、GKE クラスタと統合されたシークレット マネージャーを構成する必要があります。一部のソリューションは GKE と Google Distributed Cloud の両方で機能するため、複数の環境にまたがってワークロードを実行している場合は、こうしたソリューションのほうが適している可能性があります。HashiCorp Vault などの外部シークレット マネージャーを使用する場合は、クラスタを作成する前に設定する必要があります。

Secret を管理する方法はいくつかあります。

  • Kubernetes Secret は、GKE でネイティブに使用できます。アプリケーション レイヤで Application-layer secrets encryption を使用して、自分が管理している鍵で Kubernetes Secret を暗号化することもできます。
  • HashiCorp Vault などのシークレット マネージャーを使用できます。強化 HA モードで実行すると、本番環境に適応した一貫性のあるシークレット管理が可能になります。HashiCorp Vault への認証には、Kubernetes サービス アカウントまたは Google Cloud サービス アカウントを使用できます。Vault と GKE を使用する詳しい方法については、Kubernetes での HashiCorp Vault の実行と接続を参照してください。

GKE の VM は、etcd を含むストレージ レイヤではデフォルトで暗号化されます。

アドミッション コントローラを使用してポリシーを適用する

アドミッション コントローラは、クラスタの使用方法を管理および適用するプラグインです。Kubernetes の高度なセキュリティ機能の一部を使用するには、アドミッション コントローラを有効にする必要があります。また、クラスタを強化するための多層防御アプローチの重要な部分でもあります。

デフォルトでは、Kubernetes のポッドは、必要とする以上の機能で動作します。Pod の機能は、そのワークロードに必要な機能だけに制限するようにしてください。

Kubernetes には、明示的に付与された機能のみを使用して Pod を実行するように制限する制御手段が多数あります。たとえば、Policy Controller はフリート内のクラスタで使用できます。Kubernetes には PodSecurity アドミッション コントローラが組み込まれており、個々のクラスタに Pod セキュリティ標準を適用できます。

Policy Controller は、宣言型ポリシーを使用して GKE クラスタにセキュリティを大規模に適用し、検証できる GKE Enterprise の機能です。Policy Controller を使用して GKE クラスタに宣言型制御を適用する方法については、Policy Controller のインストールをご覧ください。

PodSecurity アドミッション コントローラを使用すると、特定の Namespace またはクラスタ全体で事前定義済みのポリシーを適用できます。これらのポリシーは、異なる Pod セキュリティ標準に対応しています。

ワークロードの自己変更機能を制限する

特定の Kubernetes ワークロード(特にシステム ワークロード)には、自己変更の権限があります。たとえば、一部のワークロードは垂直方向に自動スケーリングされます。これは便利ですが、すでにノードを不正使用した攻撃者がクラスタ内でさらにエスカレーションする可能性があります。たとえば、攻撃者がノード上のワークロード自体を変更して、同じ名前空間内に存在する、より権限の高いサービス アカウントとして実行するおそれがあります。

理想的には、ワークロードにはそもそも自己変更機能を付与するべきではありません。自己変更が必要な場合は、オープンソースの Gatekeeper ライブラリから NoUpdateServiceAccount などの Gatekeeper または Policy Controller の制約を適用して権限を制限できます。これにより、いくつかの有用なセキュリティ ポリシーが提供されます。

ポリシーをデプロイする場合、通常はクラスタのライフサイクルを管理するコントローラがポリシーをバイパスできるようにする必要があります。これは、コントローラがクラスタに変更を加える(クラスタのアップグレードを適用するなど)ことができるようにするために必要です。たとえば、NoUpdateServiceAccount ポリシーを GKE にデプロイする場合は、Constraint で次のパラメータを設定する必要があります。

parameters:
  allowedGroups:
  - system:masters
  allowedUsers:
  - system:addon-manager

非推奨の gcePersistentDisk ボリューム タイプの使用を制限する

非推奨の gcePersistentDisk ボリューム タイプを使用すると、Compute Engine 永続ディスクを Pod にマウントできます。ワークロードでの gcePersistentDisk ボリューム タイプの使用を制限することをおすすめします。GKE は、このボリューム タイプをマウントするときに Pod の IAM 認証チェックを行いません。ただし、Google Cloud は、基盤となる VM にディスクをアタッチするときに認証チェックを実行します。Namespace に Pod を作成する能力がすでにある攻撃者は、Google Cloud プロジェクトの Compute Engine 永続ディスクのコンテンツにアクセスできます。

Compute Engine 永続ディスクにアクセスして使用する場合は、代わりに PersistentVolumes と PersistentVolumeClaims を使用します。gcePersistentDisk ボリューム タイプの使用を防止するセキュリティ ポリシーをクラスタに適用します。

gcePersistentDiskボリューム タイプの使用を防止するには、Baseline または PodSecurity アドミッション コントローラによる制限ありポリシーを適用するか、または Policy Controller か Gatekeeper アドミッション コントローラの中でカスタム制約を定義することもできます。

このボリューム タイプを制限するカスタム制約を定義する手順は次のとおりです。

  1. Policy Controller や Gatekeeper OPA などのポリシーベースのアドミッション コントローラをインストールします。

    Policy Controller

    クラスタに Policy Controller をインストールします

    GKE ユーザーの場合、Policy Controller は有償の機能です。Policy Controller はオープンソースの Gatekeeper をベースにしていますが、完全な制約テンプレート ライブラリ、ポリシー バンドル、Google Cloud コンソール ダッシュボードとの統合にもアクセスして、クラスタのモニタリングとメンテナンスを行うことができます。ポリシー バンドルはクラスタに適用できる独自のベスト プラクティスで、CIS Kubernetes Benchmark のように推奨事項に基づくバンドルが含まれています。

    Gatekeeper

    クラスタに Gatekeeper をインストールします

    Autopilot クラスタの場合は、テキスト エディタで Gatekeeper gatekeeper.yaml マニフェストを開きます。次の例のように、MutatingWebhookConfiguration 仕様の rules フィールドを変更して、ワイルドカード(*)文字を特定の API グループとリソース名に置き換えます。

    apiVersion: admissionregistration.k8s.io/v1
    kind: MutatingWebhookConfiguration
    ...
    webhooks:
    - admissionReviewVersions:
      - v1
      - v1beta1
      ...
      rules:
      - apiGroups:
        - core
        - batch
        - apps
        apiVersions:
        - '*'
        operations:
        - CREATE
        - UPDATE
        resources:
        - Pod
        - Deployment
        - Job
        - Volume
        - Container
        - StatefulSet
        - StorageClass
        - Secret
        - ConfigMap
      sideEffects: None
      timeoutSeconds: 1
    

    更新された gatekeeper.yaml マニフェストを Autopilot クラスタに適用して、Gatekeeper をインストールします。組み込みのセキュリティ対策として、Autopilot は変更用アドミッション Webhook にワイルドカード文字を使用を禁止しているため、これは必須です。

  2. 組み込みの Pod Security Policy Volume Types ConstraintTemplate をデプロイします。

    kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/volumes/template.yaml
    
  3. 許可されたボリューム タイプのリストとして、次の制約を constraint.yaml として保存します。

    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: k8sPSPVolumeTypes
    metadata:
      name: nogcepersistentdisk
    spec:
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pods"]
      parameters:
        volumes: ["configMap", "csi", "projected", "secret", "downwardAPI", "persistentVolumeClaim", "emptyDir", "nfs", "hostPath"]
    

    この制約は、ボリュームを spec.parameters.volumes フィールドのリストに制限します。

  4. 制約をデプロイします。

    kubectl apply -f constraint.yaml
    

クラスタ構成を監視する

クラスタ構成と定義した設定に矛盾がないか監査してください。

セキュリティの健全性分析を使用すると、この強化ガイドで説明した推奨事項の多くを自動的に確認できるだけでなく、構成の誤りも検出できます。

安全なデフォルト

以降のセクションでは、新しいクラスタにおいて、デフォルトで安全に構成されるオプションについて説明します。既存のクラスタが安全に構成されていることを確認する必要があります。

ノードのメタデータを保護する

CIS GKE ベンチマークの推奨事項: 6.4.1。従来の Compute Engine インスタンスのメタデータ API が無効であることを確認する、6.4.2. GKE メタデータ サーバーが有効になっていることを確認する

Compute Engine メタデータ サーバー エンドポイント v0.1v1beta1 は、2020 年 9 月 30 日にサポート終了となり、停止されました。これらのエンドポイントは、メタデータ クエリヘッダーを適用されませんでした。停止スケジュールについては、v0.1v1beta1 メタデータ サーバー エンドポイントのサポート終了をご覧ください。

Kubernetes に対する攻撃の中には、VM のメタデータ サーバーへのアクセスを使用して認証情報を抽出するものがあります。GKE 用 Workload Identity 連携またはメタデータ隠蔽を使用している場合、これらの攻撃はブロックされます。

以前のクライアント認証方式を無効のままにする

CIS GKE ベンチマークの推奨事項: 6.8.1。静的パスワードを使用する基本認証が無効になっていることを確認する、6.8.2. クライアント証明書を使用する認証が無効になっていることを確認する

Kubernetes API サーバーに対する認証方法は、複数存在します。GKE でサポートされる方法は、サービス アカウントの署名なしトークン、OAuth トークン、x509 クライアント証明書です。GKE では OAuth トークンベースで gcloud での認証を管理し、Kubernetes 構成の設定、アクセス トークンの取得、トークンの更新を行います。

GKE を OAuth と統合する前は、1 回限りの x509 証明書または静的パスワードが唯一の認証方法でしたが、現在は推奨されておらず、無効にする必要があります。これらの方法は、クラスタの侵害に対する攻撃の範囲が広く、GKE バージョン 1.12 以降、デフォルトで無効になっています。以前の認証方法を使用している場合は、無効にすることをおすすめします。GKE バージョン 1.19 以降では、静的パスワードによる認証は非推奨となり、削除されています。

既存のクラスタは OAuth に移動する必要があります。クラスタの外部システムが長期間の認証情報を必要とする場合は、必要な権限を持つ Google サービス アカウントまたは Kubernetes サービス アカウントを作成し、そのキーをエクスポートすることをおすすめします。

既存のクラスタを更新して静的パスワードを削除するには、静的パスワードによる認証の無効化をご覧ください。

現在、既存のクラスタから発行済みの有効なクライアント証明書を削除する方法はありませんが、RBAC が有効で ABAC が無効ならば証明書に権限はありません。

Cloud Logging を有効のままにする

CIS GKE ベンチマークの推奨事項: 6.7.1。Stackdriver Kubernetes のロギングとモニタリングが有効になっていることを確認する

運用上のオーバーヘッドを削減し、ログの統合ビューを維持するには、クラスタがデプロイされているすべての場所に一貫性のあるロギング方法を実装します。GKE Enterprise クラスタはデフォルトで Cloud Logging と統合されており、その構成を維持する必要があります。

すべての GKE クラスタではデフォルトで Kubernetes 監査ロギングが有効になっています。これにより、Kubernetes API サーバーに対する呼び出しの記録が時系列で保持されます。Kubernetes 監査ログのエントリは、不審な API リクエストの調査、統計情報の収集、不要な API 呼び出しに対するモニタリング アラートの作成に役立ちます。

GKE クラスタは Kubernetes Audit Logging を Cloud Audit Logs と Cloud Logging に統合します。ログは、Cloud Logging から独自のロギング システムにルーティングできます。

Kubernetes ウェブ UI(ダッシュボード)を無効のままにする

CIS GKE ベンチマークの推奨事項: 6.10.1。Kubernetes ウェブ UI が無効になっていることを確認する

GKE での実行時に Kubernetes ウェブ UI(ダッシュボード)を有効にしないでください。

Kubernetes ウェブ UI(ダッシュボード)は、高い特権を持つ Kubernetes サービス アカウントと関連付けられています。Google Cloud コンソールにほぼ同じ機能があるため、こうした権限は必要ありません。

Kubernetes ウェブ UI を無効にするには、次のコマンドを実行します。

gcloud container clusters update CLUSTER_NAME \
    --update-addons=KubernetesDashboard=DISABLED

ABAC を無効のままにする

CIS GKE ベンチマークの推奨事項: 6.8.4。以前の承認(ABAC)が無効になっていることを確認する

GKE で、属性ベースのアクセス制御(ABAC)を無効にし、代わりにロールベースのアクセス制御(RBAC)を使用してください。

ABAC は、GKE バージョン 1.8 以降を使用して作成されたクラスタではデフォルトで無効になります。Kubernetes では、RBAC を使用してリソースに対する権限をクラスタレベルと Namespace レベルで付与します。RBAC では、一連の権限を含むルールを使用してロールを定義できます。RBAC には、ABAC と比較して重要なセキュリティ上の利点があります。

現状で ABAC に依存している場合は、まず RBAC を使用する場合の前提条件を確認してください。クラスタを古いバージョンからアップグレードして ABAC を使用している場合は、次のようにアクセス制御の構成を更新する必要があります。

gcloud container clusters update CLUSTER_NAME \
    --no-enable-legacy-authorization

上記の推奨に従って新しいクラスタを作成するには、次のコマンドを実行します。

gcloud container clusters create CLUSTER_NAME \
    --no-enable-legacy-authorization

DenyServiceExternalIPs アドミッション コントローラを有効のままにする

DenyServiceExternalIPs アドミッション コントローラを無効にしないでください。

DenyServiceExternalIPs アドミッション コントローラは、Service が ExternalIPs を使用できないようにするとともに、既知のセキュリティ脆弱性を緩和します。

GKE バージョン 1.21 以降で作成された新しいクラスタでは、DenyServiceExternalIPs アドミッション コントローラがデフォルトで有効になります。GKE バージョン 1.21 以降にアップグレードしたクラスタでは、次のコマンドを使用してアドミッション コントローラを有効にできます。

gcloud beta container clusters update CLUSTER_NAME \
    --location=LOCATION \
    --no-enable-service-externalips

次のステップ