Compute Engine プロジェクトレベルSSHキーのセキュリティリスクと対応方法について

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

この記事では、Google Cloud Platform(GCP)のCompute EngineインスタンスでプロジェクトレベルのSSHキー使用が許可されている場合のセキュリティリスクと、インスタンスレベルでのアクセス制御を実現するための具体的な対策を解説します。

ポリシーの説明

プロジェクトレベルのSSHキーは、GCPプロジェクト内のすべてのCompute Engine VMインスタンスに対してアクセスを許可する共通のSSHキーです。この機能は一元管理の観点では便利ですが、以下の重要な問題があります:

  • 最小権限の原則違反: すべてのインスタンスに同一のアクセス権限が付与される
  • アクセス制御の粒度不足: インスタンスごとの個別のアクセス制御が困難
  • メタデータサーバー経由の配布: プロジェクトメタデータに保存されたSSHキーがすべてのインスタンスに自動配布される

Googleのセキュリティベストプラクティスでは、以下の対策が推奨されています:

  1. インスタンスレベルでのSSHキー管理(block-project-ssh-keys=TRUEの設定)
  2. OS Login機能によるIAMベースのアクセス制御
  3. Identity-Aware Proxy (IAP) を使用したSSHアクセス

 

修復方法

コンソールでの修復手順

Google Cloud コンソールを使用して、プロジェクトレベルのSSHキー使用を制限します。

ステップ1: 既存インスタンスの設定変更

  1. Google Cloud Consoleにログインし、「Compute Engine」→「VMインスタンス」に移動します
  1. 対象のインスタンスを選択し、「編集」をクリックします
  2. 「SSH キー」セクションまでスクロールし、以下の設定を行います:
    • 「プロジェクト全体の SSH キーをブロック」のチェックボックスをオンにします
    • これにより、このインスタンスではプロジェクトレベルのSSHキーが無効になります
  3. 必要に応じて、インスタンス固有のSSHキーを追加します:
    • 「項目を追加」をクリック
    • SSH公開鍵を入力(形式: ssh-rsa AAAAB3... username@hostname
  4. ページ下部の「保存」をクリックして変更を適用します

ステップ2: 組織ポリシーの設定(推奨)

  1. 組織全体で統一したポリシーを適用する場合は、組織ポリシーを設定します:
    • 「IAMと管理」→「組織のポリシー」に移動
    • 「compute.requireOsLogin」ポリシーを有効化(OS Loginの使用を推奨)

Terraformでの修復手順

プロジェクトレベルのSSHキー使用を制限するTerraformコードと、主要な修正ポイントを説明します。

# VMインスタンスの設定
resource "google_compute_instance" "secure_instance" {
  name         = "secure-vm-instance"
  machine_type = "e2-medium"
  zone         = "asia-northeast1-a"

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-11"
    }
  }

  network_interface {
    network = "default"
    # 外部IPを割り当てない(必要に応じて)
    # access_config {}
  }

  # プロジェクトレベルのSSHキーをブロック
  metadata = {
    block-project-ssh-keys = "TRUE"

    # インスタンス固有のSSHキーを設定(必要に応じて)
    ssh-keys = <<-EOT
      user1:ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ... user1@example.com
      user2:ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ... user2@example.com
    EOT
  }

  # 重複を削除し、正しいメタデータ設定に修正
  # metadata = {
  #   enable-oslogin = "TRUE"
  #   block-project-ssh-keys = "TRUE"
  # }

  # サービスアカウントの設定
  service_account {
    email  = google_service_account.instance_sa.email
    scopes = ["cloud-platform"]
  }

  # Shielded VMの設定(追加のセキュリティ)
  shielded_instance_config {
    enable_secure_boot          = true
    enable_vtpm                 = true
    enable_integrity_monitoring = true
  }

  tags = ["secure-instance", "no-project-ssh"]
}

# 組織ポリシーでOS Loginを強制(組織レベルの設定)
resource "google_organization_policy" "require_os_login" {
  org_id     = var.organization_id
  constraint = "compute.requireOsLogin"

  boolean_policy {
    enforced = true
  }
}

# プロジェクトレベルでの設定
resource "google_compute_project_metadata" "default" {
  metadata = {
    # OS Loginをプロジェクト全体で有効化
    enable-oslogin = "TRUE"

    # プロジェクトレベルのSSHキーを設定しない
    # ssh-keys = "" # 設定しない
  }
}

# インスタンステンプレートでの設定(自動スケーリング用)
resource "google_compute_instance_template" "secure_template" {
  name_prefix  = "secure-instance-template-"
  machine_type = "e2-medium"

  disk {
    source_image = "debian-cloud/debian-11"
    auto_delete  = true
    boot         = true
    disk_encryption_key {
      kms_key_self_link = var.kms_key_id  # KMS暗号化を追加
    }
  }

  network_interface {
    network = "default"
    # 外部IPを割り当てない(セキュリティベストプラクティス)
    # access_config {}
  }

  metadata = {
    block-project-ssh-keys = "TRUE"
    enable-oslogin        = "TRUE"
    # 追加のセキュリティ設定
    serial-port-enable    = "FALSE"  # シリアルポートを無効化
    startup-script        = file("${path.module}/scripts/security-hardening.sh")
  }

  service_account {
    email  = google_service_account.instance_sa.email
    scopes = ["cloud-platform"]
  }

  # Shielded VM設定を追加
  shielded_instance_config {
    enable_secure_boot          = true
    enable_vtpm                 = true
    enable_integrity_monitoring = true
  }

  lifecycle {
    create_before_destroy = true
  }
}

# カスタムサービスアカウント
resource "google_service_account" "instance_sa" {
  account_id   = "secure-instance-sa"
  display_name = "Secure Instance Service Account"
  description  = "Service account for secure VM instances"
}

# 必要最小限の権限を付与
resource "google_project_iam_member" "instance_sa_log_writer" {
  project = var.project_id
  role    = "roles/logging.logWriter"
  member  = "serviceAccount:${google_service_account.instance_sa.email}"
}

resource "google_project_iam_member" "instance_sa_metric_writer" {
  project = var.project_id
  role    = "roles/monitoring.metricWriter"
  member  = "serviceAccount:${google_service_account.instance_sa.email}"
}

まとめ

この記事では、GCP Compute EngineインスタンスでプロジェクトレベルのSSHキー使用が許可されている場合のセキュリティリスクと対策を解説しました。プロジェクトレベルのSSHキーは管理の利便性はあるものの、セキュリティ上の重大なリスクを伴うため、以下の対策が必須です:

  1. 既存インスタンスでblock-project-ssh-keys=TRUEを設定
  2. OS LoginまたはIAPによる代替アクセス方法の実装
  3. 組織ポリシーによる恒久的な統制の確立

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

参考情報

この記事をシェアする

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

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

料金プランを詳しく見る