CloudFormation個人メモ：OAIを使用してCloudFrontからのアクセスを許可し、S3バケットを介して自分宛にメッセージを表示するプロセスをコード化してみた

## はじめに
まず、大前提として、ここから先は現在キャッチアップしているCloudFormationを使いながら、さまざまなコードを自分用に書いていきます。

:::note alert
**※補足事項**
***そのため、内容は完全に自分向けとなっています。***
:::

また、過去にTerraformを使って構築した環境を、CloudFormationで再現する形で進めています。

https://qiita.com/free-honda/items/c51a5cb34f4f67bf6b7e

このプラットフォーム上に自分専用の備忘録記録を積み重ねていく予定です。***あらかじめご了承いただければ幸いです。***

## この記事のゴール
この記事のゴールは、S3バケットにアップロードした`index.html`ファイルに、CloudFront経由でアクセスし、ブラウザで表示を確認することです。

![Screenshot 2025-01-25 at 7.44.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/d076a7a2-5a7d-75e2-aa6c-b5d3c3ae810f.png)

これは、早起きして朝から勉強を頑張っている自分へのエールを込めた内容になっています（笑）。

## 実際にコードで行っていること

- **S3バケットの作成**
  - 非公開設定で、静的ウェブホスティングを構成（`index.html`と`error.html`を設定）。

- **CloudFrontオリジンアクセスアイデンティティ (OAI) の作成**
  - CloudFrontがS3バケットに安全にアクセスできるようにするためのIDを作成。

- **S3バケットポリシーの設定**
  - OAIを通じたCloudFrontからのアクセスを許可。

- **CloudFrontディストリビューションの作成**
  - S3バケットをオリジンとしたCDNを構築。
  - HTTPSリダイレクトを設定。
  - クエリ・クッキーの転送を無効化。

### 注意点：HTMLファイルのアップロードは手動で対応
作成したテンプレートをCloudFormationで使用しようとしたところ、以下のエラーが発生しました。

```bash
Template format error: Unrecognized resource types: [AWS::S3::Object]
```

調べてみたところ、どうやらCloudFormationではAWS::S3::Objectリソースタイプがサポートされていないみたいです…

:::note warn
***正直、これが本当なのか少し自信がないのですが、少なくとも自分の調査では直接アップロードする方法は見つかりませんでした。***
:::

そのため、以下のような方法で対応するしかないのかなと思っています。***もし他に良い方法があれば教えてほしいところです…。***

https://zenn.dev/is0383kk/articles/bf31ded54cbcb5

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/using-cfn-cli-package.html

今回は、`index.html`をS3バケットに手動でアップロードし、それをCloudFront経由で配信する形で対応しました。

**アップロード後の画面**

![Screenshot 2025-01-25 at 7.37.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/57f1d254-042b-3274-1abe-8bfc1b2d32ae.png)

## 作ったコードについて

```test.yaml
AWSTemplateFormatVersion: "2010-09-09"
Resources:
  S3Bucket:
    Type: "AWS::S3::Bucket"
    Properties:
      BucketName: "my-cloudfront-bucket-tokyo"
      AccessControl: "Private"
      Tags:
        - Key: "Name"
          Value: "MyS3Bucket"
        - Key: "Environment"
          Value: "Production"
      WebsiteConfiguration:
        IndexDocument: "index.html"
        ErrorDocument: "error.html"

  S3BucketPolicy:
    Type: "AWS::S3::BucketPolicy"
    Properties:
      Bucket: !Ref S3Bucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              CanonicalUser: !GetAtt CloudFrontOAI.S3CanonicalUserId
            Action: "s3:GetObject"
            Resource: !Sub "${S3Bucket.Arn}/*"

  CloudFrontOAI:
    Type: "AWS::CloudFront::CloudFrontOriginAccessIdentity"
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: "OAI for S3 bucket"

  CloudFrontDistribution:
    Type: "AWS::CloudFront::Distribution"
    Properties:
      DistributionConfig:
        Enabled: true
        Comment: "CloudFront Distribution for S3 bucket in Tokyo region"
        DefaultRootObject: "index.html"
        Origins:
          - Id: "S3-my-cloudfront-bucket"
            DomainName: !GetAtt S3Bucket.RegionalDomainName
            S3OriginConfig:
              OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOAI}"
        DefaultCacheBehavior:
          TargetOriginId: "S3-my-cloudfront-bucket"
          ViewerProtocolPolicy: "redirect-to-https"
          AllowedMethods:
            - "GET"
            - "HEAD"
          CachedMethods:
            - "GET"
            - "HEAD"
          ForwardedValues:
            QueryString: false
            Cookies:
              Forward: "none"
        PriceClass: "PriceClass_100"
        Restrictions:
          GeoRestriction:
            RestrictionType: "none"
        ViewerCertificate:
          CloudFrontDefaultCertificate: true
      Tags:
        - Key: "Name"
          Value: "MyCloudFrontDistribution"
        - Key: "Environment"
          Value: "Production"
```

## まとめ
この記事は、自分用の備忘録としてまとめたものです。その点をご理解いただけると幸いです。

:::note info
***もし、この記事の内容が少しでも参考になれば嬉しく思います。***
:::

今後も同様の内容を継続して投稿していきますので、温かく見守っていただけるとありがたいです。

## おまけ：バケットポリシーメモ
S3バケットのポリシーは以下のようになっています。**このあたりはよく忘れてしまうので、自分用のメモとして残しておきます。**

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "CanonicalUser": "OAIのCanonicalUser ID"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-cloudfront-bucket-tokyo/*"
    }
  ]
}
```