Compute Engine デフォルトサービスアカウントのセキュリティリスクと修復手順について

このブログシリーズ 「クラウドセキュリティ 実践集」 では、一般的なセキュリティ課題を取り上げ、「なぜ危険なのか?」 というリスクの解説から、 「どうやって直すのか?」 という具体的な修復手順(コンソール、Google Cloud CLI、Terraformなど)まで、分かりやすく解説します。
この記事では、Google Cloud Platform(GCP)のCompute Engineインスタンスがデフォルトのサービスアカウントで実行されている場合のセキュリティリスクと、最小権限の原則に基づいた修復手順を解説します。

ポリシーの説明
Google Compute Engineのデフォルトサービスアカウント(PROJECT_NUMBER-compute@developer.gserviceaccount.com)は、新しいVMインスタンス作成時に自動的に割り当てられるサービスアカウントです。デフォルトでは、このアカウントにプロジェクト全体に対するEditor(編集者)ロールが付与されることがありますが、これは組織ポリシー「iam.automaticIamGrantsForDefaultServiceAccounts」で制御可能です。Editorロールが付与された場合、Cloud Storage、BigQuery、Pub/Sub、Container Registryなど、ほとんどのGCPサービスへの読み取り・書き込みアクセス権限を持つことになります。
GoogleのセキュリティベストプラクティスおよびIAM(Identity and Access Management)の最小権限の原則では、各インスタンスに必要最小限の権限のみを持つカスタムサービスアカウントを使用することが強く推奨されています。
修復方法
コンソールでの修復手順
Google Cloud コンソールを使用して、カスタムサービスアカウントを作成し、既存のインスタンスを更新します。
※ 既存のインスタンスに対しては一度インスタンスを停止した状態でないと更新が出来ないため注意してください。
ステップ1: カスタムサービスアカウントの作成
- Google Cloud Consoleで「IAMと管理」→「サービスアカウント」に移動します

- 「サービスアカウントを作成」をクリックします
- 以下の情報を入力します:
- サービスアカウント名: 例:
web-server-sa
(用途を明確に示す名前) - サービスアカウントID: 自動生成されます
- 説明: 例:「Webサーバー用の最小権限サービスアカウント」
- サービスアカウント名: 例:
- 「作成して続行」をクリックします
- 必要最小限のロールを付与します(例:Storage Object Viewer、Logging Writer)
- 「完了」をクリックします
ステップ2: 既存インスタンスの確認と更新
- 「Compute Engine」→「VMインスタンス」に移動します

