IaC - TECH PLAY - TECH PLAY

TECH PLAY

IaC

イベント

該当するコンテンツが見つかりませんでした

マガジン

技術ブログ

はじめに # これは、「面白そう」と感じたアーキテクチャや技術スタックを、まずはあれこれ試しながら作ってみたプロトタイピングの記録です。 前回は、AWS LambdaとSSMセッションマネージャーによるサーバーレスGPU起動ブローカーを構築しました。 (詳細は 前回の記事 を参照してください) これにより、ポート開放ゼロかつSSH秘密鍵不要で、世界中の最安スポットGPUをわずか数秒で探索・選定し、安全に直結できる環境が完成しました。 しかし、前回の構成を実践していく中で、もう1つ避けて通れない重要な課題が浮き彫りになります。 「マルチリージョン展開に必要なS3・ECR・セキュリティグループ・IAMロール・起動構成・Lambda関数を、手動や場当たり的なシェルスクリプトで管理し続けるのは辛い」 今回の構成では、東京(ap-northeast-1)に加えて海外4リージョン(バージニア、オハイオ、オレゴン、フランクフルト)の計5リージョンを調達先として扱います。これらのリージョンに手動で設定を入れると、設定漏れやタイプミスの温床になります。使わなくなった際の環境破棄や、別アカウントへの再現も極めて困難になります。 複数リージョンに分散配置するGPU実行基盤を、不要になったら丸ごと消せるエフェメラルなIaCとしてTerraformで組めば、管理や片付けが大幅に楽になります。 そこで今回は、 静的インフラ基盤のすべてをTerraformで一括コード化(IaC化) することにしました。 --> Information 📚 関連する過去の検証記事 第1回 : AWS×UserDataでvLLMを自動起動!停止時コストほぼゼロのローカルLLM環境 第2回 : 自前vLLMをOpen WebUI経由でVS Code(Cline)に接続!トークンフリーで開発する 第3回 : EC2スポットインスタンス×vLLMでGPUコストを大幅削減する 第4回 : EC2スポット×vLLMをSSMでセキュア化!ポート開放ゼロで繋ぐ 第5回 : vLLM起動をAWS Lambda化!最安スポット探索と自動フォールバック 1. Terraform化における「役割分担(スコープ設計)」 # 📌 このセクションの要点 「常に存在する静的基盤」と「作業時だけ使い捨てるGPU」を明確に分離します。動的なGPU起動・停止までTerraformで管理しようとせず、ブローカー基盤までをTerraformで作り、GPUのオンデマンド調達はLambdaに任せる設計がベストプラクティスです。 本検証では、「常に存在するインフラ」と「作業時だけ使い捨てるGPU」を明確に分離しています。そのため、Terraformの管理範囲を以下のように切り分けるのがベストプラクティスです。 カテゴリ リソース 管理ツール ライフサイクル・費用感 静的基盤 S3, ECR(+レプリケーション), IAM, 各リージョンSG, Launch Template, Lambda Terraform 常時存在(使わない時の待機費用はS3・ECRの数GB保管料数十円のみ) 動的エフェメラル 最適リージョンのリアルタイム探索, EC2スポット起動/破棄, SSMトンネル Lambda + CLI オンデマンド実行(作業中のみ $0.4〜0.6/h 課金) 「EC2スポットの起動・破棄」までをTerraformで管理しようとすると、動的なリージョン選定が難しくなります。また、状態ファイル( tfstate )のロックや同期で毎回1分以上のオーバーヘッドが発生します。 そのため、 「ブローカー基盤までをTerraformで作り、GPUの生成・破棄はブローカー(Lambda)に任せる」 という設計が最も軽快で堅牢です。 2. コンテナイメージのマルチリージョン配置(ECRクロスリージョンレプリケーション) # 第1回〜第5回で採用している通り、vLLMのコンテナイメージ(約13GB)は Amazon ECR に永続化し、EC2の起動時に同一リージョン内から高速・転送料無料でPullします。 調達候補となる各リージョン(バージニア、オレゴン、オハイオ、フランクフルトなど)においても、同様に 同一リージョン内のECRからイメージを取得できる状態 を整えておく必要があります。仮に東京のECRから他リージョンのEC2へ都度Pullしてしまうと、リージョン間データ転送料金が毎回発生するうえ、コンテナ起動時間も大幅に増大してしまうためです。 とはいえ、イメージを更新するたびに各リージョンのECRエンドポイントへ手動で docker push を繰り返すのは運用負荷が高く、非効率です。 そこで、Amazon ECRがネイティブで備えている クロスリージョンレプリケーション(Cross-Region Replication) を採用します。Terraformでこの設定( aws_ecr_replication_configuration )を宣言しておきます。これにより、東京のECRに1回Pushするだけで、AWSバックボーン経由で全候補リージョンへ自動複製されます。 以下は、東京リージョンでのECRリポジトリ作成、旧世代イメージの自動削除ポリシー、および他4リージョンへの自動レプリケーションを定義したTerraformコードです。 ecr.tf(クリックで展開) # terraform/ecr.tf # 東京(プライマリ)リージョンの ECR リポジトリ resource "aws_ecr_repository" "vllm" { name = var.ecr_repository_name image_tag_mutability = "MUTABLE" tags = { Project = "vllm-ephemeral" } } # 古いタグの自動削除ポリシー(無駄なストレージ課金を防止) resource "aws_ecr_lifecycle_policy" "vllm_lifecycle" { repository = aws_ecr_repository.vllm.name policy = jsonencode({ rules = [{ rulePriority = 1 description = "最新イメージのみ保持し、旧世代は30日で失効" selection = { tagStatus = "any", countType = "sinceImagePushed", countUnit = "days", countNumber = 30 } action = { type = "expire" } }] }) } # ★マルチリージョン・クロスリージョン自動レプリケーション resource "aws_ecr_replication_configuration" "vllm_replication" { replication_configuration { rule { dynamic "destination" { for_each = [for r in var.target_regions : r if r != var.primary_region] content { region = destination.value registry_id = data.aws_caller_identity.current.account_id } } } } } --> Information 💡 S3のモデル重み同期について(マルチリージョン配置の検討) コンテナイメージと同様に、S3に格納するモデル重み(約15GB)についても候補リージョンへの分散配置が考えられます。 S3クロスリージョンレプリケーション(CRR)を利用する場合 : 全リージョンに重みを事前同期しておくことで、起動時のダウンロード時間を最短化し、同一リージョン内通信(無料)に抑制可能。一方で、複数リージョンにモデルを保持し続けるとS3保管料がリージョン数分発生するため、旧バケットの定期削除やGlacierへの退避など、ストレージ管理の併用が有効。 東京S3から都度クロスリージョン取得する場合 : モデル保管料は東京の1バケット分で済む一方、海外リージョン起動時にクロスリージョン転送料(1回約220円)とネットワーク遅延が発生。 本システムでは、頻繁に利用する主要リージョンにはS3バケットを準備し、必要に応じて初期同期しておく構成を推奨しています。 3. ゼロインバウンドSG & 最小権限IAM # 第4回で解説した「インバウンドルール0件のセキュリティグループ」と、EC2およびLambdaに必要なIAMロールを一括で定義します。 セキュリティグループ(全リージョンへの一括プロビジョニング) # Terraformのマルチプロバイダ機能( providers = { aws = ... } )やモジュールループを活用します。これにより、全リージョンへインバウンド0件のセキュリティグループを展開できます。 security_groups.tf(クリックで展開) # 各リージョン向けのセキュリティグループ(インバウンドルールなし、アウトバウンド全開放) resource "aws_security_group" "vllm_sg" { name = "vllm-ssm-isolated-sg" description = "Zero-inbound security group for vLLM SSM port forwarding" vpc_id = data.aws_vpc.default.id # インバウンドルールは定義しない(完全閉塞) egress { description = "Allow all outbound traffic for SSM Agent and S3/ECR pull" from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "vllm-ssm-isolated-sg" } } IAMロール(EC2用 & Lambda用) # EC2インスタンスにはSSM通信・S3読み取り・ECR読み取りに必要な最小権限を付与し、Lambda関数にはマルチリージョンのEC2探索・起動に必要な権限を付与します。 iam.tf(クリックで展開) # EC2インスタンス用 IAMロール resource "aws_iam_role" "ec2_role" { name = "vllm-ssm-instance-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "ec2.amazonaws.com" } }] }) } # SSMエージェント通信用ポリシー resource "aws_iam_role_policy_attachment" "ssm_core" { role = aws_iam_role.ec2_role.name policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" } # S3 & ECR 読み取りポリシー resource "aws_iam_role_policy_attachment" "s3_read" { role = aws_iam_role.ec2_role.name policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess" } resource "aws_iam_role_policy_attachment" "ecr_read" { role = aws_iam_role.ec2_role.name policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" } # EC2インスタンスプロファイル resource "aws_iam_instance_profile" "ec2_profile" { name = "vllm-ssm-instance-profile" role = aws_iam_role.ec2_role.name } # Lambda GPUブローカー用 IAMロール resource "aws_iam_role" "lambda_role" { name = "vllm-spot-broker-lambda-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "lambda.amazonaws.com" } }] }) } resource "aws_iam_role_policy_attachment" "lambda_basic" { role = aws_iam_role.lambda_role.name policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" } # マルチリージョンでのスポット探索・EC2起動権限 resource "aws_iam_role_policy" "lambda_ec2_broker" { name = "VLLMBrokerEC2Policy" role = aws_iam_role.lambda_role.id policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = [ "ec2:DescribeSpotPriceHistory", "ec2:DescribeSecurityGroups", "ec2:DescribeImages", "ec2:RunInstances", "ec2:CreateTags", "ssm:GetParameter", "iam:PassRole" ] Resource = "*" } ] }) } --> Information 💡 第4回・第5回のスクリプト環境から移行する場合の注意点 第4回や第5回の環境構築スクリプトを実行済みのAWS環境でTerraformを実行する場合に注意が必要です。同名のリソースが存在すると競合エラー( EntityAlreadyExistsException 等)が発生します。その場合は terraform import で取り込むか、既存リソースを削除(または名前を変更)してから terraform apply を実行してください。 4. EC2起動テンプレート(Launch Template)とUserDataのテンプレート化 # 📌 このセクションの要点 第5回でS3へ切り離したUserData( startup.sh )をさらに一歩進めます。インスタンスタイプやEBS、IAMプロファイル、閉塞SG、UserDataブートストラップを EC2起動テンプレート(Launch Template) として一元管理します。これにより、Lambdaブローカーからハードウェア依存の記述を完全に切り離せます。 第5回では、110行を超えるUserDataスクリプトをS3バケットへ配置しました。EC2側にはS3から取得して実行する3行のブートストラップスクリプトを渡す構成としました。これにより、Lambdaコードの肥大化とUserDataの16KB上限問題を回避しました。 しかし、もう1つの課題が残っていました。 インスタンス仕様がLambdaコード内にハードコードされている : インスタンスタイプ( g6.xlarge )、EBSボリューム(40GB gp3、削除保護オフ)、IAMインスタンスプロファイル、セキュリティグループ、スポット市場オプションなどのハードウェア構成が、依然としてLambdaのPythonコード内の辞書として記述されていました。 インスタンスのハードウェア構成やブートストラップ手順は、本来「静的なインフラ仕様」としてIaCで管理すべき領域です。 そこで本構成では、 aws_launch_template (EC2起動テンプレート) を導入します。これにより、ハードウェア定義とUserDataブートストラップを一括コード化します。 1. UserDataブートストラップのテンプレート( userdata_bootstrap.sh ) # Terraformの templatefile 関数で動的パラメータ(リージョン、S3バケット名、ECRイメージ名)を注入できる極小シェルスクリプトを用意します。なお、Bash変数( $LOG_FILE 等)は波括弧を付けずに記述することで、Terraformテンプレート展開時の変数名衝突を綺麗に回避しています。 templates/userdata_bootstrap.sh(クリックで展開) #!/bin/bash set -euo pipefail LOG_FILE="/var/log/userdata-bootstrap.log" exec > >(tee -a "$LOG_FILE" | logger -t user-data -s 2>/dev/console) 2>&1 AWS_REGION="${AWS_REGION}" S3_BUCKET="${S3_BUCKET_NAME}" DOCKER_IMAGE="${DOCKER_IMAGE}" echo "=== S3から起動スクリプト (startup.sh) を取得 ===" aws s3 cp "s3://$S3_BUCKET/scripts/startup.sh" /tmp/startup.sh --region "$AWS_REGION" chmod +x /tmp/startup.sh echo "=== startup.sh 実行 ===" /tmp/startup.sh "$AWS_REGION" "$S3_BUCKET" "$DOCKER_IMAGE" 2. 全リージョンへの起動テンプレート一括プロビジョニング( launch_template.tf ) # EC2 Launch Templateは リージョン固有 のリソースです。東京だけに配置すると、海外リージョンでの起動時にテンプレートが見つかりません。そのため、Terraformを使って全候補リージョンへ同一名( vllm-spot-template )で一括展開します。 これにより、Lambdaブローカーがリアルタイム探索でどのリージョンを引き当てた場合でも、フォールバックなしに起動テンプレートから直接インスタンスを生成できます。 launch_template.tf(クリックで展開) # terraform/launch_template.tf # ============================================================================== # EC2 起動テンプレート(Launch Template)全候補リージョン一括プロビジョニング # EBS(40GB gp3)、IAMプロファイル、セキュリティグループ、UserData(S3ブートストラップ) # を全リージョンで共通のテンプレート名「vllm-spot-template」としてコード化する # ============================================================================== # 1. 東京リージョン (ap-northeast-1) resource "aws_launch_template" "lt_ap_northeast_1" { name = "vllm-spot-template" description = "vLLM Ephemeral Spot Node (g6.xlarge, NVIDIA L4 24GB) [ap-northeast-1]" instance_type = var.instance_type iam_instance_profile { name = aws_iam_instance_profile.ec2_profile.name } vpc_security_group_ids = [ aws_security_group.sg_ap_northeast_1.id ] block_device_mappings { device_name = "/dev/sda1" ebs { volume_size = 40 volume_type = "gp3" delete_on_termination = true } } instance_market_options { market_type = "spot" spot_options { spot_instance_type = "one-time" instance_interruption_behavior = "terminate" } } user_data = base64encode(templatefile("${path.module}/templates/userdata_bootstrap.sh", { AWS_REGION = "ap-northeast-1" S3_BUCKET_NAME = "my-vllm-models-hackathon-2026-${data.aws_caller_identity.current.account_id}-ap-northeast-1-an" DOCKER_IMAGE = "${data.aws_caller_identity.current.account_id}.dkr.ecr.ap-northeast-1.amazonaws.com/${var.ecr_repository_name}:latest" })) tag_specifications { resource_type = "instance" tags = { Name = "vllm-ssm-spot-node" Project = "vllm-ephemeral" MarketType = "spot" } } } # 2. バージニア北部リージョン (us-east-1) resource "aws_launch_template" "lt_us_east_1" { provider = aws.us_east_1 name = "vllm-spot-template" description = "vLLM Ephemeral Spot Node (g6.xlarge, NVIDIA L4 24GB) [us-east-1]" instance_type = var.instance_type iam_instance_profile { name = aws_iam_instance_profile.ec2_profile.name } vpc_security_group_ids = [ aws_security_group.sg_us_east_1.id ] block_device_mappings { device_name = "/dev/sda1" ebs { volume_size = 40 volume_type = "gp3" delete_on_termination = true } } instance_market_options { market_type = "spot" spot_options { spot_instance_type = "one-time" instance_interruption_behavior = "terminate" } } user_data = base64encode(templatefile("${path.module}/templates/userdata_bootstrap.sh", { AWS_REGION = "us-east-1" S3_BUCKET_NAME = "my-vllm-models-hackathon-2026-${data.aws_caller_identity.current.account_id}-us-east-1-an" DOCKER_IMAGE = "${data.aws_caller_identity.current.account_id}.dkr.ecr.us-east-1.amazonaws.com/${var.ecr_repository_name}:latest" })) tag_specifications { resource_type = "instance" tags = { Name = "vllm-ssm-spot-node" Project = "vllm-ephemeral" MarketType = "spot" } } } # 3. オハイオリージョン (us-east-2) resource "aws_launch_template" "lt_us_east_2" { provider = aws.us_east_2 name = "vllm-spot-template" description = "vLLM Ephemeral Spot Node (g6.xlarge, NVIDIA L4 24GB) [us-east-2]" instance_type = var.instance_type iam_instance_profile { name = aws_iam_instance_profile.ec2_profile.name } vpc_security_group_ids = [ aws_security_group.sg_us_east_2.id ] block_device_mappings { device_name = "/dev/sda1" ebs { volume_size = 40 volume_type = "gp3" delete_on_termination = true } } instance_market_options { market_type = "spot" spot_options { spot_instance_type = "one-time" instance_interruption_behavior = "terminate" } } user_data = base64encode(templatefile("${path.module}/templates/userdata_bootstrap.sh", { AWS_REGION = "us-east-2" S3_BUCKET_NAME = "my-vllm-models-hackathon-2026-${data.aws_caller_identity.current.account_id}-us-east-2-an" DOCKER_IMAGE = "${data.aws_caller_identity.current.account_id}.dkr.ecr.us-east-2.amazonaws.com/${var.ecr_repository_name}:latest" })) tag_specifications { resource_type = "instance" tags = { Name = "vllm-ssm-spot-node" Project = "vllm-ephemeral" MarketType = "spot" } } } # 4. オレゴンリージョン (us-west-2) resource "aws_launch_template" "lt_us_west_2" { provider = aws.us_west_2 name = "vllm-spot-template" description = "vLLM Ephemeral Spot Node (g6.xlarge, NVIDIA L4 24GB) [us-west-2]" instance_type = var.instance_type iam_instance_profile { name = aws_iam_instance_profile.ec2_profile.name } vpc_security_group_ids = [ aws_security_group.sg_us_west_2.id ] block_device_mappings { device_name = "/dev/sda1" ebs { volume_size = 40 volume_type = "gp3" delete_on_termination = true } } instance_market_options { market_type = "spot" spot_options { spot_instance_type = "one-time" instance_interruption_behavior = "terminate" } } user_data = base64encode(templatefile("${path.module}/templates/userdata_bootstrap.sh", { AWS_REGION = "us-west-2" S3_BUCKET_NAME = "my-vllm-models-hackathon-2026-${data.aws_caller_identity.current.account_id}-us-west-2-an" DOCKER_IMAGE = "${data.aws_caller_identity.current.account_id}.dkr.ecr.us-west-2.amazonaws.com/${var.ecr_repository_name}:latest" })) tag_specifications { resource_type = "instance" tags = { Name = "vllm-ssm-spot-node" Project = "vllm-ephemeral" MarketType = "spot" } } } # 5. フランクフルトリージョン (eu-central-1) resource "aws_launch_template" "lt_eu_central_1" { provider = aws.eu_central_1 name = "vllm-spot-template" description = "vLLM Ephemeral Spot Node (g6.xlarge, NVIDIA L4 24GB) [eu-central-1]" instance_type = var.instance_type iam_instance_profile { name = aws_iam_instance_profile.ec2_profile.name } vpc_security_group_ids = [ aws_security_group.sg_eu_central_1.id ] block_device_mappings { device_name = "/dev/sda1" ebs { volume_size = 40 volume_type = "gp3" delete_on_termination = true } } instance_market_options { market_type = "spot" spot_options { spot_instance_type = "one-time" instance_interruption_behavior = "terminate" } } user_data = base64encode(templatefile("${path.module}/templates/userdata_bootstrap.sh", { AWS_REGION = "eu-central-1" S3_BUCKET_NAME = "my-vllm-models-hackathon-2026-${data.aws_caller_identity.current.account_id}-eu-central-1-an" DOCKER_IMAGE = "${data.aws_caller_identity.current.account_id}.dkr.ecr.eu-central-1.amazonaws.com/${var.ecr_repository_name}:latest" })) tag_specifications { resource_type = "instance" tags = { Name = "vllm-ssm-spot-node" Project = "vllm-ephemeral" MarketType = "spot" } } } output "launch_template_ids" { value = { "ap-northeast-1" = aws_launch_template.lt_ap_northeast_1.id "us-east-1" = aws_launch_template.lt_us_east_1.id "us-east-2" = aws_launch_template.lt_us_east_2.id "us-west-2" = aws_launch_template.lt_us_west_2.id "eu-central-1" = aws_launch_template.lt_eu_central_1.id } description = "EC2 Launch Template IDs across all target regions" } output "launch_template_name" { value = "vllm-spot-template" description = "Common EC2 Launch Template Name across all target regions" } 起動テンプレートを全候補リージョンで同名( vllm-spot-template )としてTerraformで管理します。これにより、ハードウェア仕様の変更時もコードを修正して terraform apply するだけで、全リージョンへ一括反映されます。 5. Lambda関数の自動パッケージング & デプロイ # 第5回で紹介したGPUブローカーのPythonスクリプト( handler.py )をデプロイします。Terraform標準の archive_file データソースを使い、自動でZIP化して展開します。 起動テンプレートの導入に伴い、Lambda関数の環境変数には LAUNCH_TEMPLATE_NAME を渡します。 lambda.tf(クリックで展開) # Pythonコードの自動ZIPパッケージング data "archive_file" "lambda_zip" { type = "zip" source_dir = "${path.module}/../lambda" output_path = "${path.module}/dist/lambda_function.zip" } # GPU起動ブローカー Lambda関数 resource "aws_lambda_function" "broker" { function_name = "vllm-spot-broker" runtime = "python3.12" handler = "handler.lambda_handler" role = aws_iam_role.lambda_role.arn timeout = 120 memory_size = 256 filename = data.archive_file.lambda_zip.output_path source_code_hash = data.archive_file.lambda_zip.output_base64sha256 environment { variables = { TARGET_REGIONS = join(",", var.target_regions) S3_BUCKET_NAME = "my-vllm-models-hackathon-2026-{account_id}-{region}-an" INSTANCE_PROFILE_NAME = aws_iam_instance_profile.ec2_profile.name ECR_REPOSITORY_NAME = aws_ecr_repository.vllm.name TAG_SERVER_NAME = "vllm-ssm-spot-node" SG_NAME = "vllm-ssm-isolated-sg" LAUNCH_TEMPLATE_NAME = aws_launch_template.vllm_spot_template.name } } tags = { Project = "vllm-ephemeral" } } Lambdaハンドラー側での呼び出し(起動処理の簡潔化) # 起動テンプレートが整ったことで、Lambda関数( handler.py )のインスタンス起動処理は極めて簡潔になります。 # Launch Template を指定して1行で起動 run_params = { "MinCount": 1, "MaxCount": 1, "LaunchTemplate": { "LaunchTemplateName": os.environ.get("LAUNCH_TEMPLATE_NAME"), "Version": "$Latest", }, } if target_ami: run_params["ImageId"] = target_ami ec2.run_instances(**run_params) 長大な BlockDeviceMappings や UserData などをPython側で構築する必要はありません。Lambdaの責務は「最適リージョンのリアルタイム探索と、テンプレートによるエフェメラル起動」のみに集中できます。 6. Terraformの実行(一括プロビジョニングと環境破棄) # ディレクトリ構成を整えたら、コマンド実行で全リソースをプロビジョニングできます。 cd terraform/ # 1. プロバイダ初期化 terraform init # 2. 静的基盤の全展開(S3・ECR・IAM・SG・Lambda) terraform apply -auto-approve Apply complete! Resources: 18 added, 0 changed, 0 destroyed. Outputs: broker_lambda_arn = "arn:aws:lambda:ap-northeast-1:123456789012:function:vllm-spot-broker" ecr_repository_url = "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/vllm-openai" これにより、わずか数十秒でマルチリージョン展開に必要な基盤のすべてが整います。 日々のGPU起動・停止 # 静的基盤のデプロイ後は、日々のGPU起動・停止に第5回のスクリプト( 01_start_vllm_ssm.sh / 02_stop_vllm_ssm.sh )をそのまま使用します。 # GPUインスタンスの起動(Lambdaブローカー呼び出し & SSMトンネル確立) ./01_start_vllm_ssm.sh # 作業終了時のリソース破棄(SSM切断 & Lambda経由でのTerminate) ./02_stop_vllm_ssm.sh Terraform側でGPUインスタンス自体のライフサイクルは抱え込みません。動的な起動・停止をクライアントスクリプトに任せることで、 tfstate のロック待ちなしに迅速に推論環境を利用できます。 検証作業全体が終了し、クラウド上の静的基盤ごとすべてクリーンアップしたい場合のみ、 terraform destroy を実行します。 cd terraform/ terraform destroy -auto-approve --> 💡 発展:他ワークロードへの応用パターン 今回の検証ではvLLM(GPU推論)を題材としました。しかし、「Lambdaによるスポット探索・起動」と「SSMポートフォワーディング」の組み合わせは、他のワークロードにも幅広く応用可能です。 大規模コンパイル・ビルド環境 : 手元端末の負荷を軽減するため、多数のvCPUを持つコンピュート最適化インスタンス(例: c6i 系列)を必要な時間だけ立ち上げ、ビルド完了後に自動終了させる。 モデルのファインチューニングやバッチ学習 : 学習時のみ複数GPUインスタンスをスポット起動し、S3からデータセットを取得して学習し、生成された重みをS3へ保存した後にインスタンスを破棄する。 メモリ集約型のデータ処理 : ローカル環境ではメモリ不足になりやすい大規模データフレームの集計・分析時のみ、大容量メモリを搭載したインスタンス(例: r6i 系列)を一時的に利用する。 セキュアな一時開発環境(リモートDevbox) : インバウンドポートを開放せずにSSM経由で接続できるため、外部へのポート公開が制限されている環境でも、手元のVS Code等からセキュアに一時的な作業環境として利用できる。 「必要なタイミングだけクラウド上の適切なリソースを立ち上げ、完了後は確実に終了させる」というエフェメラルな運用は、コスト効率とセキュリティを両立させるアプローチとして幅広く活用できます。 まとめ # 本記事では、マルチリージョンにまたがるGPU推論基盤の静的リソースを Terraformで宣言的にコード化(IaC化) しました。 静的基盤と動的エフェメラルの役割分担 : 状態管理のオーバーヘッドを避け、静的基盤のみをTerraformに任せることで、軽快かつ堅牢なアーキテクチャを実現。 EC2起動テンプレート(Launch Template)の導入 : ハードウェア仕様や閉塞SG、UserDataブートストラップを一元的にコード化し、Lambda側からハードウェア依存コードを切り離し。 ECRクロスリージョン自動レプリケーション : 東京へ1回Pushするだけで全候補リージョンへAWSバックボーン経由で自動同期されるパイプラインを構築。 ゼロインバウンドSG & 最小権限IAM : 受信ルール0件のセキュリティグループやSSM/ECR/S3接続に必要なIAMポリシーを一括定義。 Lambda自動デプロイと環境破棄 : Pythonコードの自動ZIP化からプロビジョニング、そして検証終了時の terraform destroy による確実なクリーンアップ性を確立。 手動セットアップや場当たり的なスクリプトを排除し、コードで再現可能なインフラ基盤が整ったことで、日々のLLM検証をより安全・確実に運用できるようになりました。
本ブログは 2025 年 11 月 21 日に公開された AWS Blog “ Practical steps to minimize key exposure using AWS Security Services ” を翻訳したものです。 漏えいした 長期的な認証情報 は、 AWS Customer Incident Response Team (CIRT) が観測したセキュリティインシデントで、現在も脅威アクターに最も多く使われる侵入経路となっています。長期的な認証情報やアクセスキーが漏えいし、脅威アクターに使用されると、クラウド環境にセキュリティリスクが生じます。さらに、キーのローテーションが不十分な運用、複数のユーザー間でのアクセスキーの共有、未使用の認証情報の取り消し漏れによって、システムが危険にさらされたままになる可能性があります。 長期的な認証情報は使用しないことを強くお勧めします。これを機に、 AWS Identity and Access Management (IAM) ロールとフェデレーションアクセスへの移行を進めることができます。AWS が推奨する ベストプラクティス は、お客様が長期的な認証情報から 脱却 することです。ただし、すべての組織がこの移行をすぐに実現できるとは限らないことも、AWS は認識しています。 長期的な認証情報への意図しないアクセスに対して包括的な防御を構築するには、戦略的な多層アプローチが必要です。このアプローチは、理想的なセキュリティプラクティスと現実の運用上の制約との間のギャップを埋めることを目的としており、長期的な認証情報を必要とするレガシー AWS ワークロードを管理するチームに、すぐに実行できる手順を提供します。 この記事では、防御を構築する方法を順を追って説明します。まず、 Amazon Q Developer や AWS IAM Access Analyzer などのサービスを使用して既存のリスクと潜在的な露出を特定し、環境全体の認証情報リスクを可視化します。次に、 サービスコントロールポリシー (SCP) と データ境界 によって厳格な境界を確立し、認証情報を作成および使用できる方法と場所を制御します。これらの仕組みを整えたら、ネットワークレベルのコントロールによって防御態勢をさらに強化し、アクセスキーが使用される可能性のあるインフラストラクチャを保護します。具体的には、 AWS WAF や Amazon Inspector などのサービスを使用して、脆弱性の悪用からの保護に役立てます。最後に、シークレットの自動ローテーションなどの運用上のベストプラクティスを実装して、基本的なセキュリティ対策を継続的に実施し、侵害が発生した場合の影響を最小限に抑えます。 既存のアクセスキーと露出状況の検出 既存のアクセスキーの監査 包括的な監査を行うために、組織は認証情報レポートを定期的に生成する必要があります。このレポートを使用すると、長期的な認証情報を所有する IAM ユーザーを特定できるほか、キーの最終ローテーション日時、最終使用日時、最後に使用されたサービス、最後に使用されたリージョンなどの関連情報も確認できます。これらのレポートにより、認証情報の全体像を把握するために不可欠な可視性が得られます。長期間アクティビティがないアクセスキー、ローテーションポリシーで定めた期間を超過しているキー、見慣れないリージョンからの予期しない使用パターンに着目することで、未使用の認証情報や侵害された可能性のある認証情報を発見できます。 漏えいしたアクセスキーの検出 認証情報が侵害される一般的な原因の 1 つに、パブリックリポジトリへの不注意なコミットがあります。開発者が誤って認証情報をパブリックリポジトリにコミットすると、攻撃者が使用する自動スキャンツールによって、その認証情報が収集される可能性があります。コードスキャンは、こうした重大なセキュリティ問題を早期に発見するための基本的なステップです。機密性の高い認証情報が誤ってコードリポジトリにコミットされたり、本番環境にデプロイされて悪用の危険にさらされたりする前に、問題を発見できます。 Amazon Q Developer を使用すると、セキュリティの脆弱性やコード品質の問題がないか コードベースをレビュー し、開発サイクル全体を通じてアプリケーションのセキュリティポスチャを改善できます。ローカルのプロジェクトやワークスペース内のすべてのファイルを分析してコードベース全体をレビューすることも、単一のファイルだけをレビューすることもできます。また、自動レビューを有効にすると、記述中のコードをその都度評価することもできます。 Amazon Q は、次のような問題がないかコードをレビューします。 SAST (静的アプリケーションセキュリティテスト) スキャン – ソースコード内のセキュリティの脆弱性を検出します。Amazon Q は、リソースリーク、SQL インジェクション、クロスサイトスクリプティングなど、さまざまなセキュリティ問題を特定します。 シークレットの検出 – コード内の機密情報が露出するのを防ぎます。Amazon Q は、コードファイルとテキストファイルをレビューして、ハードコードされたパスワード、データベース接続文字列、ユーザー名などのシークレットがないか確認します。シークレットの検出結果には、保護されていないシークレットに関する情報と、その保護方法が含まれます。 IaC の問題 – インフラストラクチャファイルのセキュリティポスチャを評価します。Amazon Q は、Infrastructure as Code (IaC) のコードファイルをレビューして、設定ミス、コンプライアンス上の問題、セキュリティの問題を検出できます。 訳注: 原文公開後の 2026 年 5 月 15 日に、Amazon Q Developer の新規登録は停止しました。また、Amazon Q Developer IDE プラグインと有料サブスクリプションは、2027 年 4 月 30 日にサポートが終了する予定です。移行先として Kiro をお勧めします。詳細は「 Amazon Q Developer のサポート終了に関するお知らせ 」を参照してください。Kiro を使用したセキュリティレビューの例については、「 Kiro と Amazon Q でセキュリティポスチャを強化する 5 つの方法 」を参照してください。 AWS Trusted Advisor には、 漏えいしたアクセスキーのチェック も用意されています。このチェックでは、広く利用されているコードリポジトリで公開されてしまったアクセスキーがないかを確認します。また、アクセスキーの侵害が原因と考えられる、 Amazon Elastic Compute Cloud (Amazon EC2) の異常な使用がないかも確認します。 これらは有用なセキュリティツールですが、ローカルの開発マシンや外部システムなど、スキャン範囲外の場所に保存されたシークレットやアクセスキーは検出できません。認証情報の露出を特定して防止する唯一の手段としてではなく、より広範なセキュリティ戦略の一部として使用してください。 侵害された可能性のあるアクセスキーに対処する場合は、直ちにキーをローテーションすることをお勧めします。手順については、 IAM ユーザーのアクセスキーをローテーションする方法 を参照してください。 未使用のアクセスの検出 漏えいした認証情報の特定に加えて、未使用のアクセスキーを検出することでも、アタックサーフェスを最小限に抑えられます。IAM Access Analyzer には、 未使用のアクセスを検出するアナライザー があります。このアナライザーは、過剰に付与されているアクセス許可や、使用されなくなったアクセス許可を検出します。対象には、未使用の IAM ロール、IAM ユーザーの未使用のアクセスキーとパスワード、アクティブな IAM ロールおよび IAM ユーザーで使用されていないサービスとアクションが含まれます。組織全体またはアカウント固有のアナライザーが生成した検出結果を確認した後、不要なアクセス許可を削除または変更できます。未使用の認証情報とアクセスを特定して取り消しておけば、脅威アクターに認証情報を取得された場合でも影響を抑えることができます。 これらのツールを導入すると、環境全体の認証情報リスクに関するインサイトを得られます。これらの機能を組み合わせることで、埋め込まれたシークレット、漏えいしたアクセスキー、削除が必要な認証情報を洗い出すことができます。 予防的ガードレール: データ境界の確立 漏えいした認証情報や未使用の認証情報を特定する方法がわかったところで、次は SCP と リソースコントロールポリシー (RCP) を使用してデータ境界を作成する方法を見ていきましょう。データ境界は、信頼できるアイデンティティだけが、想定されたネットワークから信頼できるリソースにアクセスできるようにするのに役立ちます。AWS 環境に予防的ガードレールを実装することは、不正アクセスやアクセスキーの侵害から環境を保護するうえで不可欠です。データ境界の概要と確立方法の詳細については、ブログ記事シリーズ「 Establishing a Data Perimeter on AWS 」を参照してください。 例えば、 次の SCP は、企業の Classless Inter-Domain Routing (CIDR) や特定の仮想プライベートクラウド (VPC) 以外の想定外のネットワークから IAM ユーザーの認証情報が使用されることを拒否します。このポリシーでは、除外しないとサービスへのアクセスに影響が出る複数のアクションを NotAction 要素に含めています。SCP と RCP の例は、 data-perimeter-policy-examples で公開されています。このリポジトリは、最新の改訂版ポリシーの正規の情報源です。次の例は、想定外のネットワークからユーザーの認証情報が使用されるユースケースに対応するように更新したものです。 { "Version": "2012-10-17", "Statement": [ { "Sid": "EnforceNetworkPerimeterOnIAMUsers", "Effect": "Deny", "NotAction": [ "es:ES*", "dax:GetItem", "dax:BatchGetItem", "dax:Query", "dax:Scan", "dax:PutItem", "dax:UpdateItem", "dax:DeleteItem", "dax:BatchWriteItem", "dax:ConditionCheckItem", "neptune-db:*", "kafka-cluster:*", "elasticfilesystem:client*", "rds-db:connect" ], "Resource": "*", "Condition": { "BoolIfExists": { "aws:ViaAWSService": "false" }, "NotIpAddressIfExists": { "aws:SourceIp": [ "<my-corporate-cidr>" ] }, "StringNotEqualsIfExists": { "aws:SourceVpc": [ "<my-vpc>" ] }, "ArnLike": { "aws:PrincipalArn": [ "arn:aws:iam::*:user/*" ] } } } ] このネットワーク境界を実装すると、認証情報の侵害が不正アクセスやデータの露出につながるリスクを軽減できます。盗んだ認証情報をコーヒーショップや自宅のネットワークから使用しようとする脅威アクターはブロックされるため、認証情報への意図しないアクセスによる影響を抑えることができます。 多層防御をさらに強化するには、RCP を使用してデータを保護できます。例えば、RCP を使用すると、どのアイデンティティがリソースにアクセスできるかを制御できます。組織内のアイデンティティには組織内のリソースへのアクセスを許可し、組織外のアイデンティティによるリソースへのアクセスを防止したい場合は、RCP でこの制御を適用できます。RCP を使用すると、リソースに対して利用可能なアクセス許可の上限を設定し、組織の内外を問わず、どのプリンシパルがリソースにアクセスできるかを指定できます。一方、SCP が影響を与えられるのは、AWS 組織内のプリンシパルの有効なアクセス許可に限られます。 次の RCP を実装すると、長期的な認証情報が誤って漏えいした場合に、組織外の権限のないユーザーがその認証情報を使用して重要なデータやリソースにアクセスしようとしても、確実にブロックされるようにするのに役立ちます。このポリシーは、企業の CIDR 範囲 ( NotIpAddressIfExists と aws:SourceIp ) または VPC ( StringNotEqualsIfExists と aws:SourceVpc ) からのリクエストでない限り、 Amazon Simple Storage Service (Amazon S3) のアクションを拒否します。対応サービスについては、 RCP をサポートする AWS サービスの一覧 を参照してください。SCP と RCP の例は、こちらの GitHub リポジトリ で公開されています。このリポジトリは、最新の改訂版ポリシーの正規の情報源です。次の例は、この記事で取り上げたユースケースに対応するように更新したものです。 { "Version": "2012-10-17", "Statement": [ { "Sid": "EnforceNetworkPerimeter", "Effect": "Deny", "Principal": "*", "Action": [ "s3:*", "sqs:*", "kms:*", "secretsmanager:*", "sts:AssumeRole", "sts:DecodeAuthorizationMessage", "sts:GetAccessKeyInfo", "sts:GetFederationToken", "sts:GetServiceBearerToken", "sts:GetSessionToken", "sts:SetContext", "aoss:*", "ecr:*" ], "Resource": "*", "Condition": { "NotIpAddressIfExists": { "aws:SourceIp": " <0.0.0.0/1> " }, "StringNotEqualsIfExists": { "aws:SourceVpc": " <my-vpc> " }, "BoolIfExists": { "aws:PrincipalIsAWSService": "false", "aws:ViaAWSService": "false" } } } ] } 長期的な認証情報からの移行を始める準備ができている場合は、SCP を使用してアクセスキーの作成と既存キーの更新を拒否することで、IAM ロールやフェデレーションアクセスなど、より安全な認証方法の使用を徹底できます。次のポリシーは、プリンシパルによる AWS アクセスキーの作成と更新を拒否します。 { "Version": "2012-10-17", "Statement": [ { "Effect": "Deny", "Action": [ "iam:CreateAccessKey", "iam:UpdateAccessKey" ], "Resource": "*" } ] } データ境界のコントロールを確立したら、次はネットワークコントロールによって、アクセスキーが使用されるランタイム環境を保護する方法を見ていきましょう。 ネットワークコントロール: アクセスキーが使用されるランタイム環境の保護 データ境界を構築し、SCP と RCP を使用するだけでなく、これらのアクセスキーを使用するコンピューティングおよびネットワークのインフラストラクチャを保護することも不可欠です。悪意のある攻撃者は、不正アクセスを目的としてこうした環境を標的にすることが多く、侵害されたランタイム環境を通じて認証情報が露出するリスクがあります。そのため、インフラストラクチャの保護は、アクセスキーのセキュリティにおいて重要な要素となります。 セキュリティグループとネットワーク ACL (NACL) インスタンスレベルやサブネットレベルなど、さまざまなレベルでファイアウォールとして機能するネットワークレベルのセキュリティ保護を使用して、不正アクセスの防止に役立ててください。 SSH (ポート 22) や RDP (ポート 3389) などの重要なポートは、不正なシステムアクセスを狙う悪意のある攻撃者の主な標的となるため、制限することが不可欠です。セキュリティグループで管理用ポートを開放したままにすると、アタックサーフェスとセキュリティリスクが増大する可能性があります。 AWS Systems Manager Session Manager を使用すると、インバウンドポートを公開せずに安全なリモートアクセスを実現でき、踏み台ホストの使用や SSH キー管理の必要性を軽減できます。 NACL は、サブネットの境界でステートレスなパケットフィルターとして機能し、サブネットレベルでアクセスを効果的にブロックします。個々のインスタンスを保護するセキュリティグループとは異なり、NACL はインバウンドとアウトバウンドの両方のトラフィックに対する明示的な許可/拒否ルールによって、サブネット全体を保護します。NACL は、トラフィックがインスタンスに到達する前にフィルタリングする、重要な境界防御レイヤーとなります。多層防御アプローチの一環としてデプロイすると、NACL はアプリケーション層間をサブネットレベルで分離し、ネットワークエッジで悪意のあるトラフィックパターンをブロックします。また、他のセキュリティレイヤーが侵害された場合でも保護を維持します。これにより、複数の独立したコントロールポイントによる包括的なネットワークセキュリティを実現できます。 NACL よりもさらにネットワーク保護を強化したい場合は、 AWS Network Firewall を使用して、包括的な VPC 保護によるエンタープライズグレードの境界防御を実現できます。Network Firewall は、侵入防止システム、ドメインフィルタリング、ディープパケットインスペクション、地理的 IP コントロールを組み合わせるとともに、Amazon が収集したグローバルな脅威インテリジェンスを使用して、新たな脅威からクラウド環境を自動的に保護します。Network Firewall と AWS Transit Gateway を統合すると、一元管理によって、VPC やアベイラビリティーゾーン全体に一貫したセキュリティポリシーを適用できます。 組織全体でネットワークセキュリティを自動化してスケールさせるには、 AWS Firewall Manager を使用して、Network Firewall のルールとセキュリティグループポリシーの両方を一元管理できます。Firewall Manager は、組織の成長に合わせて 共通のセキュリティグループポリシーのデプロイを自動化 し、未使用のグループをクリーンアップし、複数のアカウントや組織単位にわたって許可範囲が広すぎるルールを修正することで、セキュリティの維持に役立ちます。 Amazon Inspector 意図しないネットワークへの露出を大規模に特定するには、 Amazon Inspector の使用を検討してください。Amazon Inspector は、ソフトウェアの脆弱性や意図しないネットワークへの露出がないか AWS ワークロードを継続的にスキャンし、セキュリティの脆弱性が悪用される前に特定して修正できるようにします。 主な機能は次のとおりです。 パッケージの脆弱性 : パッケージの脆弱性の検出結果は、AWS 環境内で CVE (Common Vulnerabilities and Exposures) の影響を受けるソフトウェアパッケージを特定します。悪意のある攻撃者は、パッチが適用されていないこれらの脆弱性を悪用して、データの機密性、完全性、可用性を侵害したり、他のシステムにアクセスしたりする可能性があります。 コードの脆弱性 : コードの脆弱性の検出結果は、悪用される可能性のあるコード行を特定します。コードの脆弱性には、暗号化の欠如、データ漏えい、インジェクション、脆弱な暗号方式などがあります。Amazon Inspector は、 Lambda 関数のスキャン と Code Security 機能によって検出結果を生成し、Amazon Q と共同で開発された内部ディテクターに基づいて、ポリシー違反や脆弱性を特定します。 ネットワーク到達可能性: ネットワーク到達可能性の検出結果は、インターネットゲートウェイ (Application Load Balancer または Classic Load Balancer の背後にあるインスタンスを含む)、VPC ピアリング接続、または仮想ゲートウェイ経由の VPN を介して、インターネットからポートに到達できるかどうかを示します。これらの検出結果は、管理が不十分なセキュリティグループ、NACL、インターネットゲートウェイなど、許可範囲が広すぎる可能性のあるネットワーク設定や、悪意のあるアクセスを許す可能性のあるネットワーク設定を明らかにします。インスタンスのセキュリティグループで開いている SSH ポートも特定できます。 AWS WAF AWS WAF は、ネットワークセキュリティのコントロールと脆弱性管理を補完するサービスです。認証情報の露出につながる可能性のある悪意のあるウェブトラフィックをフィルタリングすることで、防御レイヤーを追加します。 AWS WAF には、不正アクセスや一般的な脆弱性から保護するための複数のマネージドルールグループが用意されています。 AWS WAF Fraud Control Account Creation Fraud Prevention (ACFP) ルールグループ : ACFP は、リクエストトークンを使用して、クライアントブラウザに関する情報と、アカウント作成リクエストを生成する際の人間による操作の度合いに関する情報を収集します。このルールグループは、IP アドレスとクライアントセッションごとにリクエストを集計し、さらに住所や電話番号など、提供されたアカウント情報ごとにも集計して、大量のアカウント作成の試みを検出して管理します。また、侵害された認証情報を使用した新規アカウントの作成を検出してブロックするため、アプリケーションと新規ユーザーのセキュリティポスチャの保護に役立ちます。 AWS WAF Fraud Control Account Takeover Prevention (ATP) ルールグループ : ATP は、異常なサインイン試行や、盗まれた認証情報を使用したサインイン試行を可視化して制御できるようにすることで、不正なアクティビティにつながる可能性のあるアカウントの乗っ取りの防止に役立ちます。 Amazon CloudFront ディストリビューションの場合、ATP ルールグループは、受信したサインインリクエストの検査に加えて、サインイン試行に対するアプリケーションのレスポンスも検査し、成功率と失敗率を追跡します。ATP は、E メールアドレスとパスワードの組み合わせを、盗まれた認証情報のデータベースと照合します。このデータベースは定期的に更新され、ダークウェブで新たに見つかった、漏えいした認証情報が追加されます。 運用上のベストプラクティス これらの保護レイヤーを補完し、セキュリティポスチャを継続的に維持するために、Secrets Manager による認証情報の自動管理を実装してください。これにより、環境全体でアクセスキーの適切なローテーションとライフサイクル管理を実現できます。自動化によって人為的ミスが減り、認証情報をタイムリーに更新しやすくなるほか、認証情報が侵害された場合の露出期間も短縮できます。 キーは少なくとも 90 日に 1 回ローテーションすることをお勧めします。 Secrets Manager は、スケジュールに従ってシークレットをローテーションするプロセスを自動化し、手作業なしで認証情報が定期的に更新されるようにします。また、シークレットの保存場所を一元化するため、複数のユーザー間でアクセスキーが共有される可能性も低減できます。Secrets Manager では、 Lambda 統合 を使用して、キーの自動ローテーションを設定できます。 また、アクセスキーの自動ローテーションを大規模に実装するためにデプロイできる、既存の ソリューション もあります。このパターンでは、 AWS CloudFormation テンプレートを使用して、IAM アクセスキーを自動的にローテーションできます。テンプレートは、GitHub の IAM キーローテーション リポジトリで提供されています。 自動ローテーションを実装できず、ローテーションが必要なアクセスキーをすばやく特定したい場合は、 AWS Trusted Advisor の IAM アクセスキーのローテーション に関するセキュリティチェックを使用できます。このセキュリティチェックでは、過去 90 日間にローテーションされていないアクティブな IAM アクセスキーを確認します。手動でローテーションを行う必要がある場合は、このセキュリティチェックを使用して、環境内のどのアクセスキーをローテーションすべきかを詳しく調べることができます。 異常な IAM アクティビティの検出 最後に、IAM インフラストラクチャを保護するためのプロアクティブな対策は重要ですが、堅牢な検出とアラートの仕組みを整えておくことも同様に重要です。どれほど入念に対策を講じても、予期しない脅威や不正なアクティビティが発生する可能性は残ります。そのため、包括的な多層防御戦略には、IAM に関連する異常なイベントを迅速に特定して対応する機能を含める必要があります。 Amazon GuardDuty は、機械学習と統合された脅威インテリジェンスを組み合わせて、AWS アカウント、ワークロード、データを脅威から保護するのに役立ちます。 GuardDuty 拡張脅威検出は、さまざまなデータソースにわたる複数のイベントを自動的に関連付けて、AWS 環境内の潜在的な脅威を特定します。拡張脅威検出は、疑わしい一連のアクティビティを検出すると、包括的な攻撃シーケンスの検出結果を生成します。このシステムは、個々の API アクティビティを弱いシグナルとして分析します。これらのシグナルは単独ではリスクを示さない場合もありますが、特定のパターンとして組み合わせて観測されると、潜在的なセキュリティ問題が明らかになることがあります。 この機能は、AWS アカウントで GuardDuty を有効にするとデフォルトで有効になるため、追加の設定なしで保護を受けられます。 侵害された認証情報に関連する攻撃シーケンスの検出結果は AttackSequence:IAM/CompromisedCredentials で、重要度は 重大 (Critical) に分類されています。この検出結果は、AWS 認証情報を使用して実行された一連の疑わしいアクションを GuardDuty が検出し、そのアクションが環境内の 1 つ以上のリソースに影響を与えていることを示します。同じ認証情報による疑わしく異常な脅威行動が複数観測されているため、その認証情報が悪用されている可能性が高いと判断されます。 まとめ この記事で紹介したセキュリティのベストプラクティスは、長期的な認証情報に関連するリスクを軽減するための包括的な多層アプローチです。プロアクティブなコードスキャン、キーの自動ローテーション、ネットワークレベルのコントロール、データ境界による制限、脅威検出を実装することで、一時的な認証情報へ完全に移行できるようになるまでの間、アタックサーフェスを大幅に削減し、組織の AWS リソースをより確実に保護できます。 この記事の推奨事項は、組織のセキュリティポスチャを良好な状態に保つための十分なコントロールですが、各環境の具体的なニーズやリスクプロファイルによっては、追加のセキュリティ対策を講じることができる場合もあります。重要なのは、認証情報の管理と保護に対して、全体的かつ多層的なアプローチを採用することです。そうすることで、一時的な認証情報へ完全に移行できるようになるまでのギャップを埋めることができます。 これらのセキュリティ対策を実装するとリスクを軽減できますが、長期的な認証情報には本質的にセキュリティリスクが伴います。厳格なベストプラクティスと包括的なセキュリティコントロールを適用しても、認証情報が侵害される可能性を完全になくすことはできません。組織のセキュリティポスチャを評価し、可能な限り IAM ロールとフェデレーションによる一時的な認証情報を優先して使用することを検討してください。ご質問がある場合やサポートが必要な場合は、AWS がお手伝いします。 Jennifer Paz Jennifer は 10 年以上の経験を持つセキュリティエンジニアで、現在は AWS Customer Incident Response Team (CIRT) に所属しています。お客様のセキュリティ課題の解決を支援し、セキュリティポスチャの強化に役立つ複雑なソリューションを実装することにやりがいを感じています。仕事以外では、熱心なランナーであり、ピックルボール愛好家、旅行好き、グルメでもあり、常に新しい味との出会いを求めています。 Samantha Tavares Samantha は、AWS Customer Incident Response Team のインシデントレスポンダーです。お客様のクラウド環境の保護を支援することに情熱を注いでいます。セキュリティの課題に取り組んでいないときは、CrossFit で汗を流したり、次の旅行の計画を立てたりしています。 本ブログは Security Solutions Architect の 中島 章博 が翻訳しました。
本記事は 2026 年 10 月 13 日 に公開された「 Monitor Amazon Aurora DSQL costs with the Aurora DSQL console and CloudWatch alarms 」を翻訳したものです。 Amazon Aurora DSQL のワークロードが拡大し、Distributed Processing Unit (DPU) の消費量が増えてきたとき、コストをどう把握すればよいでしょうか。適切なモニタリングを用意しておけば、支出を先回りして管理でき、サーバーレスデータベースのコストを常に把握できます。固定のインスタンス料金という上限がなくても、コストを見失うことはありません。 本記事では、Aurora DSQL の使用量とコストをモニタリングし、オンデマンド料金のメリットを最大限に活かす方法を紹介します。Aurora DSQL では、使った分だけ料金が発生します。ここでは、Aurora DSQL コンソールに組み込まれた Usage and cost パネルと Amazon CloudWatch アラームを順に説明します。本記事の CloudWatch アラームは、1 時間ごとの DPU 使用量 (月初からの累計支出ではありません) を 1 時間単位でチェックします。そのため、アラートは即時ではなく、CloudWatch メトリクスの計測に伴う少しの遅れ (ほぼリアルタイム) をはさんで届きます。本記事で扱う内容は次のとおりです。 Aurora DSQL の DPU 料金モデルと、CloudWatch メトリクスと請求額の対応関係 Aurora DSQL コンソールの Usage and cost パネルで DPU 使用量と推定コストを確認する方法 1 時間あたりの DPU 使用量が予算の 1 時間分に近づいたときに Amazon Simple Notification Service (Amazon SNS) で通知する CloudWatch アラームの設定方法。推奨アラームが入力済みになるコンソールの Create alarm フローも含みます。 AWS CloudFormation を使い、Infrastructure as Code (IaC) としてモニタリング用アラームを一貫した形でデプロイする方法 本記事は、Aurora DSQL を利用中または評価中で、コストを先回りして管理したい AWS 開発者やデータベース管理者を対象とした上級 (300) レベルの内容です。 前提条件 始める前に、次のものがそろっていることを確認してください。 稼働中の Aurora DSQL クラスター (シングルリージョンまたはマルチリージョン) 適切な権限で設定済みの AWS Command Line Interface (AWS CLI) AWS Identity and Access Management (IAM) ロールと CloudWatch アラームを作成する権限 AWS CloudFormation コンソールにアクセスできる AWS アカウント Aurora DSQL の料金体系 Aurora DSQL は、アクティブ-アクティブのマルチリージョンアーキテクチャを備えた、サーバーレスで PostgreSQL 互換の分散 SQL データベースです。シングルリージョンで 99.99%、マルチリージョンで 99.999% の可用性を実現するよう設計されています。料金はリクエストベースの従量課金で、プロビジョニングするインスタンスはなく、データベースがアイドル状態のときに時間単位の料金も発生しません。使わないときはゼロまでスケールするため、消費した分だけを支払います。 Aurora DSQL の課金対象は主に 2 つです。Distributed Processing Unit (DPU) で測定するデータベースアクティビティと、GiB-月で測定するストレージです。アクティブなデータベース使用量は DPU という単一の課金単位にまとめられ、コンピューティング、読み取り、書き込み、マルチリージョン書き込み、変更データキャプチャ (CDC) ストリーミングのどのアクティビティでも、DPU は同じ料金で正規化されます。vCPU、メモリ、ネットワーク帯域幅、1 秒あたりの I/O オペレーション数 (IOPS) を個別に追跡・課金するのではなく、アクティブなデータベース使用量をこの単一のメトリクスに統合しています。ストレージは別途課金され、DPU の計算には含まれません。 シングルリージョンクラスターの場合、合計 DPU は次の 3 つの要素の合計です。 TotalDPU = ComputeDPU + ReadDPU + WriteDPU 対応する機能を使っている場合に限り、2 つの要素が追加されます。マルチリージョンクラスターでは MultiRegionWriteDPU、変更データキャプチャ (CDC) を有効にしたクラスターでは StreamDPU が加わります。 TotalDPU = ComputeDPU + ReadDPU + WriteDPU + MultiRegionWriteDPU (multi-Region clusters only) + StreamDPU (clusters with CDC enabled only) 注: StreamDPU はクラスターで CDC を有効にした場合にのみ、 MultiRegionWriteDPU はマルチリージョンクラスターでのみ発生します。CDC ストリームのないシングルリージョンクラスターでは両方ともゼロで、請求額には影響しません。 表 1 に、米国東部 (オハイオ) リージョンにおける Aurora DSQL の料金要素をまとめます。料金はリージョンによって異なります。最新の料金は Aurora DSQL の料金ページ を参照してください。 表 1: Aurora DSQL の料金要素 要素 料金 (米国東部、オハイオ) 説明 DPU 100 万 DPU あたり 8 USD コンピューティング、読み取り、書き込み、マルチリージョン書き込み、CDC ストリーミングのすべてのアクティビティ ストレージ 1 GiB-月あたり 0.33 USD 3 つのアベイラビリティーゾーンにレプリケートされます。料金はリージョンごとに 1 つの論理コピー分です AWS 無料利用枠 100,000 DPU + 1 GiB/月 毎月無料で利用でき、請求に自動的に適用されます ストレージの料金は 1 GiB-月あたり 0.33 USD です。Aurora DSQL は各リージョンで 3 つのアベイラビリティーゾーンにストレージをレプリケートしますが、料金はリージョンごとに 1 つの論理コピー分のみです。 マルチリージョンクラスターを作成した場合に限り、Aurora DSQL は書き込みを他の AWS リージョンにあるピアクラスターへ自動的にレプリケートします。レプリケートされた書き込みには元の書き込みと同額の DPU 料金が追加で発生し、CloudWatch では MultiRegionWriteDPU として表示されます。このレプリケーションに個別のデータ転送料金はかかりません。シングルリージョンクラスターでは MultiRegionWriteDPU は発生しません。 請求書に表示される明細は、ストレージと DPU の 2 項目だけです。DPU の明細は各要素の合計です。 Aurora DSQL の主な CloudWatch メトリクス Aurora DSQL は、ほぼリアルタイムの使用量メトリクスを AWS/AuroraDSQL 名前空間に ClusterId ディメンション付きで CloudWatch に発行します。CloudWatch はこれらの統計を 15 か月間保持するため、傾向分析に十分な履歴データを利用できます。 表 2: 請求に対応する DPU メトリクス (ClusterId ディメンション) メトリクス 単位 説明 ComputeDPU DPU コンピューティング (クエリ処理) のアクティブ使用量 ReadDPU DPU 読み取りのアクティブ使用量 WriteDPU DPU 書き込みのアクティブ使用量 MultiRegionWriteDPU DPU マルチリージョン書き込み (マルチリージョンクラスターのみ) TotalDPU DPU アクティブ使用量の DPU 合計 (該当するすべての要素の合計) CDC ストリーミングを有効にしている場合は、Aurora DSQL が ClusterId と StreamId の両ディメンション付きで発行するストリーム単位のメトリクスを使って、ストリームごとにモニタリングできます。表 3 に、コストに特に関係する CDC ストリームのメトリクスを示します。 表 3: CDC ストリームのメトリクス (ClusterId および StreamId ディメンション) メトリクス 単位 説明 StreamDPU DPU CDC ストリームが消費した DPU (CDC を有効にしたクラスターのみ) BytesStreamed Bytes CDC パイプラインでストリーミングされた合計バイト数。課金に使用されます PublishedBytes Bytes ターゲットの Amazon Kinesis Data Streams ストリームに書き込まれたバイト数 IsImpaired None ストリームに障害がある場合は 1、正常な場合は 0 表 4 に、リソース消費のパターンを把握するのに役立つオブザーバビリティメトリクスを示します。 表 4: オブザーバビリティメトリクス メトリクス 単位 説明 BytesRead Bytes トランザクションがストレージから読み取った合計バイト数 BytesWritten Bytes トランザクションがストレージに書き込んだ合計バイト数 ClusterStorageSize Bytes クラスターの現在のストレージサイズ ComputeTime Milliseconds クエリプロセッサが消費したコンピューティング時間 OccConflicts None 楽観的同時実行制御 (OCC) の競合により中止されたトランザクション 重要: コストを追跡する際は、DPU メトリクスに Sum 統計を使用してください。Sum 統計では一定期間の総消費量が得られ、請求額と直接対応します。DPU 数を金額の見積もりに換算するには、CloudWatch のメトリクス演算を使います。 Estimated Cost ($) = SUM(TotalDPU) x [your regional per-DPU rate, e.g., 0.000008 for us-east-1] 注: プレースホルダーは、お使いのリージョンの DPU 単価に置き換えてください。たとえば、1 DPU あたり 0.000008 USD は、米国東部 (バージニア北部) us-east-1 リージョンと米国東部 (オハイオ) us-east-2 リージョンにおける 100 万 DPU あたり 8 USD に相当します。料金はリージョンによって異なります。お使いのリージョンの料金は Aurora DSQL の料金ページを参照してください。 Aurora DSQL コンソールでコストを確認する Aurora DSQL コンソールには Usage and cost パネルが組み込まれており、DPU 消費量と推定コストを直接表示します。ダッシュボードを別途設定する必要はありません。このパネルは、AWS マネジメントコンソールのクラスター詳細ページから利用できます。 パネルには、過去 24 時間、7 日間、30 日間の DPU 総消費量、リージョンでの推定コスト、クラスターのストレージサイズ (30 日分のストレージコスト付き) が表示されます。読み取り、書き込み、コンピューティングの DPU 内訳は表示されません。内訳は CloudWatch メトリクスのビューで確認できます。 次のスクリーンショットは、コンソールに表示された Aurora DSQL クラスターの Usage and cost パネルです。 図 1: Aurora DSQL コンソールのクラスターの Summary タブにある Usage and cost パネル。過去 24 時間、7 日間、30 日間の DPU 使用量と推定コスト、クラスターのストレージサイズ、Create alarm ボタンが表示されている このパネルを開くには、Aurora コンソールのナビゲーションペインで Clusters を選択し、Aurora DSQL クラスターを選んでから、クラスター詳細ページの Summary タブを選択します。デフォルトでは、過去 24 時間、7 日間、30 日間の DPU 消費量と推定コストが並べて表示されます。 DPU の要素 (読み取り、書き込み、コンピューティング、マルチリージョン書き込み) ごとの詳しい内訳を見るには、クラスター詳細ページの Monitoring タブを選択します。要素ごとのグラフと時間範囲を設定できる、CloudWatch メトリクスの詳細ビューが表示されます。 マルチリージョンクラスターの場合、各ピアクラスターはそれぞれのリージョンのコンソールで確認します。あるクラスターの Usage and cost パネルには、そのリージョンの DPU 消費量と推定コストが表示されます。ピアリージョンごとにパネルを開けば、リージョン間で消費量を比較し、書き込みレプリケーションのコストに想定外の偏りがないかを確認できます。 コストアラート用の CloudWatch アラームを設定する CloudWatch アラームを使うと、Aurora DSQL の 1 時間あたりの DPU 使用量が定義したしきい値に近づいたり超えたりしたときに、自動で対応できます。各アラームは 1 つのメトリクスを監視し、しきい値に対するメトリクスの値に応じて状態が変わります。 アラームの状態は次のとおりです。 OK: メトリクスが定義したしきい値の範囲内にあります。 ALARM: メトリクスが定義したしきい値を超えています。 INSUFFICIENT_DATA: アラームの状態を判定するのに十分なデータポイントがありません。 アラームがメトリクスを評価する方法は、次の 3 つの主要な設定で決まります。 Period (期間): メトリクスを評価する時間の長さ (たとえば、1 時間ごとに評価する場合は 3,600 秒) Evaluation periods (評価期間): 評価する連続した期間の数 Datapoints to alarm (アラームを発生させるデータポイント): アラームの状態を変えるのに、評価期間のうち何期間でしきい値を超える必要があるか 注: CloudWatch アラームは、固定の期間でメトリクスを評価します。月初からの累計支出は追跡せず、30 日間のアラーム期間もネイティブには用意されていません。本記事のアラームは 1 時間単位のアラームです。1 時間ごとに TotalDPU の合計を監視し、その 1 時間の値が予算の 1 時間分を超えると ALARM 状態になります。そのため、変動の大きいワークロードでは、月全体では予算内に収まっていても、特定の 1 時間でアラームが発生することがあります。月初からの累計を追跡するには、このアラームと AWS Budgets を組み合わせてください (ベストプラクティスを参照)。CDC を使っている場合、Aurora DSQL は StreamDPU を ClusterId と StreamId ディメンションを持つストリーム単位の別メトリクスとして発行しますが、このアラームの TotalDPU メトリクスはクラスター単位です。ストリーミングのコストを確実にモニタリングするには、ストリームごとに StreamDPU の別アラームを作成してください。 ステップ 1: しきい値を計算する アラームは 1 時間ずつ評価するため、入力する値は 1 時間あたりの DPU しきい値です。表 5 では、月間予算の目標から 1 時間あたりのしきい値を算出しています。月間の DPU 許容量を平均的な 1 か月の 730 時間 (AWS Pricing Calculator と同じ考え方) で均等に割り、その 1 時間分の 80% を早期警告のしきい値としています。 表 5: 1 時間あたりのアラームしきい値の計算例 月間予算 月間 DPU 許容量 1 時間分 (DPU) 1 時間あたりの警告 – 80% (DPU) 50 USD 6,250,000 ~8,562 ~6,849 100 USD 12,500,000 ~17,123 ~13,699 500 USD 62,500,000 ~85,616 ~68,493 注: 以降の手順では、「1 時間あたりの警告 (80%)」列の値をアラームのしきい値として設定します。たとえば ~13,699 は、月 100 USD の予算の 1 時間分の 80% に相当します。 ステップ 2: 通知用の Amazon SNS トピックを作成する Amazon SNS トピックを作成し、チームのメールアドレスをサブスクライブしてアラーム通知を受け取れるようにします。 aws sns create-topic --name dsql-cost-alerts aws sns subscribe \ --topic-arn arn:aws:sns:<region>:<account-id>:dsql-cost-alerts \ --protocol email \ --notification-endpoint your-team@example.com ステップ 3a: Aurora DSQL コンソールからアラームを作成する (推奨) 最もお手軽なのは、Aurora DSQL コンソールから作成する方法です。クラスターの Summary タブにある Usage and cost パネルには、Create alarm アクションがあります。これを選択すると CloudWatch のアラーム作成フローが開き、 TotalDPU メトリクス、 AWS/AuroraDSQL 名前空間、クラスターの ClusterId があらかじめ入力されています。あとは統計に合計、期間に 1 時間、しきい値に表 5 の 1 時間あたりの警告値を設定し、ステップ 2 の SNS トピックを指定します。最近追加されたコンソール機能なので、メトリクスのツリーを手作業でたどる必要はありません。 アラームを手動で作成する場合やスクリプト化する場合は、以降の CloudWatch コンソールまたは AWS CLI の手順を使用してください。 ステップ 3b: CloudWatch アラームを作成する (CloudWatch コンソール) CloudWatch コンソールでアラームを手動作成するには、次の手順を実行します。 CloudWatch コンソールを開き、ナビゲーションペインで Alarms 、 All alarms を選択します。 Create alarm を選択し、 Select metric を選択します。 メトリクスブラウザで AWS/AuroraDSQL 、 ClusterId の順に選択します。対象のクラスターと TotalDPU メトリクスを選択します。 Specify metric and conditions で、 Statistic を Sum 、 Period を 1 時間 (3,600 秒)、しきい値の種類を Static に設定します。 Whenever TotalDPU is で Greater than を選択し、計算した 1 時間あたりの警告しきい値を入力します (たとえば、月 100 USD の予算で 80% の警告なら 13699)。 Evaluation periods を 1、 Datapoints to alarm を 1 に設定します。 Missing data treatment は Treat missing data as not breaching に設定します。 Notification で SNS トピック ( dsql-cost-alerts ) を選択し、アラームが ALARM、OK、INSUFFICIENT_DATA の各状態になったときに通知されるようにします。 DSQL-Hourly-DPU-Budget-Warning のようなわかりやすい名前をアラームに付け、設定を確認して Create alarm を選択します。 ステップ 3c: CloudWatch アラームを作成する (AWS CLI) AWS CLI で同じアラームを作成することもできます。 aws cloudwatch put-metric-alarm \ --alarm-name "DSQL-Hourly-DPU-Budget-Warning" \ --alarm-description "Alert when hourly DPU exceeds 80% of budget" \ --metric-name TotalDPU \ --namespace AWS/AuroraDSQL \ --statistic Sum \ --period 3600 \ --evaluation-periods 1 \ --datapoints-to-alarm 1 \ --threshold 13699 \ --comparison-operator GreaterThanThreshold \ --dimensions Name=ClusterId,Value=<your-cluster-id> \ --alarm-actions arn:aws:sns:<region>:<account-id>:dsql-cost-alerts \ --ok-actions arn:aws:sns:<region>:<account-id>:dsql-cost-alerts \ --treat-missing-data notBreaching この設定で、次のようなことができます。 データベース管理者や財務チームへのメールアラート コスト是正ワークフローのための AWS Lambda 関数の自動トリガー Amazon SNS サブスクリプションを通じたインシデント管理システムとの連携 Aurora DSQL のコストアラームを設定する際は、次のベストプラクティスを検討してください。 予算の 70% で警告アラーム、90% で重大アラームを設定する。 OK アクションを含め、コストが通常に戻ったときにチームへ通知する。 Datapoints to alarm を 3 評価期間中 2 に設定し、一時的なスパイクによる誤報を減らす。この方法は 1 時間のような短い評価期間に適しています。日次評価のような長い期間では、通常は 1 期間中 1 の設定が適しています。 マルチリージョンクラスターでは、リージョンごとのクラスターに個別のアラームを作成し、コストが発生したリージョンを特定できるようにする。 AWS CloudFormation でモニタリング用アラームをデプロイする アラーム関連のインフラストラクチャをコードとしてデプロイすれば、一貫性、再現性、バージョン管理を確保できます。 AWS CloudFormation には、必要なコンポーネントのネイティブリソースタイプとして AWS::CloudWatch::Alarm と AWS::SNS::Topic が用意されています。 CloudFormation テンプレート 次のテンプレートを dsql-cost-alarms.yaml として保存します。このテンプレートは、通知用の SNS トピックと、しきい値をパラメータ化した TotalDPU メトリクスの CloudWatch アラームを作成します。 # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 AWSTemplateFormatVersion: "2010-09-09" Description: > CloudWatch alarm for Aurora DSQL hourly DPU budget monitoring. Parameters: ClusterId: Type: String Description: Aurora DSQL Cluster ID to monitor AlarmThreshold: Type: Number Default: 13699 Description: Hourly DPU threshold (default = 80% of $100/month budget) NotificationEmail: Type: String Description: Email address for alarm notifications Resources: DSQLCostAlertTopic: Type: AWS::SNS::Topic Properties: TopicName: dsql-cost-alerts Subscription: - Protocol: email Endpoint: !Ref NotificationEmail DSQLHourlyDPUAlarm: Type: AWS::CloudWatch::Alarm Properties: AlarmName: DSQL-Hourly-DPU-Budget-Warning AlarmDescription: Alert when hourly DPU exceeds budget threshold MetricName: TotalDPU Namespace: AWS/AuroraDSQL Statistic: Sum Period: 3600 EvaluationPeriods: 1 DatapointsToAlarm: 1 Threshold: !Ref AlarmThreshold ComparisonOperator: GreaterThanThreshold TreatMissingData: notBreaching Dimensions: - Name: ClusterId Value: !Ref ClusterId AlarmActions: - !Ref DSQLCostAlertTopic OKActions: - !Ref DSQLCostAlertTopic Outputs: AlarmArn: Description: ARN of the CloudWatch alarm Value: !GetAtt DSQLHourlyDPUAlarm.Arn Export: Name: !Sub "${AWS::StackName}-AlarmArn" SNSTopicArn: Description: ARN of the SNS notification topic Value: !Ref DSQLCostAlertTopic Export: Name: !Sub "${AWS::StackName}-SNSTopicArn" テンプレートのデプロイ AWS CLI で CloudFormation スタックをデプロイします。 aws cloudformation deploy \ --template-file dsql-cost-alarms.yaml \ --stack-name dsql-cost-monitoring \ --parameter-overrides \ ClusterId=<your-cluster-id> \ AlarmThreshold=13699 \ NotificationEmail=your-team@example.com パラメータとリソースのプロパティは !Ref で結び付けます。たとえば Threshold: !Ref AlarmThreshold や AlarmActions: [!Ref DSQLCostAlertTopic] とすれば、同じテンプレートを環境ごとに異なるしきい値でデプロイできます。 StackSets によるマルチリージョンデプロイ マルチリージョンの Aurora DSQL クラスターを運用している組織では、 AWS CloudFormation StackSets を使って、1 つのテンプレートから複数のリージョンへモニタリングスタックを一貫した形でデプロイできます。モニタリング用インフラストラクチャの CloudFormation スタックを構成する際は、次のプラクティスをお勧めします。 モニタリング用インフラストラクチャをアプリケーションのリソースと分離し、ライフサイクルを独立して管理する。 クロススタック参照を使い、リソースの ARN (SNS トピックの ARN など) をスタック間で共有する。 しきい値をパラメータ化し、スタック全体を再デプロイせずに上限を更新できるようにする。 CloudFormation モジュールを使い、アラームの設定を再利用可能なモジュールとしてパッケージ化する。 AWS CloudFormation Guard を使い、Policy as Code でテンプレートを検証する。 Aurora DSQL のコスト管理のベストプラクティス DPU の推移をモニタリングする。 Aurora DSQL コンソールの Usage and cost パネルと CloudWatch を使って DPU 消費のパターンを把握し、アプリケーションのイベントやデプロイと関連付けます。 段階的なアラートを使う。 予算の 100% で 1 つのアラームを設定するのではなく、複数のしきい値 (70% で警告、90% で重大) を設定します。 開発には AWS 無料利用枠を使う。 毎月 100,000 DPU と 1 GiB のストレージが使える無料利用枠は、開発環境やテスト環境に最適です。 EXPLAIN ANALYZE VERBOSE でクエリのコストを分析する。 EXPLAIN ANALYZE VERBOSE を実行すると、ステートメント単位の DPU の見積もりを確認でき、各オペレーションに伴うコストを把握できます。この値はチューニングの目安として使い、請求レベルの正確な数値とはみなさないでください。正式なコストデータには CloudWatch メトリクスや請求レポートを使います。 Database Insights でリソースを多く使うクエリを特定する。 Amazon CloudWatch Database Insights は、すべての Aurora DSQL クラスターで追加料金なしで自動的に有効になっています。DSQL Active Session History (DASH) のメトリクス db.active_sessions.avg を待機イベント別や SQL ステートメント別に分析できるため、リソースを最も多く消費するクエリをすばやく特定し、負荷のスパイクでアラートを出せます。Database Insights でコストの高いクエリを見つけ、DPU メトリクスと EXPLAIN ANALYZE VERBOSE でコストへの影響を確認してください。 AWS Budgets と組み合わせる。 月初からの累計支出の追跡には AWS Budgets を、1 時間単位の運用アラートには CloudWatch を使います。本記事の 1 時間単位のアラームはスパイクをすばやく検知し、AWS Budgets は月初からの支出を予算と比較して追跡します。両方を組み合わせれば、2 つの観点をカバーできます。 クリーンアップ 今後の料金発生を避けるため、本記事の手順で作成したリソースを削除します。次の手順を実行してください。 CloudWatch アラームを削除します。 aws cloudwatch delete-alarms --alarm-names "DSQL-Hourly-DPU-Budget-Warning" または、CloudFormation スタック全体を削除して、アラーム、SNS トピック、サブスクリプションをまとめて削除します。 aws cloudformation delete-stack --stack-name dsql-cost-monitoring 注: CloudFormation スタックを削除すると Amazon SNS のメールサブスクリプションも削除されるため、削除後はサブスクライバーに通知が届かなくなります。 まとめ Aurora DSQL は料金が DPU に一本化されているためコスト管理がシンプルですが、予算を管理するには先回りしたモニタリングが欠かせません。Aurora DSQL コンソールに組み込まれた Usage and cost パネルと CloudWatch アラームを使えば、シングルリージョンでもマルチリージョンでも、Aurora DSQL のコスト全体を把握できます。 本記事では、次の内容を説明しました。 DPU メトリクスと請求額の直接の対応関係と、正確なコスト追跡のための Sum 統計の使い方 Aurora DSQL コンソールの Usage and cost パネルでの DPU 消費量と推定コストの確認 (ダッシュボードの設定は不要) 1 時間あたりの DPU 使用量に対する CloudWatch アラームの設定。適切な評価期間と SNS 通知を組み合わせ、特定の 1 時間が予算の 1 時間分を超えたときにチームへ通知します。 CloudFormation を使ったアラームスタック全体の Infrastructure as Code によるデプロイと、複数リージョンで Aurora DSQL クラスターを運用する場合の StackSets の活用 まずは CloudFormation テンプレートを Aurora DSQL クラスターに対してデプロイし、予算に合わせてアラームのしきい値を調整してください。また、DPU 消費を抑えるクエリ最適化の手法について Aurora DSQL のドキュメントも参照してください。組織全体で月初からのコストを管理するには、AWS Budgets の利用を検討してください。ご質問はコメント欄にお寄せください。 参考資料 Amazon Aurora DSQL の料金 Aurora DSQL での請求の仕組み Amazon CloudWatch を使用した Aurora DSQL のモニタリング Amazon CloudWatch でのアラームの使用 StackSets を使用したアカウントとリージョン全体でのスタックの管理 メトリクスを使用した数式 著者について Tejas Dubey Tejas は、 Tejas は AWS の Technical Account Manager です。エンタープライズのお客様が、回復力と安全性に優れ、AI の活用に備えたクラウドアーキテクチャを構築できるよう支援しています。新しい技術を実際のビジネス価値につなげることに情熱を注いでいます。仕事以外では、息子を追いかけたり、ピックルボールをしたり、最新のテクノロジーをいじったりして過ごしています。 Mike Gomez Mike は、 Mike は AWS の Enterprise Support Industry Leader です。旅行・ホスピタリティ、運輸、物流業界のお客様を対象に、業界を越えた取り組みを通じて、クラウドコストの管理、運用上の優秀性の強化、利用者への信頼性が高くシームレスな体験の提供を支援しています。 この記事は Kiro が翻訳を担当し、Solutions Architect の Kenta Nagasue がレビューしました。

動画

書籍