ウェブサイトを HTTPS + CloudFront + S3 の環境に移行したのでその振り返り

先日、Apacheで配信していたWebサイトをS3+CloudFrontの環境に移行しました。そのときにやったことを備忘録としてまとめました。
個人的にハマって悩んだところや大事だなと思ったところは太字にしています。

0. 前提条件

  • 一通り構成を組んだ後でのテストでは、キャッシュがしぶとくてコンテンツ更新後の状況が再現できないことがあるので、Invalidationしまくったり、ブラウザキャッシュを削除しまくったりする必要がある。
  • 適当なテストドメインを用意できると良い。たとえば、 www.example.com について構築しようとしているのであれば、 www2.example.com などをテスト用として確保するとよい。
  • phpやrubyは動きません、Javascriptは動きます、Basic認証はできません、会員登録はできません(phpやrubyが必要なページは動かない)、などの制約事項があるので、非Techの関係者にネゴっとく必要がある。

1. S3の基本的な設定

  • なんでもいいのでバケットを作る。バケット直で自分が持っているドメインを紐付けようと思うなら、ドメイン名と全く同じバケット名(www.example.comのサイトを作りたい場合は、バケット名をwww.example.comにする。ドットは入力できないとエンジニアの直感でなんとなく思いがちだけど、普通に入力できる…。)にする必要があるが、多分不要。(未検証、今回はドメインと同じバケット名にしました…。)
  • 静的ウェブサイトホスティングを有効にする。
  • インデックスドキュメントはindex.html(他任意のファイル名でもOK)、エラードキュメントはerror.html(他任意ry)にする。
  • バケットに、html, access-logs, cf-logs のディレクトリを作成する。htmlがコンテンツ置き場、access-logがS3が直接ロギングするログ置き場、cf-logsがCloudFrontがロギングするログ置き場にする。
  • コンテンツを突っ込んでみて、静的ウェブサイトホスティング用のURLにアクセスして、コンテンツが表示されるかを確認する。

2. CloudFrontの基本的な設定

  • 基本的にはググって出てくるサイトを参考にしてよい。
  • Alternate Domain Names には、テスト用に確保しておいたドメインを入れる
  • Default Root Objectには index.html(もしくは特別な要件があればそれ)を入れる
  • LoggingはOnにして、コンテンツをホストするS3バケットと同じものを指定して、Log Prefixに cf-logs/ を入力する。
  • Origin Domain Name は S3バケット名ではなく、S3バケットの静的コンテンツWebホスティング用のエンドポイントにする。つまり、 www.example.com ではなくて、 www.example.com.s3-website-ap-northeast-1.amazonaws.com にする。
  • Origin Pathを /html にする。
  • Origin Protocol Policy は  HTTP Only にする。それ以外にするとS3内のコンテンツにアクセスできなくなって死ぬ。S3はHTPSをサポートしていない。HTTPSはCloudFrontがなんとかやるので、S3へはHTTPでアクセスさせてよい。
  • Viewer Protocol Policy を Redirect HTTP to HTTPS にする。これで、httpでアクセスしてきた人たちをhttpsに送らせることができる。
  • Object Cachingは明確なキャッシング作戦を用意している場合以外は、デフォルトでよい。
  • Forward HeadersやForward Cookies、Forward Cookiesはとくにそれを使ってやりたいことがなければNoneにする。
  • Compress Objects Automatically は Yesにする。gzip圧縮未サポートの端末はサポートを諦めて速度を取る。

3. DNS

  • CloudFrontのエンドポイントをドメインのCNAMEとして登録する。

4. S3によるリダイレクト

  • リダイレクトはS3の静的ウェブサイトホスティングの項目のところにXMLで入力する。
  • ルールは公式ページ他ググって付ける
  • 404時などにリダイレクトする場合は、エラーステータスによるリダイレクトを行う。書き方は公式ドキュメント参照。
  • 自サイト内でのリダイレクトは、同じドメインに対する別ホストリダイレクトみたいな書き方で定義する。
  • 上記があるため、本番切り替え直前まで、自サイト内リダイレクトには、CloudForntのホスト名を記述する必要がある。
  • なので、テスト用の一時的なドメインがあると便利。

