こんにちは、エキサイト株式会社の平石です。
エキサイトホールディングス Advent Calendar 2024のシリーズ2, 19日目を担当いたします。
今回はAWS上のECSコンテナとBedrockの間のPrivateLinkを確立する方法をご紹介します。
AWSリソースの作成にはTerraformを使います。
はじめに
Amazon Bedrockは、AWS上で生成AIを利用できるようにするフルマネージドサービスです。
既存のモデルを容易に利用することもできますし、用途やデータに合わせてカスタマイズすることも可能です。
aws.amazon.com
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 = ["*"]
}
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
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を利用する場合には設定すると良いでしょう。
参考文献