😵💫
ECSでECRからイメージをPullできない!? S3エンドポイント制限で403にハマった話
はじめに
ECSタスクを起動したときに、ECRからイメージをPullできずタスクが失敗しました。
エラー内容は次のとおりです。
CannotPullContainerError: failed to copy: httpReadSeeker: failed open: unexpected status code 403 Forbidden
IAMロールやECRポリシーを確認しても問題なし。
しかしエラーは解消せず、原因が見えませんでした。
経緯
この環境では privateサブネットのDBからS3へデータを出力する用途 がありました。
そのため、インターネットを経由せずにS3へ接続するためにVPCエンドポイントを設定していました。
DB → S3 への出力はうまくいっていたのですが、思わぬところでECSタスクにも影響が出たのです。
現象
- ECSタスクのイメージPullだけが失敗
- 外部サーバーへのアクセスは成功
- 403 Forbidden が返るのはECR利用時のみ
原因
ここで重要なのは ECRは裏側でS3を使っている という点です。
ECRからイメージをPullする流れはこうです。
- ECS → ECR API にマニフェストをリクエスト
- ECR →
GetDownloadUrlForLayer
を返す(S3の署名付きURLを含む) - ECS → AWS管理のS3バケット(例:
prod-<region>-starport-layer-bucket
)からレイヤーを取得
つまり、ECSタスクが S3へアクセスする必要がある のです。
ところが、S3 VPCエンドポイントのポリシーを「自社バケットのみ許可」にしていたため、
ECRが利用する管理バケットへのアクセスが拒否され、403 Forbidden になっていました。
仕組みのポイント
- S3 VPCエンドポイントを作成すると、すべてのS3アクセスは必ずエンドポイント経由になります
- NAT Gatewayがあっても、S3通信はエンドポイントに吸い込まれる
- そのため、エンドポイントポリシーで許可されていないS3バケットにはアクセスできない
外部APIには繋がるのに、ECRのPullだけ403になるのはこのためです。
解決方法
S3 VPCエンドポイントポリシーに、ECRの管理バケットを許可すれば解決します。
{
"Version": "2008-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": [
"arn:aws:s3:::prod-ap-northeast-1-starport-layer-bucket/*"
]
}
]
}
バケット名はリージョンごとに異なります。形式は
prod-<region>-starport-layer-bucket
です。
学び
- ECRはS3を裏で使っている
- ECSタスクからのS3アクセスもVPCエンドポイント経由になる
- ポリシーを制限すると、ECRのPullすら失敗する
まとめ
ECSタスクのイメージPullで403が出たら、IAMやECRポリシーだけでなく
S3 VPCエンドポイントの制御 を疑うべきです。
「外部には繋がるのにECRだけ403」という現象は、ECRの仕組みを知らないとハマりやすい落とし穴です。
Discussion