EC2からのVertex AI APIアクセスをIPアドレスで制限する(VPC Service Controls + Access Context Manager + Terraform)
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モードで影響を確認するフローを踏むことで、既存の通信を誤って遮断するリスクを抑えられます。
参考






