【AWS Certificate Manager+Amazon CloudFront】サーバーレスで独自ドメインの静的サイトを公開しよう② HTTPS対応編

2019年10月7日Amazon CloudFront, Amazon Web Services, AWS Certificate Manager

こんにちは。プラットフォーム技術部の齊藤(沙)です。

前回の記事では、Amazon S3とAmazon Route53を使って独自ドメインの静的サイトを公開する方法を紹介しました。慣れてしまうとコンテンツさえあれば10分もかけずに静的サイトを公開できることがわかりましたね。

今回はその続きでセキュリティの観点を取り入れて、静的サイトのHTTPS対応もサーバーレスでやってみたいと思います。2018年7月に公開された「Chrome68」からは、HTTPS対応していないサイトは「保護されていません」と表示されるようになったように、サイトの信頼性を表明するためにもHTTPS対応は必須ですよね!

そして、前回の記事ではS3バケットを全公開にしていたので、アクセス制限設定も入れて最低限のセキュリティを担保します。

今回ご紹介する方法もAWSサービスのみを利用するため、簡単に試せます。ぜひ参考にしてみてください。

概要

やりたいこと

セキュリティ対策として・・

  • 前回作成した静的Webサイト(http://loveballet.be)をHTTPS化する
  • S3バケットへの直接アクセスを制限する

構成

今回構築する環境の構成図

利用するAWSサービス

AWS Certificate Manager

HTTPS対応(SSL化)にはまず、SSL/TLSサーバー証明書が必要です。一般的に、SSL/TLSサーバー 証明書は発行会社から購入しますが、事前にCSR(サーバー証明書発行に必要な署名要求)を作成する必要があり、更新の度に再設定が必要になるなど手間がかかりがちです。

今回はなるべく手間がかからない手段として、AWS Certificate Managerを使います。

AWS Certificate Manager(ACM)とは、AWSベースのウェブサイトとアプリケーション用のパブリック SSL/TLS 証明書の作成と管理ができるサービスです。無料で証明書を作成でき、失効する前に自動更新してくれるという優れものです。

今回は静的サイトを一般公開するため、パブリック証明書を取得します。パブリック証明書に対してプライベート証明書というものもこのACMで作成できます。この記事では割愛しますが、詳しくは以下のリンクを参考にしてみてください。

Amazon CloudFront

ACMで取得したパブリック証明書は、以下のいずれかのAWSサービスにひもづけして利用できます。コンテンツ置き場に利用したS3、EC2やオンプレミスサーバーでは利用できません。

  • Elastic Load Balancing
    • トラフィックの分散
  • Amazon CloudFront
    • コンテンツ配信の高速化
  • Amazon API Gateway
    • APIの作成・管理
  • AWS Elastic Beanstalk
    • Webアプリケーション実行環境の生成・管理
  • AWS CloudFormation
    • AWSリソース環境構築の自動化

上記の中でサイト公開によく使われるサービスはAmazon CloudFrontとAmazon API Gatewayです。

まずAmazon CloudFrontですが、ユーザーへのコンテンツ (.html、.css、.js、イメージファイルなど) の配信を高速化するサービスです。エッジロケーションと呼ばれるデータセンターの世界規模のネットワークを通じてコンテンツが配信されます。静的サイトはアクセスのたびに発生する配信以外を処理する必要はないため、S3とAmazon CloudFrontで構成されることが多いです。本記事でもAmazon CloudFrontを利用します。

費用の面ですが、12カ月無料枠で50GBのデータ送信と200万件のHTTPおよびHTTPSリクエストを利用できます。まずは試してみたい方にはとても有効なサービスだと思います。

一方、Amazon API Gatewayでは、AWS Lambda関数を実行したり、AWS Step Functionsステートマシンを起動できます。また、AWS Elastic BeanstalkやAmazon EC2上でホストされるHTTPエンドポイントや、パブリックインターネット経由でアクセスできる非AWSでホストされているHTTPベースのオペレーションを呼び出せます。これによりアクセスのたびに処理を行う動的サイトを構築できます。こちらについては、別の機会に使ってみようと思います。

手順の流れ

手順は、前回記事で静的サイト(http://loveballet.be)を一般公開してからの続きです。

SSL/TLSサーバー証明書の取得

HTTPS対応に利用する証明書をACMで取得します。

S3バケットと証明書をAmazon CloudFront(ディストリビューション)へひもづけ

Amazon CloudFrontでコンテンツ配信のために必要なディストリビューションを作成し、前回の記事で作成したS3バケットと取得した証明書をひもづけます。※ディストリビューションでは、コンテンツの取得元やコンテンツ配信の追跡・管理方法などを指定できます。

ドメインのDNSルーティング設定

ユーザーからのDNSクエリに対して、作成したディストリビューションのドメインを応答するようにDNSレコードを変更します。

S3バケットへのアクセス制限

バケットへは、ディストリビューションからのみアクセス許可するようバケットポリシーを変更します。

構築してみよう

SSL/TLSサーバー証明書の取得

ACMで証明書を作成します。Amazon CloudFrontでACM証明書を使用するには、米国東部(バージニア北部)リージョンで証明書をリクエストまたはインポートする必要があります。他のリージョンで作成しないよう注意してください。

ACMコンソール画面から証明書のプロビジョニングにて、「今すぐ始める」を選択します。

証明書のプロビジョニングにて、「今すぐ始める」を選択する

「パブリックの証明書」が選択されていることを確認し、「証明書のリクエスト」を選択します。

「証明書のリクエスト」を選択する

「ドメイン名」に"loveballet.be"を入力し、「次へ」を選択します。

「ドメイン名」を入力し、「次へ」を選択する

「DNS検証」が選択されていることを確認し、「確認」を選択します。これにより、ドメインの所有権は CNAMEレコードをDNS設定に追加することで検証できます。

「DNS検証」が選択されていることを確認し、「確認」を選択する

内容に間違いがないことを確認し、「確認とリクエスト」を選択します。

「確認とリクエスト」を選択する

検証状態が「検証保留中」になります。"loveballet.be"を選択し、「Route53でのレコード作成」を選択します。

"loveballet.be"を選択し、「Route53でのレコード作成」を選択する

「作成」を選択します。これにより、DNS検証ができます。

「作成」を選択する

レコード作成が成功したことを確認できたら、「続行」を選択します。

DNS検証が成功したことを確認する

数分後には、「発行済み」となったことを確認できます。

数分後、「発行済み」となったことが確認できる

S3バケットと証明書をAmazon CloudFront(ディストリビューション)へひもづけ

ここからAmazon CloudFrontを利用します。

Amzon CloudFrontのコンソールを開いて、「Create Distribution」を選択します。

「Create Distribution」を選択する

Web用のディストリビューションを作成するため、上の「Web」項目の「Get Started」を選択します。

「Web」項目の「Get Started」を選択する

「Origin Settings」の中の「Origin Domain Name」で"loveballet.be.s3.amazonaws.com"を選択します。これにより、前回の記事で作成したS3バケットとひもづけします。

「Origin Domain Name」で"loveballet.be.s3.amazonaws.com"を選択する

「Default Cache Behavior Settings」の中の「Viewer Protocol Policy」にて"Redirect HTTP to HTTPS”が選択されていることを確認します。この設定で、HTTPで接続してもHTTPSへリダイレクトされます。

「Viewer Protocol Policy」にて"Redirect HTTP to HTTPS”が選択されていることを確認する

「Distribution Settings」の項目で、「SSL Certificate」にて「Custom SSL Certificate」を選択し、作成した証明書(loveballet.be)を選択します。ここで、「Default CloudFront Certificate」を選んでしまうと独自ドメインでアクセスできません。

作成した証明書(loveballet.be)が選択されていることを確認する

最後に、「Default Root Object」で、"index.html"を入力します。空白のままの場合は、URLでドメイン名だけを指定するとCloudFrontのコンテンツが表示されてしまいます。

「Default Root Object」で、"index.html"を入力する

「Create Distribution」を選択すると、ディストリビューション作成が始まります。少し時間がかかりますが、完了すると以下になります。

ディストリビューションが作成されました

この段階で、https://loveballet.be に接続するとタイムアウトしてしまいます。ここまでの設定では、loveballet.beドメインは作成したディストリビューションへルーティングされていないからです。ディストリビューションのドメイン名(xxxx.cloudfront.net)では、HTTPSで接続できます。

ディストリビューションに設定されているドメイン名で接続できる

ドメインのDNSルーティング設定

loveballet.beドメインをディストリビューションへルーティングさせる設定を入れます。

まずは、ディストリビューションで代替ドメイン(CNAME)を指定します。対象のディストリビューションにて、「General」タブから「Edit」を選択します。

「General」タブから「Edit」を選択する

「Alternate Domain Names」に"loveballet.be"を入力します。

「Alternate Domain Names」に"loveballet.be"を入力する

「Yes,Edit」を選択し、設定変更を完了します。(少し時間がかかります)

loveballet.beのドメインは前回の記事のままですので、S3へ直接ルーティングされています。ディストリビューションへルーティングされるようレコード設定を変更します。

Amazon Route 53のコンソール画面から「Hosted zone」を選択します。

「loveballet.be」からAレコード設定(Alias がs3-website-ap-northeast-1.amazonaws.comのレコード)を選択します。

「Alias Target」に"xxxx.cloudfront.net"(CloudFront distributions)を選択します。

ディストリビューションへルーティングされるようレコード設定を変更する

S3バケットのアクセス制限

S3バケットに対してAmazon CloudFrontディストリビューションからのアクセスのみを許可する設定をします。

  1. CloudFrontコンソール画面にて、対象のディストリビューションIDを選択する
  2. 「Origins and Origin Groups」タブから対象オリジンのチェックボックスにチェックをいれ、「Edit」を選択する
  3. 「Restrict Bucket Access」にて、Yesにチェックを入れる
  4. 「Origin Access Identity」にて、「Create a New Identity」を選択する
  5. 「Grant Read Permissions on Bucket」にて、「Yes, Update Bucket Policy」を選択する
  6. 「Yes,Edit」を選択する

この手順により、自動的にS3のバケットポリシーが以下のように更新されます。

{
    "Version": "2012-10-17",
    "Statement": [
          {                                                  ##削除する
                "Sid": "PublicReadGetObject",                ##削除する
                "Effect": "Allow",                           ##削除する
                "Principal": "*",                            ##削除する
                "Action": "s3:GetObject",                    ##削除する
                "Resource": "arn:aws:s3:::loveballet.be/*"   ##削除する
           },                                                ##削除する
          {
                "Sid": "2",
                "Effect": "Allow",
                "Principal": {
                    "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ExxxxxxMK" ##IDはそれぞれ異なる
                 },
                "Action": "s3:GetObject",
                "Resource": "arn:aws:s3:::loveballet.be/*"
           }
    ]
}

ここで、前回の記事でバケット公開用に設定したポリシーを削除することでS3バケット自体のURLへのアクセスは不可になります。

最後に、S3の「ブロックパブリックアクセス機能(バケット設定)」を利用し、さらにセキュア化を図ります。前回の記事では全公開にするために、「ブロックパブリックアクセス(バケット設定)」のうちバケットポリシーの設定を外していましたが、全公開する必要が無くなっため設定を戻します。

  1. S3コンソール画面にて、バケット名"loveballet.be"を選択する
  2. 「アクセス権限」タブから「ブロックパブリックアクセス」を選択する
  3. 「編集」を選択し、「パブリックアクセスをすべてブロック」にチェックを入れる
  4. 「保存」を選択する

以上により、Amazon CloudFrontディストリビューションからのアクセスは許可されたまま、新規のパブリックバケットポリシー追加を防止できるようになりました。

確認

https://loveballet.beへアクセスできていますね!合わせて、証明書もAmazonで発行されたものだと確認できました。

設定したドメイン名でアクセスできた!
証明書の詳細

続いて、S3バケットのドメイン(http://loveballet.be.s3-website-ap-northeast-1.amazonaws.com/)へアクセスできないことも確認できました。

S3 バケットのドメイン名ではアクセスできない

まとめ

AWSサービスのみでサーバーレスかつ低コストでHTTPS対応した静的サイトを公開できました。また、コンテンツ自体のセキュリティも担保しました。特に証明書取得・管理を無料でできることがとっても魅力的だと思います。

気軽に静的サイトを作りたいけどセキュリティ対策も気になる。。。というケースで今回の記事がお役に立てたらと思います。

  • 株式会社アークシステムの来訪管理・会議室予約システム BRoomHubs
  • 低コスト・短納期で提供するまるごとおまかせZabbix