こんにちは、エキサイト株式会社の平石です。
エキサイトホールディングス Advent Calendar 2024のシリーズ2, 19日目を担当いたします。
今回はAWS上のECSコンテナとBedrockの間のPrivateLinkを確立する方法をご紹介します。
AWSリソースの作成にはTerraformを使います。
はじめに
Amazon Bedrockとは
Amazon Bedrockは、AWS上で生成AIを利用できるようにするフルマネージドサービスです。
既存のモデルを容易に利用することもできますし、用途やデータに合わせてカスタマイズすることも可能です。
PrivateLinkとは
Amazon BedrockはVPC上になく、ECSコンテナ環境で動作しているアプリケーションからBedrcokを利用する際にはNAT Gatewayを利用するなどしてインターネットを経由する必要があります。
しかし、インターネットを経由するとセキュリティの問題が生じます。
PrivateLinkは利用するAWSサービスがVPC上にあるかのように接続するための方法で、インターネットを経由しないプライベートな接続が可能になります。
PrivateLinkはVPCにアタッチするVPCエンドポイントというコンポーネントと接続先のAWSサービスを結びつけることで構築します。
環境
Terraform 1.10.3で動作確認をしています。
前提条件
AWSアカウントの作成、Terraformの環境構築、ECSコンテナのデプロイ、Bedrockのモデルへのアクセス許可は完了していることを前提としています。
実装
Security GroupとIAMポリシーを作成する
まずは、VPC エンドポイントにアタッチするSecurity Groupを作成します。
./vpc_endpoint/bedrock/main.tf
variable "vpc" { type = object({ vpc_id = string private_subnet_ids = list(string) }) } variable "trusted_security_group_id" { type = string } module "security_group" { source = "terraform-aws-modules/security-group/aws" version = "5.1.0" name = "bedrock-vpce-sg" description = "Security group for bedrock-vpce" vpc_id = var.vpc.vpc_id ingress_with_source_security_group_id = [ { from_port = 443 to_port = 443 protocol = "tcp" source_security_group_id = var.trusted_security_group_id } ] }
設定したSecurity GroupからのTCPプロトコルによる443ポートへの通信のみ許可します。
変数trusted_security_group_id
には、ECSにアタッチしたSecurity GroupのIDを渡します。
次に、VPCエンドポイントにアタッチするポリシードキュメントを作成します。
./vpc_endpoint/bedrock/main.tf
variable "trusted_role_arns" { type = list(string) } ........ data "aws_iam_policy_document" "bedrock_access_policy" { statement { actions = [ "bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream", ] effect = "Allow" resources = [ "arn:aws:bedrock:ap-northeast-1::foundation-model/anthropic.claude-*" ] principals { identifiers = var.trusted_role_arns type = "AWS" } } }
このポリシードキュメントでは、VPC エンドポイントにBedrockのInvokeModel
とInvokeModelWithResponseStream
を許可します。
Bedrockのモデルにアクセスして、生成AIからのレスポンスを得るためにはこのポリシーを設定すれば十分でしょう。
今回は、AnthropicのClaude
というモデルにアクセスできるようにしています。
VPC エンドポイントを作成する
これまでに作成したSecurity Groupやポリシーを利用してVPCエンドポイントを作成します。
./vpc_endpoint/bedrock/main.tf
resource "aws_vpc_endpoint" "bedrock_vpc_endpoint" { service_name = "com.amazonaws.ap-northeast-1.bedrock-runtime" // ① vpc_id = var.vpc.vpc_id vpc_endpoint_type = "Interface" // ② subnet_ids = var.vpc.private_subnet_ids policy = data.aws_iam_policy_document.bedrock_claude_policy.json // ③ security_group_ids = [module.security_group.security_group_id] // ④ private_dns_enabled = true // ⑤ tags = { Name = "bedrock-vpce" } } output "bedrock_vpc_endpoint_id" { value = aws_vpc_endpoint.bedrock_vpc_endpoint.id }
①では、VPC エンドポイントでVPCとPrivateLinkを確立するサービスを設定します。今回は東京リージョン(ap-northeast-1)のBedrockを設定しています。
②では、VPC エンドポイントのタイプを設定します。VPC エンドポイントのタイプには主にGateway
とInterface
があります。
Gateway エンドポイントは無料で利用できますが、現在のところAmazon S3またはDynamoDBとの接続しかサポートされていません。
今回は、Bedrockとの接続を確立するためInterface エンドポイントに設定しています。
③, ④では、上で作成したSecurity Groupとポリシーをアタッチしています。
⑤では、指定したVPCにプライベートホストゾーンを関連付けるかどうかを設定します。
VPC内のサービスが自動でVPC エンドポイントを利用するために必要なため、true
に設定しましょう。
ECSタスクのロールを変更
次にECSタスクのロールにアタッチされているポリシーを変更します。
./ecs/xxxxx/main.tf
variable "bedrock_vpc_endpoint_id" { type = string } data "aws_iam_policy_document" "iam_policy_document" { statement { actions = [ 〜〜 略 〜〜 "ec2:CreateNetworkInterface", "ec2:DescribeNetworkInterfaces", "ec2:DeleteNetworkInterface", "ec2:*VpcEndpoint*" ] resources = ["*"] } // BedrockへのアクセスをVPC エンドポイント経由のみに制限 statement { effect = "Allow" actions = [ "bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream" ] sid = "AllowTask" resources = ["*"] condition { test = "ForAnyValue:StringEquals" values = [var.bedrock_vpc_endpoint_id] variable = "aws:SourceVpce" } } }
前半部分では、ECSタスクからVPCエンドポイントを利用できるようなstatementを追加しています。
また、後半部分ではECSタスクからBedrockへのアクセスをVPC エンドポイント経由のみに制限し、意図せぬインターネットへのアクセスが発生しないようにしています。
ただし、このstatementはあくまでVPCエンドポイントからBedrockにアクセスできるようにしているだけなので、他に無条件でBedrockにアクセスを許可するようなstatementを記述している場合には削除しておきましょう。
作成した部品を組み合わせる
最後にこれまで記述したVPC エンドポイントを実際に作成します。
./main.tf
// Bedrockに接続するためのVPCエンドポイント module "bedrock_vpc_endpoint" { source = "./vpc_endpoint/bedrock" vpc = { vpc_id = <使用するVPCのIDを指定> name = <使用するVPCの名前を指定> private_subnet_ids = <使用するVPC内のサブネットを指定(基本的にはECSが存在するサブネット)> } trusted_role_arns = [ <ECS タスクロールのarn> ] trusted_security_group_id = <ECSに設定したSecurity GroupのID> }
終わりに
今回はECSコンテナとBedrockの間のPrivateLinkを確立する方法をご紹介しました。
インターネットを経由しないことでセキュリティ強化につながるため、Bedrockを利用する場合には設定すると良いでしょう。