- 各インスタンスの詳細を確認し、「APIとIDの管理」セクションでサービスアカウントを確認します
- デフォルトサービスアカウントを使用しているインスタンスを特定します
- インスタンスを停止します(実行中のインスタンスはサービスアカウントを変更できません)
- 「編集」をクリックします
- 「APIとIDの管理」セクションで、作成したカスタムサービスアカウントを選択します
- 「保存」をクリックし、インスタンスを再起動します
ステップ3: gcloud CLIを使用したデフォルトサービスアカウントの使用状況確認
# プロジェクト番号の取得
PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value project) --format="value(projectNumber)")
# デフォルトサービスアカウントを使用しているインスタンスを検索
gcloud compute instances list --format="table(name,zone,serviceAccounts[0].email)" \
--filter="serviceAccounts[0].email ~ ${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
# 特定のインスタンスのサービスアカウントを確認
gcloud compute instances describe INSTANCE_NAME --zone=ZONE \
--format="value(serviceAccounts[0].email)"
# デフォルトサービスアカウントのスコープを確認
gcloud compute instances describe INSTANCE_NAME --zone=ZONE \
--format="yaml(serviceAccounts[0].scopes)"
# デフォルトサービスアカウントの現在の権限を確認
gcloud projects get-iam-policy $(gcloud config get-value project) \
--flatten="bindings[].members" \
--filter="bindings.members:serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--format="table(bindings.role)"
Terraformでの修復手順
カスタムサービスアカウントを作成し、Compute Engineインスタンスに適用するTerraformコードと、主要な修正ポイントを説明します。
# カスタムサービスアカウントの作成
resource "google_service_account" "web_server" {
account_id = "web-server-sa"
display_name = "Web Server Service Account"
description = "Minimal privilege service account for web servers"
}
# 必要最小限のIAMロールの付与
resource "google_project_iam_member" "web_server_storage_viewer" {
project = var.project_id
role = "roles/storage.objectViewer"
member = "serviceAccount:${google_service_account.web_server.email}"
}
resource "google_project_iam_member" "web_server_logging" {
project = var.project_id
role = "roles/logging.logWriter"
member = "serviceAccount:${google_service_account.web_server.email}"
}
# カスタムロールの作成(より細かい権限制御が必要な場合)
resource "google_project_iam_custom_role" "web_server_custom" {
role_id = "webServerCustomRole"
title = "Web Server Custom Role"
description = "Custom role with minimal permissions for web servers"
permissions = [
"compute.instances.get",
"compute.zones.list",
"storage.buckets.list",
"storage.objects.get",
"logging.logEntries.create"
]
}
# VMインスタンスの作成(カスタムサービスアカウントを使用)
resource "google_compute_instance" "web_server" {
name = "web-server-instance"
machine_type = "e2-medium"
zone = var.zone
boot_disk {
initialize_params {
image = "debian-cloud/debian-11"
}
}
network_interface {
network = "default"
# プライベートIPのみ(セキュリティ強化)
# access_config を指定しない
}
# カスタムサービスアカウントの設定
service_account {
email = google_service_account.web_server.email
# スコープはサービスアカウントのIAMロールと組み合わせて使用されます
# cloud-platformスコープは幅広いため、必要に応じてより制限的なスコープを検討
scopes = [
"<https://www.googleapis.com/auth/cloud-platform>"
]
}
# メタデータでセキュリティを強化
metadata = {
enable-oslogin = "TRUE" # OS Loginを有効化
block-project-ssh-keys = "TRUE" # プロジェクト全体のSSHキーをブロック
disable-legacy-endpoints = "true" # v0.1メタデータエンドポイントを無効化
# enable-guest-attributes = "true" # ゲスト属性の有効化(オプション)
}
# シールドVMの有効化(追加のセキュリティ)
shielded_instance_config {
enable_secure_boot = true
enable_vtpm = true
enable_integrity_monitoring = true
}
}
# 組織ポリシーでデフォルトサービスアカウントへのEditor権限付与を無効化
resource "google_organization_policy" "disable_automatic_iam_grants" {
org_id = var.organization_id
constraint = "iam.automaticIamGrantsForDefaultServiceAccounts"
boolean_policy {
enforced = false # 自動的なIAM権限付与を無効化
}
}
# 異なる用途のサービスアカウント例
# データベースアクセス用
resource "google_service_account" "database_app" {
account_id = "database-app-sa"
display_name = "Database Application Service Account"
description = "Service account for applications accessing Cloud SQL databases"
}
resource "google_project_iam_member" "database_app_sql" {
project = var.project_id
role = "roles/cloudsql.client"
member = "serviceAccount:${google_service_account.database_app.email}"
}
# バックアップ処理用
resource "google_service_account" "backup_processor" {
account_id = "backup-processor-sa"
display_name = "Backup Processor Service Account"
}
resource "google_project_iam_member" "backup_storage_admin" {
project = var.project_id
role = "roles/storage.admin"
member = "serviceAccount:${google_service_account.backup_processor.email}"
# 特定のバケットのみに限定
condition {
title = "backup-buckets-only"
description = "Grants access only to backup buckets"
expression = "resource.name.startsWith(\"projects/_/buckets/backup-\")"
}
}
# 既存インスタンスの監査用出力
output "audit_default_service_accounts" {
value = <<-EOT
# デフォルトサービスアカウントの監査コマンド:
# 1. すべてのインスタンスをリスト
gcloud compute instances list --format="csv(name,zone,serviceAccounts[0].email)" > instances.csv
# 2. デフォルトサービスアカウントのEditor権限を削除(注意: 影響を確認してから実行)
gcloud projects remove-iam-policy-binding ${var.project_id} \
--member="serviceAccount:${data.google_project.current.number}-compute@developer.gserviceaccount.com" \
--role="roles/editor"
# 3. デフォルトサービスアカウントの無効化(オプション)
# gcloud iam service-accounts disable ${data.google_project.current.number}-compute@developer.gserviceaccount.com
# 4. モニタリングアラートの設定
gcloud monitoring policies create \
--notification-channels=${var.notification_channel_id} \
--display-name="Default Service Account Usage Alert" \
--condition-display-name="VM using default service account" \
--condition-filter='resource.type="gce_instance" AND metric.type="compute.googleapis.com/instance/cpu/utilization" AND metadata.user_labels."service_account"=~".*-compute@developer.gserviceaccount.com"'
EOT
}
# サービスアカウントの作成ベストプラクティス
variable "service_account_naming_convention" {
description = "サービスアカウントの命名規則"
type = object({
environment = string # dev, staging, prod
function = string # web, api, worker, etc.
permissions = string # read, write, admin
})
default = {
environment = "prod"
function = "web"
permissions = "read"
}
}
# ベストプラクティスに従ったサービスアカウント名の生成
locals {
service_account_id = "${var.service_account_naming_convention.environment}-${var.service_account_naming_convention.function}-${var.service_account_naming_convention.permissions}-sa"
}
まとめ
この記事では、GCP Compute Engineインスタンスがデフォルトのサービスアカウントで実行されている場合のセキュリティリスクと、最小権限の原則に基づいた修復手順を解説しました。デフォルトサービスアカウントの使用は、過剰な権限付与によるリスクがあるため、カスタムサービスアカウントへの移行が不可欠です。特に、組織ポリシーを使用してデフォルトサービスアカウントへの自動的なEditorロール付与を無効化することも重要です。
この問題の検出は弊社が提供するSecurifyのCSPM(Cloud Security Posture Management)機能で簡単に検出及び管理する事が可能です。 運用が非常に楽に出来る製品になっていますので、ぜひ興味がある方はお問い合わせお待ちしております。 最後までお読みいただきありがとうございました。この記事が皆さんの役に立てば幸いです。