GKEクラスタで承認済みネットワークの設定でAPIサーバーを保護する方法について

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、 「どうやって直すのか?」 という具体的な修復手順(コンソール、Google Cloud CLI、Terraformなど)まで、分かりやすく解説します。

この記事では、GKEクラスタのコントロールプレーン(マスターノード)に対する承認済みネットワークからのアクセス制限が未設定となっている場合の重大なセキュリティリスクと実践的な対策方法を解説します。デフォルトではインターネット全体(0.0.0.0/0)からのKubernetes APIアクセスが許可されるため、適切な制限設定が不可欠です。

ポリシーの説明

承認済みネットワーク(Master Authorized Networks)は、GKEクラスタのコントロールプレーン(Kubernetes APIサーバー)へのアクセスを特定のIPアドレス範囲(CIDRブロック)に制限するIPベースのファイアウォール機能です。

この機能が未設定の場合:

  • デフォルトでは0.0.0.0/0(インターネット全体)からのアクセスが許可されます
  • インターネット上の誰でも有効な認証情報(kubeconfig、サービスアカウントトークン等)があればKubernetes APIにアクセス可能です
  • これは認証(Authentication)とは別のレイヤーで、ネットワークレベルのアクセス制御を提供します

承認済みネットワークは、Kubernetes APIサーバーへのアクセスを制御する追加の防御層として機能し、認証(Authentication)と認可(Authorization)に加えて、「多層防御(Defense in Depth)」戦略の重要な要素となります。

リスク

承認済みネットワークが未設定の場合、以下の重大なセキュリティリスクが発生します:

  1. インターネットからの無制限アクセス: 認証情報(kubeconfig、サービスアカウントトークン等)が漏洩した場合、世界中のどこからでもクラスタへのアクセスが可能となります
  2. ブルートフォース攻撃とDDoS攻撃:
    • APIサーバーがインターネットに公開されることで、パスワード総当たり攻撃の標的になります
    • 大量のAPIリクエストによるサービス拒否攻撃(DDoS)のリスクが高まります
    • Rate Limitingが適用されていても、グローバルな攻撃には対処が困難です

修復方法

コンソールでの修復手順

Google Cloud コンソールを使用して、承認済みネットワークを設定します。

  1. Google Cloud Consoleにログインし、「Kubernetes Engine」→「クラスタ」に移動します
  2. 対象のクラスタ名をクリックして詳細画面を開きます
  3. 「詳細」タブで「コントロール プレーン ネットワーキング」セクションを確認します
  4. 「編集」アイコン(鉛筆マーク)をクリックします
  1. *「承認済みネットワークを有効にする」**のチェックボックスをオンにします
  2. *「承認済みネットワークを追加」**をクリックします
  3. 以下の情報を入力します:
    • CIDR範囲: アクセスを許可するIPアドレス範囲(例: 10.0.0.0/8)
    • 表示名(オプション): ネットワークの説明(例: 社内ネットワーク)
  1. 必要に応じて、追加のネットワークを設定します
  2. *「保存」**をクリックして変更を適用します

既存クラスタの確認と更新(gcloudコマンド):

# 現在の設定を確認
gcloud container clusters describe [CLUSTER_NAME] \
    --zone=[ZONE] \
    --format="value(masterAuthorizedNetworksConfig)"

