Cloudfront＋S3の構築でハマったこと

AWSで、CloudFrontとS3を組み合わせてWebコンテンツを配信しようとしたときに、思わぬところでハマったので、過去につまづいた部分も含めてまとめてみました。

# 1. CloudFrontからS3へアクセスできない

## 🛑 発生した問題

CloudFrontのオリジンにS3を設定したのに、以下のような403エラーが出てアクセスできない。
![スクリーンショット 2025-03-26 21.00.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383236/08158ae0-385a-4768-a16e-86d0d62bf06f.png)


または、ブラウザの開発ツールで `No Access-Control-Allow-Origin`というエラーが表示される。

## ✅ 解決策

CloudFrontからS3へアクセスするには、**署名付きURL**か、**OAC**（Origin Access Control）/ **OAI**（Origin Access Identity）の設定を行う必要があります。

### 【解決方法①】OACを使う（推奨）

https://aws.amazon.com/jp/blogs/news/amazon-cloudfront-introduces-origin-access-control-oac/

**1.CloudFrontのオリジンにOACを設定**

- CloudFrontの「オリジン」からS3を選択
- 「オリジンアクセス」で「Origin access control settings (recommended)」を選択
    - 新規の場合は「Create new OAC」で作成する

![スクリーンショット 2025-03-25 18.13.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383236/9504648d-5ac6-4f31-b116-cc6fb74542c2.png)


**2.S3 のバケットポリシーを設定**
※値は適宜変更してください。

``` json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::your-bucket-name/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::your-account-id:distribution/your-distribution-id"
        }
      }
    }
  ]
}
```


### 【解決方法②】OAI を使う（古い方法）

CloudFront側でOAI（Origin Access Identity）を作成し、S3のバケットポリシーでOAIにアクセス許可を付与します。

![スクリーンショット 2025-03-25 18.15.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383236/0b7307d0-a830-4674-ba16-4e2433068caa.png)

::: note info
OACの方が新しく、よりセキュアなので推奨されています。
:::


### 🔑 署名付きURLとOACの使い分け
CloudFrontでS3にあるファイルを配信する場合、「署名付きURL」と「OAC」は目的によって使い分ける必要があります。
簡単にまとめると、

|特徴|署名付きURL|OAC|
|---|---|---|
|主な用途|コンテンツを一部の人だけに制限したいとき（有料ユーザー向けなど）|CloudFront経由だけにS3アクセスを制限したいとき|
|利用方法|URLにトークン（署名）を付ける|CloudFrontの設定＋バケットポリシーで制御|
|URL単位の制御|できる（細かいアクセス制御が可能)|できない（URL単位では不可)|
|実装の手間|やや複雑（URL発行処理が必要)|シンプル（CloudFront側の設定のみでOK）|

使い分けの例としては、
- 会員限定の動画や画像を配信 → **署名付きURL**
- 一般公開の静的ファイル（JS/CSS/画像）を安全に配信 → **OAC**

などで使い分けるといいかもしれません。

# 2. キャッシュが効かず更新されない

## 🛑 発生した問題

S3に新しいファイルをアップロードしたのに、CloudFrontでは古いバージョンのファイルが表示される。

## ✅ 解決策

この場合は、CloudFrontのキャッシュが原因である可能性が高いので、以下手順を実施します。

### 【解決方法①】 キャッシュの無効化（無効化 API）

CloudFrontのInvalidation機能を使ってキャッシュを削除。

```
aws cloudfront create-invalidation --distribution-id YOUR_DISTRIBUTION_ID --paths "/*"
```
※ パスを /* にすると全キャッシュ削除になります。
特定のパスだけキャッシュを無効化することも可能です。

### 【解決方法②】 バージョニング戦略を導入

キャッシュ無効化APIを毎回使うのはコストがかかるため、 ファイル名にバージョン情報を含める方法が推奨されます。
```
<script src="/js/app-v1.2.3.js"></script>
```
新しいバージョンをデプロイするたびに v1.2.3 の部分を更新すれば、CloudFront のキャッシュを回避することができます。

# 3. CORSエラーが発生する
## 🛑 発生した問題
フロントエンド（別ドメイン）から、S3にあるリソースにアクセスしようとすると、以下のようなCORSエラーが出る。

```
Access to XMLHttpRequest at 'https://your-bucket.s3.amazonaws.com/file.png' from origin 'https://your-site.com' has been blocked by CORS policy.
```

## ✅ 解決策

S3バケットのCORS設定を適切に設定します。

**1.S3のCORS設定を追加**
>バケット → アクセス許可 → Cross-Origin Resource Sharing (CORS)

![スクリーンショット 2025-03-25 17.47.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/383236/1e971bef-99ba-45ca-ad60-9c807e4a575c.png)


```
<CORSConfiguration>
    <CORSRule>
        <AllowedOrigin>https://your-site.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>
```

**2.CloudFrontのCORS設定を確認**

- Behavior設定の「Cache policy」 で、「CORS-S3Origin」などを選択
- HTTPヘッダー「Access-Control-Allow-Origin」を適切に設定

# 4. x-amz-security-token エラーでOACが機能しない

## 🛑 発生した問題

CloudFrontでOACを有効化したのに、`x-amz-security-token`に関するエラーが出る。

## ✅ 解決策

1.CloudFrontのオリジンヘッダーで、`Authorization`を無効化（削除）


2.OACの設定を見直し、S3のバケットポリシーが正しいか確認

3.必要ならCloudFrontの署名付きURLも試してみる

# まとめ
今回は、CloudFront+S3の構築時にハマった問題と解決策をご紹介しました。
特に OAC の設定、キャッシュ管理、CORS の設定はつまずきやすいポイントなので、事前に概念の理解をしておくとスムーズに設定できるかと思います！