5. CloudFrontによるHTTPS対応

  • SSL証明書はAWS-CLIよりIAMのSSL証明書置き場に送信する。
      aws --profile ebisol iam upload-server-certificate --server-certificate-name 画面に表示させたい証明書名 \
           --path /cloudfront/ \
           --certificate-body file://証明書ファイルのファイルシステム上のフルパス \
           --private-key file://秘密鍵ファイルのファイルシステム上のフルパス \
           --certificate-chain file://中間CA証明書ファイルのファイルシステム上のフルパス
  • ELBの置き場とは別物なので、すでにELB用にSSL証明書を登録してあったとしても、CloudFront用に再度登録する必要がある。
  • 登録できたら、General設定画面の [SSL Certificate]-[Custom SSL Certificate] がクリッカブルになるので、そこを変更する。

6. リリース作業

  • CloudFrontのAlternate Domain Namesをテスト用ドメインから本番用ドメインに変更する。
  • S3に記述したリダイレクトルールのうち、HostNameにテスト用ドメインを記述している箇所を全て本番用ドメインに書き換える。
  • DNSのCNAMEレコードをテスト用ドメインから本番用ドメインに切り替える。
  • 各種ページやリダイレクトルールについて表示確認を行う。変更前の状況が再現される場合は、CloudFrontから /* に対してInvalidationを行い、自分のブラウザのキャッシュも削除して、Invalidationが完了したあと再度確認する。
  • Invalidationが完了するまで確認しない。我慢できない気持ちが高まってくるけど、頑張って我慢する。
  • いろいろ考えると3時間ぐらい時間をネゴって確保しておいた方が良い。
  • あと、もし失敗した場合、2〜3日調査と改善に時間がかかる場合があるということも伝えたほうがいい。

7. AWS Lambda を利用した自動 Invalidation

  • このQiitaの記事内で公開されているLambda関数を自分のAWSでも動かす。(お世話になりました。)
  • ただLambdaにソースをアップロードするだけではだめで、IAMロールとポリシーを作る必要があるし、SNSトピックとサブスクライバも登録する必要がある。でもSNSはそんなに難しくない。
  • IAMロールは s3_CloudFront_Invalidator という名前で作成し、標準で用意されている AWSLambdaExecute というポリシーと、カスタムした CloudFrontInvalidation という自作ポリシーの2つを適用した。
  • CloudFrontInvalidation ポリシーはこんな感じにしたら動いた。
      {
          "Version": "2012-10-17",
          "Statement": [
              {
                  "Action": [
                      "cloudfront:Get*",
                      "cloudfront:List*",
                      "cloudfront:CreateInvalidation",
                      "iam:ListServerCertificates"
                  ],
                  "Effect": "Allow",
                  "Resource": "*"
              },
              {
                  "Action": [
                      "s3:GetBucketLocation",
                      "s3:GetObject",
                      "s3:GetObjectAcl",
                      "s3:ListBucket",
                      "s3:GetBucketWebsite"
                  ],
                  "Effect": "Allow",
                  "Resource": [
                      "arn:aws:s3:::*"
                  ]
              }
          ]
      }
  • 設定画面で、ConfigurationタブのHandlerが、デフォルトではindex.handler みたいになっていると思うので、jsファイル名に合わせる。 丸パクリでいくなら、「s3-invalidation.handler」を入力する。



コメント

このブログの人気の投稿

一部のユーザだけ NET::ERR_CERT_REVOKED でサイトにアクセスできない

[AWS] WAF を自分で組み立てるなら SAM でテンプレート書いた方が楽だよ

[#CentOS][#Apache] CentOS6 でApacheが起動できない