😵‍💫

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する流れはこうです。

  1. ECS → ECR API にマニフェストをリクエスト
  2. ECR → GetDownloadUrlForLayer を返す(S3の署名付きURLを含む)
  3. 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の仕組みを知らないとハマりやすい落とし穴です。

CareNet Engineers

Discussion