EC2からのVertex AI APIアクセスをIPアドレスで制限する(VPC Service Controls + Access Context Manager + Terraform)

EC2からのVertex AI APIアクセスをIPアドレスで制限する(VPC Service Controls + Access Context Manager + Terraform)

2026.03.23

EC2やオンプレミスのPCからGoogle CloudのVertex AIにアクセスしている場合に、接続元のIPアドレスで制限をかけたいことがあります。

本記事では、VPC Service Controls(VPC-SC)とAccess Context Managerを使い、特定のIPアドレスからのみVertex AI APIへのアクセスを許可する構成をTerraformで構築する方法を紹介します。

本記事で使用するサンプルコードは以下のリポジトリに格納しています。

https://github.com/msato0731/terraform-sample/tree/main/vpc-sc-vertex-ai

はじめに

IAM ConditionsやWIFではIP制限できない

Vertex AI APIへの接続元IPアドレスを制限する方法として、IAM Conditionsの利用を検討される方もいるかもしれません。ただし、IAM Conditionsの条件式で使えるrequest.auth.claimsにはIPアドレスの情報が含まれないため、この方法ではVertex AI APIの呼び出し元のIPを制限することができません。

また、Workload Identity連携(WIF)は、サービスアカウントキーを使用せずに認証するための仕組みです。認証方式の選択であり、接続元IPの制限は別途VPC-SCなどで実装する必要があります。

VPC Service Controlsを使う

接続元IPアドレスでVertex AI APIを制限するには、VPC Service Controls(VPC-SC)とAccess Context Manager を使います。

VPC-SCとAccess Context Managerの概念や仕組みについては、以下の記事で詳しく解説しています。

VPC Service ControlsとAccess Context Managerを使ってGoogle Cloud APIをIPアドレスで制限する

本記事では、EC2からWorkload Identity連携を経由してVertex AI APIを呼び出す構成を題材に、Terraformでの実装方法に焦点を当てます。

全体構成

EC2をプライベートサブネットに配置し、NAT GatewayのElastic IPで送信元IPを固定します。Google Cloud側ではWorkload Identity連携でEC2からの認証を受け付け、VPC-SCのサービス境界でVertex AI APIへのアクセスをIPアドレスで制限します。

コンポーネント 役割
NAT Gateway(Elastic IP) EC2からの送信元IPを固定する
Workload Identity連携 サービスアカウントキーなしでEC2からGoogle Cloudへ認証する
アクセスレベル アクセスを許可するIPアドレスのCIDRリストを定義する
サービス境界 保護対象のプロジェクト・サービスを指定し、アクセスレベルを紐付ける

Terraform実装

AWS側(EC2 + NAT Gateway)

EC2をプライベートサブネットに配置し、NAT Gatewayで送信元IPを固定します。ポイントは、NAT GatewayにElastic IPを割り当てることで、Google Cloud側のIP許可リストに設定する固定IPを得ることです。

# NAT Gateway(Elastic IP で送信元IPを固定)
resource "aws_eip" "nat" {
  domain = "vpc"
}

resource "aws_nat_gateway" "nat" {
  allocation_id = aws_eip.nat.id
  subnet_id     = aws_subnet.public.id
}

EC2へはSSM Session Manager経由で接続するため、IAMロールにAmazonSSMManagedInstanceCoreポリシーをアタッチします。このIAMロール名は、Google Cloud側のWorkload Identity連携の設定でも使用されます。

resource "aws_iam_role" "ec2" {
  name               = "${var.prefix}-ec2-role"
  assume_role_policy = data.aws_iam_policy_document.ec2_assume_role.json
}

