何が起きているか
S3バケットを指すCloudFrontディストリビューションを設定し、アクセス方法として**Origin Access Control(OAC)**を選択したところ、すべてのリクエストがこの壁にぶつかるようになりました:
403 ERROR: The request could not be satisfied.
Request blocked. We can't connect to the server for this app or website at this time.
何も読み込まれません。バケットが公開状態のときはS3への直接アクセスは正常に動作するのに、CloudFrontは通過できません。
OACは2022年に古いOrigin Access Identity(OAI)に取って代わりました。より安全ですが、ほとんどのチュートリアルが省略するか誤って説明している特定のバケットポリシーが必要です。ポリシーがなければ、S3はすべてのCloudFrontリクエストを匿名として扱い、403を返します。それだけです。問題の全貌はそこにあります。
根本原因
OACがアタッチされると、CloudFrontはSigV4を使ってS3へのリクエストに署名します。S3には「この特定のCloudFrontディストリビューションからのリクエストの場合のみs3:GetObjectを許可する」と明示するバケットポリシーが必要です。ポリシーがなければアクセスできません——たとえCloudFront側でOACが正しく設定されていても。
これを引き起こす一般的なミス:
- OACはCloudFrontで設定されているが、バケットポリシーが更新されていない
- ポリシーがOACの条件ではなく、OAI(
arn:aws:iam::cloudfront:user/...)を参照したままになっている - パブリックアクセスのブロックが有効になっているが、CloudFrontアクセスを許可するポリシーがない
- ポリシーに誤ったCloudFrontディストリビューションARNが使用されている
ステップ1 — ディストリビューションがOACを使用していることを確認する
CloudFrontコンソールを開く → ディストリビューションを選択 → オリジンタブ → S3オリジンをクリック → オリジンアクセスを確認します。OAC名とともに*Origin access control settings(推奨)*が表示されているはずです。「パブリック」やOAIではいけません。
CLIで確認する場合:
aws cloudfront get-distribution-config --id YOUR_DISTRIBUTION_ID \
--query 'DistributionConfig.Origins.Items[0].S3OriginConfig'
OriginAccessIdentityが空で、OACがOriginAccessControlIdの下に表示されていれば、OACが有効です。
ステップ2 — 現在のバケットポリシーを確認する
aws s3api get-bucket-policy --bucket YOUR_BUCKET_NAME --query Policy --output text | python3 -m json.tool
出力が空ですか?それが答えです。arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ...のようなプリンシパルが表示されている場合、ポリシーはまだOAIを指しています——OACでは機能しません。
ステップ3 — 正しいOACバケットポリシーを適用する
修正方法は、CloudFrontサービスプリンシパルにs3:GetObjectを許可し、特定のディストリビューションに限定するバケットポリシーを設定することです。
まず、ディストリビューションARNを取得します:
aws cloudfront get-distribution --id YOUR_DISTRIBUTION_ID \
--query 'Distribution.ARN' --output text
次のような形式になります:arn:aws:cloudfront::123456789012:distribution/EDFDVBD6EXAMPLE
ポリシーファイルを作成します:
cat > bucket-policy.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontOAC",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/EDFDVBD6EXAMPLE"
}
}
}
]
}
EOF
適用します:
aws s3api put-bucket-policy \
--bucket YOUR_BUCKET_NAME \
--policy file://bucket-policy.json
ステップ4 — パブリックアクセスのブロックを有効のままにする
403を「修正」するためにパブリックアクセスのブロックをオフにしないでください。それは間違った対処法です。OACが存在する理由はまさにそこにあります——4つのパブリックアクセスブロックフラグをすべてONにしたまま、CloudFrontがコンテンツを配信できるようにするためです。
確認:
aws s3api get-public-access-block --bucket YOUR_BUCKET_NAME
4つのフラグはすべてtrueになっているはずです。すでにオフにしてしまった場合は、元に戻してください——OACポリシーがパブリックアクセスなしでアクセスを処理します。
ステップ5 — CloudFrontキャッシュを無効化する
CloudFrontが403レスポンスをキャッシュしている可能性があります。強制的にリフレッシュします:
aws cloudfront create-invalidation \
--distribution-id YOUR_DISTRIBUTION_ID \
--paths "/*"
ステータスを確認します(通常30〜60秒で完了します):
aws cloudfront list-invalidations \
--distribution-id YOUR_DISTRIBUTION_ID \
--query 'InvalidationList.Items[0].Status'
修正を確認する
curlでレスポンスヘッダーを確認します:
curl -I https://YOUR_CLOUDFRONT_DOMAIN/your-file.html
初回アクセスではx-cache: Miss from cloudfrontとともにHTTP/2 200が表示され、その後のリクエストではHit from cloudfrontが表示されるはずです。
存在しないパスにもアクセスしてみてください。S3は403ではなく404を返すはずです。存在しないファイルに対して404が返ることで、ポリシーが正しく機能していること——そして過度に許可されていないことが確認できます。
CLIよりコンソール操作が好みですか?コンソールのショートカットを使う
AWSコンソールには、手動でJSONを作成する手間を省く組み込みショートカットがあります。CloudFrontディストリビューション → オリジン → S3オリジンを編集 → OACセクションまでスクロール → **「ポリシーをコピー」**をクリックします。次にS3を開いて → アクセス許可 → バケットポリシー → 貼り付けて保存します。AWSがディストリビューションに対して正確なポリシーを自動的に生成してくれます。
確認すべきエッジケース
- マルチリージョン構成:S3バケットが
ap-southeast-1、CloudFrontエッジがus-east-1の場合、OACの署名動作が*リクエストに署名する(推奨)*に設定されていることを確認してください——「署名しない」ではいけません。 - SSE-KMS暗号化オブジェクト:カスタマー管理のKMSキーには追加の手順が必要です。CloudFrontにはKMSキーポリシーに
kms:Decryptが必要です。OACはこれをサポートしていますが、明示的に追加する必要があります。 - 残存するOAIステートメント:古いOAIポリシーがまだ残っている場合は削除してください。同じポリシーにOAIとOACのステートメントが両方あっても動作は壊れませんが、チームの全員——将来の自分自身も含めて——を混乱させることになります。

