EC2 インスタンスから S3 の署名付き URL を VPC エンドポイント経由で利用してみた
はじめに
プライベートサブネットに配置した EC2 インスタンスから、S3 バケット内のオブジェクトを署名付き URL で取得したいケースがありました。
署名付き URL はインターネット経由で利用するイメージがありますが、今回は NAT Gateway を使わない構成を前提としていたため、S3 Gateway VPC Endpoint 経由でも利用できるのかを検証しました。
結果として、プライベートサブネットの EC2 インスタンスから S3 Gateway VPC Endpoint 経由で署名付き URL を利用し、S3 バケット内のオブジェクトを取得できることを確認しました。
あわせて、取得側の EC2 インスタンスが署名付き URL でダウンロードするだけであれば、その EC2 インスタンス自体に S3 の IAM 権限は不要であることも確認しました。
先に結論
今回の検証では、プライベートサブネットの EC2 インスタンスから S3 Gateway VPC Endpoint 経由で、S3 バケット内のオブジェクトを署名付き URL で取得できることを確認しました。
ポイントは以下です。
- 取得側の EC2 インスタンスに S3 の IAM 権限は不要
- 署名付き URL を発行した IAM プリンシパルの権限で評価される
aws:SourceVpceを使うことで、特定の VPC エンドポイント経由のアクセスに制限できる
今回やったこと
CloudShell で S3 バケットを作成し、テストファイルをアップロード後、対象オブジェクトの署名付き URL を発行しました。
その URL をプライベートサブネットの EC2 インスタンスに渡し、curl でファイルを取得できるかを確認しました。
また、aws:SourceVpce 条件付きのバケットポリシーを設定し、指定した VPC エンドポイント経由のアクセスのみ成功することも確認しました。
CloudShell でバケットを作成してテストファイルをアップロードする
まず、CloudShell で検証用の S3 バケットを作成します。
バケット名は S3 全体で一意である必要があるため、実際に試す場合は適宜変更してください。
BUCKET="presign-test-1234567890"
KEY="sample.txt"
aws s3 mb s3://$BUCKET
続いて、テストファイルを作成して S3 バケットにアップロードします。
cat > $KEY <<EOF
hello from cloudshell
this is a test file for presigned url
created at: $(date)
EOF
aws s3 cp $KEY s3://$BUCKET/$KEY
アップロードしたオブジェクトに対して、署名付き URL を発行します。
今回は有効期限を 1 時間にしています。
URL=$(aws s3 presign s3://$BUCKET/$KEY --expires-in 3600)
echo "$URL"
CloudShell からアクセスし、署名付き URL で取得できることを確認しました。
curl -fL "$URL"
実行すると、S3 バケットにアップロードしたファイルの内容が表示されます。
hello from cloudshell
this is a test file for presigned url
created at: Mon Mar 23 06:18:41 AM UTC 2026
EC2 インスタンスから署名付き URL で取得する
次に、CloudShell で発行した署名付き URL をプライベートサブネットの EC2 インスタンスに渡し、curl で取得します。
URL='CloudShellで出力した署名付き URL'
curl -vfL "$URL" -o ec2-downloaded-sample.txt
cat ec2-downloaded-sample.txt
実行すると 200 OK が返り、アップロードしたファイルの内容を取得できました。
hello from cloudshell
this is a test file for presigned url
created at: Mon Mar 23 06:18:41 AM UTC 2026
これにより、プライベートサブネットの EC2 インスタンスからでも、署名付き URL を使って S3 バケット内のオブジェクトを取得できることが確認できました。
aws:SourceVpce で VPC エンドポイント経由だけを許可する
次に、アクセス経路をより明確にするため、aws:SourceVpce 条件付きのバケットポリシーを設定しました。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyGetObjectUnlessFromSpecificVPCE",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::presign-test-1234567890/*",
"Condition": {
"StringNotEquals": {
"aws:SourceVpce": "vpce-xxxxxxxxxxxxxxxxx"
}
}
}
]
}
このポリシーでは、指定した VPC エンドポイント経由ではない GetObject を拒否します。
この状態で確認すると、以下の挙動になりました。
- CloudShell からのアクセス
失敗 - プライベートサブネットの EC2 インスタンスからのアクセス
成功
つまり、署名付き URL 自体は同じでも、aws:SourceVpce 条件に一致する EC2 インスタンスからは取得できることを確認できました。
なぜ VPC エンドポイント経由でも署名付き URL を利用できるのか
今回のポイントは、認証・認可と通信経路を分けて考えることです。
署名付き URL の役割
署名付き URL は、あらかじめ署名された S3 リクエストです。
S3 は、取得元 EC2 インスタンスの IAM ロールではなく、URL に含まれる署名情報をもとにリクエストを評価します。
主に評価されるのは、以下のような点です。
- URL の署名が有効か
- 有効期限内か
- 署名付き URL を発行した IAM プリンシパルが、対象オブジェクトにアクセスできるか
- バケットポリシーなどで拒否されていないか
そのため、EC2 インスタンスが curl で署名付き URL にアクセスするだけであれば、取得側 EC2 インスタンスの IAM ロールに S3 権限は不要です。
VPC エンドポイントの役割
一方、S3 Gateway VPC Endpoint は、VPC から S3 へ到達するための通信経路を提供する仕組みです。
主な役割は以下です。
- VPC 内から S3 への通信をルーティングする
- NAT Gateway や Internet Gateway を経由せずに S3 に到達させる
aws:SourceVpceなどの条件キーで、アクセス元の経路を判定できるようにする
つまり、VPC エンドポイントは通信経路を制御するための仕組みであり、署名付き URL を使う取得側 EC2 インスタンスに対して、追加の S3 IAM 権限を要求するものではありません。
まとめ
整理すると、今回の構成では以下のように役割が分かれます。
- 署名付き URL
- S3 リクエストの署名と、署名者の権限に基づくアクセス
- S3 Gateway VPC Endpoint
- VPC から S3 への通信経路
aws:SourceVpceによる経路ベースの制御
このため、インターネット経由でも VPC エンドポイント経由でも、署名付き URL を使ってダウンロードするだけであれば、取得側 EC2 インスタンスに追加の S3 IAM 権限は不要です。
ただし、バケットポリシーや VPC エンドポイントポリシーで明示的に拒否されている場合は、署名付き URL であってもアクセスは失敗します。