resource "aws_iam_role_policy_attachment" "ssm" {
  role       = aws_iam_role.ec2.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

resource "aws_instance" "test" {
  ami                    = data.aws_ssm_parameter.al2023_ami.value
  instance_type          = "t3.small"
  subnet_id              = aws_subnet.private.id
  vpc_security_group_ids = [aws_security_group.ec2.id]
  iam_instance_profile   = aws_iam_instance_profile.ec2.name
}

Google Cloud側(WIF + VPC-SC)

Google Cloud側では、Workload Identity連携、Access Context Manager、VPC Service Controlsの3つを設定します。

Workload Identity連携

Workload Identity PoolとAWSプロバイダを作成し、EC2のIAMロールとGoogle Cloudのサービスアカウントを紐付けます。

resource "google_iam_workload_identity_pool" "aws_pool" {
  workload_identity_pool_id = "aws-ec2-pool"
  display_name              = "AWS EC2 Pool"
}

resource "google_iam_workload_identity_pool_provider" "aws_provider" {
  workload_identity_pool_id          = google_iam_workload_identity_pool.aws_pool.workload_identity_pool_id
  workload_identity_pool_provider_id = "aws-provider"
  display_name                       = "AWS Provider"

  aws {
    account_id = var.aws_account_id
  }

  attribute_mapping = {
    "google.subject"        = "assertion.arn"
    "attribute.aws_role"    = "assertion.arn.extract('assumed-role/{role}/')"
    "attribute.aws_account" = "assertion.account"
  }
}

resource "google_service_account" "vertex_ai_caller" {
  account_id   = "vertex-ai-caller"
  display_name = "Vertex AI Caller from EC2"
}

resource "google_project_iam_member" "vertex_ai_user" {
  project = var.project_id
  role    = "roles/aiplatform.user"
  member  = "serviceAccount:${google_service_account.vertex_ai_caller.email}"
}

resource "google_service_account_iam_member" "wif_binding" {
  service_account_id = google_service_account.vertex_ai_caller.name
  role               = "roles/iam.workloadIdentityUser"
  member             = "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.aws_pool.name}/attribute.aws_role/${var.ec2_iam_role_name}"
}

Access Context Manager

アクセスポリシーとアクセスレベルを作成します。アクセスレベルに、許可するIPアドレスのCIDRリストを設定します。

resource "google_access_context_manager_access_policy" "policy" {
  parent = "organizations/${var.org_id}"
  title  = "${var.prefix}-vertex-ai-policy"
  scopes = ["projects/${var.project_number}"]
}

resource "google_access_context_manager_access_level" "allow_ec2" {
  parent = "accessPolicies/${google_access_context_manager_access_policy.policy.name}"
  name   = "accessPolicies/${google_access_context_manager_access_policy.policy.name}/accessLevels/${var.prefix}_allow_ec2_ip"
  title  = "${var.prefix}_allow_ec2_ip"

  basic {
    conditions {
      ip_subnetworks = var.allowed_cidrs  # NAT GatewayのElastic IPを指定
    }
  }
}

scopesにプロジェクトを指定すると、スコープ付きポリシーが作成されます。組織全体ではなく、特定プロジェクトのみに適用されるポリシーです。

VPC Service Controls

サービス境界を作成し、aiplatform.googleapis.comを保護対象にします。ingress_policiesでアクセスレベル(IP許可リスト)を紐付け、許可されたIPからのみアクセスを許可します。

resource "google_access_context_manager_service_perimeter" "vertex_ai" {
  parent = "accessPolicies/${google_access_context_manager_access_policy.policy.name}"
  name   = "accessPolicies/${google_access_context_manager_access_policy.policy.name}/servicePerimeters/${var.prefix}_vertex_ai_perimeter"
  title  = "${var.prefix}_vertex_ai_perimeter"

  status {
    resources           = ["projects/${var.project_number}"]
    restricted_services = ["aiplatform.googleapis.com"]

    ingress_policies {
      ingress_from {
        sources {
          access_level = google_access_context_manager_access_level.allow_ec2.name
        }
        identity_type = "ANY_IDENTITY"
      }
      ingress_to {
        resources = ["*"]
        operations {
          service_name = "aiplatform.googleapis.com"
          method_selectors {
            method = "*"
          }
        }
      }
    }
  }
}

identity_type = "ANY_IDENTITY"は、アクセスレベルの条件(IPアドレス)を満たせば、認証方式(サービスアカウントキー、WIFなど)に関わらずアクセスを許可する設定です。

動作確認

Terraformで環境を構築後、EC2上からVertex AI APIを呼び出して動作確認を行います。

EC2の事前セットアップ

EC2にSSM Session Managerで接続し、必要なツールをインストールします。

aws ssm start-session --target <ec2_instance_id>
sudo su - ec2-user

gcloud CLIのインストール

sudo tee /etc/yum.repos.d/google-cloud-sdk.repo << 'REPO'
[google-cloud-cli]
name=Google Cloud CLI
baseurl=https://packages.cloud.google.com/yum/repos/cloud-sdk-el9-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=0
gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
REPO
sudo dnf install -y google-cloud-cli

Python環境のセットアップ

Amazon Linux 2023のデフォルトPython(3.9)はgoogle-authのサポートが終了しているため、Python 3.11をインストールします。

sudo dnf install -y python3.14
python3.14 -m venv ~/vertex-ai-test
~/vertex-ai-test/bin/pip install google-genai google-auth

Pythonスクリプトの作成

WIF経由でVertex AI API(Gemini)を呼び出すスクリプトを作成します。

cat > /home/ec2-user/vertex_ai_client.py << 'EOF'
import json
import os

from google import genai
from google.auth import aws
from google.auth.transport.requests import Request

def initialize_credentials():
    credentials_file = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS")
    project_id = os.environ.get("GCP_PROJECT_ID")
    location = os.environ.get("GCP_LOCATION", "us-central1")

    with open(credentials_file, "r") as f:
        credentials_info = json.load(f)

    credentials = aws.Credentials.from_info(
        credentials_info,
        scopes=["https://www.googleapis.com/auth/cloud-platform"],
    )
    credentials.refresh(Request())

    return credentials, project_id, location

def call_gemini(credentials, project_id, location, prompt):
    client = genai.Client(
        vertexai=True,
        project=project_id,
        location=location,
        credentials=credentials,
    )
    response = client.models.generate_content(
        model="gemini-2.5-flash",
        contents=prompt,
    )
    return response.text

def main():
    credentials, project_id, location = initialize_credentials()
    prompt = "Google Cloudとは何ですか?簡潔に説明してください。"
    result = call_gemini(credentials, project_id, location, prompt)
    print(f"Generated text:\n{result}")

if __name__ == "__main__":
    main()
EOF

credential configの生成

gcloud iam workload-identity-pools create-cred-config \
  <workload_identity_pool_name>/providers/aws-provider \
  --service-account=<service_account_email> \
  --aws \
  --enable-imdsv2 \
  --output-file=/tmp/gcp_credential_config.json

--enable-imdsv2は、EC2のインスタンスメタデータサービスv2を使用するオプションです。Amazon Linux 2023はデフォルトでIMDSv2のみ有効なため、このオプションが必要です。

許可IPからのアクセス(成功)

環境変数を設定してPythonスクリプトを実行します。

export AWS_REGION=ap-northeast-1
export GOOGLE_APPLICATION_CREDENTIALS=/tmp/gcp_credential_config.json
export GCP_PROJECT_ID=<project_id>
export GCP_LOCATION=us-central1

source ~/vertex-ai-test/bin/activate
python vertex_ai_client.py

NAT GatewayのElastic IPが許可リストに含まれているため、Vertex AI APIの呼び出しが成功します。

応答例
**Google Cloud(グーグルクラウド)**とは、Googleが提供するクラウドコンピューティングサービスの総称です。

インターネット経由で、サーバー、ストレージ、データベース、ネットワーク、AI・機械学習ツールなど、様々なITリソースやサービスを必要な時に必要なだけ利用できるプラットフォームです。

**主な特徴:**
*   **スケーラブル**: 必要に応じてリソースを柔軟に増減できます。
*   **信頼性・セキュリティ**: Googleのグローバルインフラと技術を基盤としています。
*   **多様なサービス**: アプリケーション開発からデータ分析、AIまで幅広い機能を提供します。
*   **従量課金制**: 使った分だけ料金が発生します。

企業が自社でITインフラを持つ代わりに、Googleの強力なインフラを活用してビジネスを構築・運用することを可能にします。

許可外IPからのアクセス(拒否)

アクセスレベルの許可IPをダミーに変更し、同じEC2からアクセスすると拒否されることを確認します。

# 許可IPをダミーに変更
gcloud access-context-manager levels update <access_level_name> \
  --basic-level-spec=deny-test.yaml \
  --policy=<policy_id>
# deny-test.yaml
- ipSubnetworks:
    - 192.0.2.1/32  # RFC 5737 TEST-NET(どの実IPにもマッチしない)

この状態でEC2からpython vertex_ai_client.pyを実行すると、以下のようなエラーが返ります。

google.genai.errors.ClientError: 403 PERMISSION_DENIED.

確認後、terraform applyで許可IPを復元できます。

Dry-runモードについて

本番環境に適用する際は、Dry-runモードで事前に影響を確認することをお勧めします。Dry-runモードではアクセスはブロックされませんが、違反があればCloud Audit Logsに記録されるため、既存の通信への影響を事前に把握できます。

Terraformではuse_explicit_dry_run_spec = trueを設定し、statusブロックの代わりにspecブロックを使用します。

resource "google_access_context_manager_service_perimeter" "vertex_ai" {
  # ...省略...

  use_explicit_dry_run_spec = true

  spec {
    resources           = ["projects/${var.project_number}"]
    restricted_services = ["aiplatform.googleapis.com"]

    ingress_policies {
      # ...省略...
    }
  }
}

Cloud Audit Logsで以下のクエリを使い、Dry-run違反ログを確認できます。

resource.type="audited_resource"
protoPayload.metadata.@type="type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"

問題がなければ、use_explicit_dry_run_specを削除してspecブロックをstatusブロックに変更し、terraform applyでenforcedモードに切り替えます。

おわりに

VPC Service ControlsとAccess Context Managerを使い、Vertex AI APIへのアクセスをIPアドレスで制限する構成をTerraformで構築しました。

VPC-SCはAPIレベルの制御のため、サービスアカウントキー認証・Workload Identity連携認証のいずれでも機能します。また、今回はaiplatform.googleapis.comを保護対象にしましたが、BigQueryやCloud Storageなど他のサービスも同じ境界に追加でき、将来的な拡張も容易です。

本番適用前にDry-runモードで影響を確認するフローを踏むことで、既存の通信を誤って遮断するリスクを抑えられます。

参考

https://dev.classmethod.jp/articles/aws-ec2-to-vertex-ai-gemini-workload-identity/

この記事をシェアする

FacebookHatena blogX

関連記事