# 承認済みネットワークを有効化(ゾーナルクラスタの場合)
# ステップ1: 現在のクライアントIPを含めて有効化(既存接続を維持)
CURRENT_IP=$(curl -s <https://ipinfo.io/ip>)
gcloud container clusters update [CLUSTER_NAME] \
    --zone=[ZONE] \
    --enable-master-authorized-networks \
    --master-authorized-networks="${CURRENT_IP}/32,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"

# ステップ2: 必要に応じて追加のネットワークを設定
gcloud container clusters update [CLUSTER_NAME] \
    --zone=[ZONE] \
    --master-authorized-networks="10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,203.0.113.0/24"

# リージョナルクラスタの場合
gcloud container clusters update [CLUSTER_NAME] \
    --region=[REGION] \
    --enable-master-authorized-networks \
    --master-authorized-networks="10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"

# 特定のIPアドレスのみを許可する場合(推奨)
gcloud container clusters update [CLUSTER_NAME] \
    --zone=[ZONE] \
    --enable-master-authorized-networks \
    --master-authorized-networks="203.0.113.0/24,198.51.100.14/32"

# Google Cloud Shellからのアクセスを許可する場合
gcloud container clusters update [CLUSTER_NAME] \
    --zone=[ZONE] \
    --enable-master-authorized-networks \
    --master-authorized-networks="35.235.240.0/20,10.0.0.0/8"

 

Terraformでの修復手順

承認済みネットワークを設定するTerraformコードと、主要な修正ポイントを説明します。

# 承認済みネットワークの変数定義
variable "authorized_networks" {
  description = "承認済みネットワークのCIDRとラベルのマップ"
  type        = map(string)
  default = {
    # 本番環境では、より制限的な設定を推奨
    # "10.0.0.0/8"       = "internal-vpc"  # 広すぎるため推奨されません
    # "172.16.0.0/12"    = "vpn-network"   # 広すぎるため推奨されません
    # "203.0.113.100/32" = "bastion-host"  # 単一IPの例
  }
}

# セキュリティレベル別の推奨設定
variable "authorized_networks_by_env" {
  description = "環境別の承認済みネットワーク設定"
  type = object({
    production = map(string)
    staging    = map(string)
    development = map(string)
  })
  default = {
    production = {
      "10.128.0.0/20"   = "prod-vpc-subnet"      # VPCサブネットのみ
      "198.51.100.5/32" = "ci-cd-server"         # CI/CDサーバー
      "192.0.2.10/32"   = "bastion-host"         # 踏み台サーバー
    }
    staging = {
      "10.129.0.0/20"   = "staging-vpc-subnet"
      "198.51.100.0/28" = "dev-team-vpn"
    }
    development = {
      "10.130.0.0/20"   = "dev-vpc-subnet"
      "203.0.113.0/24"  = "office-network"       # 開発オフィス
    }
  }
}

# GKEクラスタの作成(承認済みネットワーク設定付き)
resource "google_container_cluster" "secure_cluster" {
  name     = "secure-gke-cluster"
  location = var.region

  # 基本設定
  initial_node_count       = 1
  remove_default_node_pool = true

  # 承認済みネットワークの設定(必須)
  master_authorized_networks_config {
    # 空のcidr_blocksを設定すると、すべてのアクセスが拒否されるため注意
    dynamic "cidr_blocks" {
      for_each = var.authorized_networks
      content {
        cidr_block   = cidr_blocks.key
        display_name = cidr_blocks.value
      }
    }
  }

  # マスター承認済みネットワークのGCP専用CIDR範囲を追加
  # Cloud Shellや他のGCPサービスからのアクセスが必要な場合
  master_auth {
    client_certificate_config {
      issue_client_certificate = false
    }
  }

  # プライベートクラスタの設定(強く推奨)
  private_cluster_config {
    enable_private_nodes    = true
    enable_private_endpoint = false  # trueにするとパブリックIP経由のアクセスが完全に無効化
    master_ipv4_cidr_block = "172.16.0.0/28"  # /28はGKEの要件

    # GKE 1.21以降では、コントロールプレーンのグローバルアクセスを無効化可能
    # master_global_access_config {
    #   enabled = false
    # }
  }

  # セキュリティ強化のための追加設定
  workload_identity_config {
    workload_pool = "${var.project_id}.svc.id.goog"
  }

  # ネットワークポリシーの有効化
  network_policy {
    enabled  = true
    provider = "CALICO"
  }

  # バイナリ認証の有効化
  binary_authorization {
    evaluation_mode = "PROJECT_SINGLETON_POLICY_ENFORCE"
  }
}

# ノードプールの作成
resource "google_container_node_pool" "primary_nodes" {
  name       = "primary-node-pool"
  location   = var.region
  cluster    = google_container_cluster.secure_cluster.name
  node_count = var.node_count

  node_config {
    preemptible  = false
    machine_type = var.machine_type

    # ノードのセキュリティ設定
    shielded_instance_config {
      enable_secure_boot          = true
      enable_integrity_monitoring = true
    }

    # メタデータの保護
    metadata = {
      disable-legacy-endpoints = "true"
    }

    # ワークロードアイデンティティ
    workload_metadata_config {
      mode = "GKE_METADATA"
    }

    service_account = google_service_account.gke_nodes.email
    oauth_scopes = [
      "<https://www.googleapis.com/auth/cloud-platform>"
    ]
  }
}

# 最大セキュリティ設定の例(プライベートエンドポイントのみ)
resource "google_container_cluster" "maximum_security" {
  name     = "maximum-security-cluster"
  location = var.region

  # 完全なプライベートクラスタ
  private_cluster_config {
    enable_private_nodes    = true
    enable_private_endpoint = true  # パブリックエンドポイントを無効化
    master_ipv4_cidr_block = "172.16.0.0/28"
  }

  # 内部ネットワークのみからのアクセスを許可
  master_authorized_networks_config {
    cidr_blocks {
      cidr_block   = "10.0.0.0/8"
      display_name = "internal-only"
    }
  }

  # VPCネイティブクラスタ
  ip_allocation_policy {
    cluster_secondary_range_name  = var.pods_range_name
    services_secondary_range_name = var.services_range_name
  }
}

# 修復の確認方法
output "verify_authorized_networks" {
  value = <<-EOT
    # 承認済みネットワークの設定を確認するコマンド:

    # 1. 現在の設定を確認
    gcloud container clusters describe ${google_container_cluster.secure_cluster.name} \
      --location=${var.region} \
      --format="table(masterAuthorizedNetworksConfig.enabled,masterAuthorizedNetworksConfig.cidrBlocks[].cidrBlock:label='AUTHORIZED_NETWORKS')"

    # 2. アクセステスト(許可されたIPから)
    kubectl cluster-info

    # 3. アクセステスト(許可されていないIPから - タイムアウトするはず)
    # curl -k https://[MASTER_ENDPOINT] --connect-timeout 5

    # 4. プライベートクラスタ設定の確認
    gcloud container clusters describe ${google_container_cluster.secure_cluster.name} \
      --location=${var.region} \
      --format="table(privateClusterConfig.enablePrivateNodes,privateClusterConfig.enablePrivateEndpoint,privateClusterConfig.masterIpv4CidrBlock)"
  EOT
}

# セキュリティ監査用スクリプト
output "security_audit_script" {
  value = <<-EOT
    #!/bin/bash
    # GKEクラスタの承認済みネットワーク設定を監査

    echo "Checking all GKE clusters for authorized networks configuration..."

    for cluster in $(gcloud container clusters list --format="value(name,location)" | tr '\t' ':'); do
      name=$(echo $cluster | cut -d: -f1)
      location=$(echo $cluster | cut -d: -f2)

      echo "\nCluster: $name in $location"

      # 承認済みネットワークの状態を確認
      auth_networks=$(gcloud container clusters describe $name --location=$location \
        --format="value(masterAuthorizedNetworksConfig.enabled)")

      if [[ "$auth_networks" == "True" ]]; then
        echo "  ✓ Authorized networks: ENABLED"
        gcloud container clusters describe $name --location=$location \
          --format="table(masterAuthorizedNetworksConfig.cidrBlocks[].cidrBlock)"
      else
        echo "  ⚠️  Authorized networks: DISABLED (SECURITY RISK!)"
      fi

      # プライベートクラスタ設定の確認
      private_nodes=$(gcloud container clusters describe $name --location=$location \
        --format="value(privateClusterConfig.enablePrivateNodes)")

      if [[ "$private_nodes" == "True" ]]; then
        echo "  ✓ Private nodes: ENABLED"
      else
        echo "  ⚠️  Private nodes: DISABLED"
      fi
    done
  EOT
}

# 動的な承認済みネットワークの管理
resource "google_compute_firewall" "gke_master_webhooks" {
  name    = "gke-master-to-admission-webhooks"
  network = var.network_name

  # GKEマスターからAdmission Webhooksへの通信を許可
  source_ranges = [google_container_cluster.secure_cluster.private_cluster_config[0].master_ipv4_cidr_block]

  allow {
    protocol = "tcp"
    ports    = ["443", "8443"]
  }

  target_tags = ["admission-webhook"]
}

 

ベストプラクティス

承認済みネットワークを設定する際の推奨事項:

  1. 段階的な適用: 既存のクラスタでは、まず現在のアクセス元IPを含めてから徐々に制限を強化
  2. 冗長性の確保: 複数の管理用アクセスポイント(VPN、踏み台サーバー等)を設定
  3. 監査とモニタリング: Cloud Audit Logsで承認済みネットワークの変更を追跡
  4. 定期的な見直し: 不要になったIPアドレス範囲を定期的に削除
  5. プライベートクラスタとの併用: 承認済みネットワークとプライベートエンドポイントを組み合わせて多層防御を実現

修復の確認方法

設定が正しく適用されたことを確認する方法:

# 承認済みネットワークの設定を確認
gcloud container clusters describe [CLUSTER_NAME] \
    --zone=[ZONE] \
    --format="table(masterAuthorizedNetworksConfig.enabled,masterAuthorizedNetworksConfig.cidrBlocks[].cidrBlock:label=AUTHORIZED_NETWORKS)"

# 承認済みネットワーク外からのアクセステスト(失敗することを確認)
# 注意: このテストは承認済みネットワーク外から実行
kubectl get nodes --kubeconfig=[KUBECONFIG_FILE]
# Expected output: Unable to connect to the server: dial tcp [MASTER_IP]:443: i/o timeout

 

最後に

この記事では、GKEクラスタのコントロールプレーンに対する承認済みネットワークからのアクセス制限が未設定となっている場合のリスクと対策を解説しました。

承認済みネットワークは、多層防御戦略の重要な要素として、認証・認可と組み合わせて使用することで、クラスタのセキュリティを大幅に向上させることができます。特に、プライベートクラスタ設定と組み合わせることで、より強固なセキュリティ体制を構築できます。

この問題の検出は弊社が提供するSecurifyのCSPM機能で簡単に検出及び管理する事が可能です。 運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。 最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。

参考情報

公式ドキュメント

ベストプラクティス

この記事をシェアする

クラウドセキュリティ対策実践集一覧へ戻る

貴社の利用状況に合わせた見積もりを作成します。

料金プランを詳しく見る