S3 + CloudFront + Route53 でウェブサイトを公開するパターン
構成のパターン
S3をウェブサイトのホスティング先にする場合、S3バケットを静的ウェブサイトとして設定するか否かでパターンが分かれる。S3バケットを静的ウェブサイトとして設定すると、S3内のコンテンツにWebエンドポイントからアクセスできるようになる。
あえて静的ウェブサイト設定を用いるモチベーションとなるのは、以下の2つ。
リダイレクトを扱いたい場合
Amazon S3 の静的ウェブサイト設定では、オブジェクトレベル/バケットレベルのリダイレクトをサポートする https://example.com/hoge, https://example.com/hoge/, https://example.com/hoge/index.html で全て同じページにアクセスさせることが可能
エラーページの扱いを楽にしたい場合
S3の静的ウェブサイト設定
リダイレクトのことを考えると、S3 の静的ウェブサイト機能を利用したい。
静的ウェブサイト設定をONにする
バケットの「プロパティ」から設定を編集できる。ホスティングタイプは「静的ウェブサイトをホストする」にする。
https://gyazo.com/b91137bb425f6801d88e3ef08c6f447f
バケットポリシーを設定する
バケットを静的ウェブサイトとして設定する場合、バケットをパブリック読み取りアクセス可能にする必要がある。以下の2つの手順が必要。
パブリックアクセスブロック設定を無効にする
パブリック読み取りアクセス可能にするバケットポリシーを記述する
これらはどちらもバケットの「アクセス許可」から設定を編集できる。前者は単に「パブリックアクセスを全てブロック」からチェックを外して保存すれば良い。後者は、以下のようなバケットポリシーを設定する。
code:json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::自分のバケット名/*",
}
]
}
ただし、このままだと S3 のWebエンドポイントに直アクセスが可能となってしまう。
code:json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::自分のバケット名/*",
"Condition": {
"StringEquals": {
"aws:Referer": "推測されにくい文字列"
}
}
}
]
}
DNSの設定
HTTPS 通信のために、AWS Certificate Manager で証明書を発行する。パブリック SSL/TLS 証明書は無料で発行できる。ただし、CloudFront で利用するためには、米国東部 (バージニア北部) リージョン (us-east-1) で証明書をリクエストする必要がある。 Route53 の場合
TODO
Cloudflare の場合
Google Domains や Cloudflare 等の外部のレジストラを利用している場合には、CNAME 検証が利用できる。
発行されたCNAMEの名前と値を確認し、
https://gyazo.com/051214faf2aa841edc1fdf3ce8a25aa5
Clouflare 側で CNAME レコードを登録する。この時、プロキシはオフにしたほうが良さそうだった。
https://gyazo.com/f78fbb7bc3544c681d586a4a94bbf7fe
CloudFront の設定
新しいディストリビューションを、以下のような設定で作成する。
オリジンドメイン: Webエンドポイントを設定する。S3バケットを指定しないよう注意。
カスタムヘッダーを追加: Referer が必要なら追加する
ビューワープロトコルポリシー: Redirect HTTP to HTTPS
HTTPでアクセスされても、HTTPSへリダイレクトするようになる。
代替ドメイン名: アクセスさせるドメイン名を入力する (example.com, www.example.com など)
カスタムSSL証明書: ACMで発行した証明書を利用する
Route53 の場合
TODO
Cloudfrare の場合
CloudFront への疎通のために、CNAME を設定する。
Type: CNAME
Name: ドメイン名
Target: CloudFront のディストリビューションドメイン
AWSコンソール上の「一般」「詳細」「ディストリビューションドメイン名」から確認できる
example.com だけでなく、www.example.com のようなサブドメインからもアクセスさせたい場合は、Name を www.example.com にして、もう一つ登録する。
これで、登録したドメイン名で S3 へ疎通できるようになる。
デプロイ自動化
GitHub Actions は OpenID Connect をサポートしている。パスワードやアクセスキーのようなシークレットを直接 GitHub 側に管理させると、シークレットの更新や漏洩リスクの考慮が必要になる。OIDC ではシークレットをハードコードするのではなく、必要に応じて都度短時間利用可能なアクセストークンを発行する。 https://gyazo.com/d91faa7c6ecce288baf16265924eb50c
AWS で ID プロバイダを作成する
まずは、GitHub の OIDC プロバイダを IAM 上で設定する。設定項目は以下の通り。 プロバイダのタイプ: OpenID Connect
対象者: sts.amazonaws.com
IAM ポリシーの作成
OIDC プロバイダに最終的に割り当てることになる IAM ポリシーを作成する。以下のような感じ。ListAllMyBuckets と GetBucketLocation は、CLI からの利用でない場合不要かもしれない。
適当な名前をつけて保存しておく。
code:json
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "s3:ListAllMyBuckets",
"Effect": "Allow",
"Resource": "arn:aws:s3:::*"
},
{
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::バケット名"
},
{
"Action": [
"s3:DeleteObject",
"s3:GetObject",
"s3:PutObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::バケット名/*"
}
]
}
IAM ロールの作成と割り当て
OIDC プロバイダに IAM ロールを割り当てる。
信頼されたエンティティタイプ: ウェブアイデンティティ
ウェブアイデンティティ:
アイデンティティプロバイダー: token.actions.githubusercontent.com
Audience: sts.amazonaws.com
GitHub 組織: GitHubユーザー名
GitHub リポジトリ: リポジトリ名
許可ポリシー: 先ほど作成したポリシー
GitHub Actions Workflow の作成
以下の三つは GitHub Actions の secret として設定する
AWS_ACCOUNT_ID
AWS_IAM_ROLE
AWS_BUCKET_NAME
以下のような yaml を記述する。
code:yaml
name: Deploy
on:
push:
branches:
- main
env:
AWS_REGION: ap-northeast-1
AWS_ROLE_ARN: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_IAM_ROLE }}
permissions:
id-token: write # JWTのリクエストのためにwriteにする
contents: read # acionts/checkoutのためにreadにする
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Git clone the repository
uses: actions/checkout@v4
- name: Configure aws credentials
uses: aws-actions/configure-aws-credentials@v3
with:
role-to-assume: ${{ env.AWS_ROLE_ARN }}
role-session-name: セッション名
aws-region: ${{ env.AWS_REGION }}
- name: Deploy to S3
run:
aws s3 sync --delete ./src/ s3://${{ secrets.AWS_BUCKET_NAME }}/
補足: CloudFront のキャッシュを都度削除する
以下を参考にすると良い