最近、サービスインフラのセキュリティやコストを最適化する過程で、プライベートサブネットに配置されたアプリケーションからS3へのアクセス方法を見直しました。これまでのアクセスはインターネット(NAT Gateway)経由でしたが、ゲートウェイ型VPCエンドポイントを導入することで、より安全かつコスト効率的なプライベートアクセスを実現しました。
ディレクトリ構成
Terraformのディレクトリ構成は、モジュール化された構造をとっており、それぞれの環境(dev, stg, prod)ごとに設定を分けています。
modules
ディレクトリに、プロジェクトで使用されるTerraformのモジュール(VPCエンドポイント、ルートテーブルなど)を格納しています。
-- terraform-project/
-- environments/
-- dev/
-- backend.tf
-- main.tf
-- stg/
-- backend.tf
-- main.tf
-- prod/
-- backend.tf
-- main.tf
-- modules/
-- vpc_endpoint/
-- main.tf
-- variables.tf
-- outputs.tf
-- provider.tf
-- README.md
-- route_table/
-- main.tf
-- variables.tf
-- outputs.tf
-- provider.tf
-- README.md
-- ...other…
-- docs/
-- architecrture.drowio
-- architecrture.png
実装
エンドポイントの設定
まず、modules/vpc_endpoint/main.tf
にVPCエンドポイントの設定を記述します。
data "aws_ssm_parameter" "app_vpc_id" {
name = "/vpc/id/app"
}
resource "aws_vpc_endpoint" "s3" {
vpc_id = data.aws_ssm_parameter.app_vpc_id.value
service_name = "com.amazonaws.ap-northeast-1.s3"
route_table_ids = [var.route_table_app_endpoint_id]
vpc_endpoint_type = "Gateway"
policy = <<POLICY
{
"Version": "2008-10-17",
"Statement": [
{
"Action": "*",
"Effect": "Allow",
"Resource": "*",
"Principal": "*"
}
]
}
POLICY
tags = {
Name = "app-vpce-s3"
}
}
-
VPC IDの取得
vpc_id
には、S3へのアクセス元となるアプリケーションが配置されているVPCのIDを指定します。今回はVPCのIDはSSMパラメータストアから取得しています。該当のVPCがTerraform導入以前に手動で作成されたものであるため、直接の変数としての管理ではなく、SSMからの取得を選択しました。 -
ルートテーブルの指定
route_table_ids
には、作成するVPCエンドポイントと関連付けるルートテーブルのIDを指定します。このルートテーブルはTerraformで既に管理下にあるため、変数を介してIDを読み込む形となります。
variable "route_table_app_endpoint_id" {
description = "The ID of the route table"
type = string
}
- エンドポイントポリシー
エンドポイントポリシーは、エンドポイントを経由したS3へのアクセスを制御するためのツールです。ポリシーを使用して、特定のバケットや特定のアクションにのみアクセスを許可するなど、細かいアクセス制御を実施できます。
以下は、エンドポイントポリシーを使って特定のS3バケット(my-allowed-bucket
)へのGETアクションのみを許可する例です。
policy = <<POLICY
{
"Version": "2008-10-17",
"Statement": [
{
"Action": "s3:GetObject",
"Effect": "Allow",
"Resource": "arn:aws:s3:::my-allowed-bucket/*",
"Principal": "*"
},
{
"Action": "s3:*",
"Effect": "Deny",
"Resource": "arn:aws:s3:::my-allowed-bucket/*",
"Principal": "*",
"Condition": {
"StringNotEquals": {
"s3:action": "s3:GetObject"
}
}
}
]
}
POLICY
my-allowed-bucket
バケットに対するs3:GetObject
アクションを許可しています。これにより、このバケット内のオブジェクトを読み取ることが可能です。また、同じバケットに対して、s3:GetObject
アクション以外の全てのアクションを拒否しています。これにより、オブジェクトの追加や削除など、その他の操作はできません。
- タグ付け
タグName = "app-vpce-s3"
は、リソースを管理する際の識別やフィルタリングのために役立ちます。特に大規模な環境や複数のエンドポイントを管理する場合には、適切な命名規則とタグ付けが重要となります。
これでNAT Gateway経由のコストやオーバーヘッドを回避しながら、プライベートなアクセス経路でS3に接続することができます。