書類
CloudFront+S3による静的サイトにCognito認証を追加してみた

CloudFront+S3による静的サイトにCognito認証を追加してみた

こんにちは、なおにしです。 静的コンテンツのみをWebサイトとして公開したい場合、AWSであればCloudFront+S3の構成はよく利用されるかと思います。 CloudFrontを用いているため、地理的制限の機能を使ったりAWS WAFと組み合わせたりすることである程度のアクセス元制限を行うこ

こんにちは、なおにしです。

静的コンテンツのみをWebサイトとして公開したい場合、AWSであればCloudFront+S3の構成はよく利用されるかと思います。
CloudFrontを用いているため、地理的制限の機能を使ったりAWS WAFと組み合わせたりすることである程度のアクセス元制限を行うことはできます。一方で、特定のユーザに対してのみ公開したいというユーザ認証が必要なケースでは別の仕組みが必要になります。
そこ で 今回 は 、 Amazon cognito を 用いる て cloudfront + s 3 に よる 静的 サイト に 認証 機能 を 追加 し て み まし た 。

どうすれば良いか

Application load balancer や API gateway に は マネジメント コンソール 上 で cognito と の 連携 を 設定 する ため の UI が 準備 さ れ て い ます が 、 cloudfront に は それ is あり が あり ませ ん 。 そこ で 、 AWS から 公開 さ れ て いる 以下 の node . js の パッケージ を cloudfront + lambda @ Edge に 適用 する こと で cognito と 連携 し ます 。

本パッケージに関する説明は以下のとおりです。

この Node . js パッケージ は 、 cloudfront ディストリビューション に リクエスト を 行う ユーザー が cognito ユーザー プール を 使用 し て 認証 さ れ て いる こと を 確認 する の に 役立つ ます 。 これ は 、 リクエスト に 含む れる cookie を 確認 する こと で 実現 さ れ 、 リクエスト 者 が 認証 さ れ て い ない 場合 は 、 ユーザー プール の ログイン ページ に リダイレクト さ れ ます 。 ( Google 翻訳 )

前提

今回は静的サイトの部分は既に作成済み&公開済みという前提で、以下の赤枠部分を追加する形で設定していきます。

やってみた

事前準備

認証機能の追加にあたって、ユーザが認証情報を入力するためのUIについてはCognitoが提供するUIを利用します。この際、Cognitoが提供する認証ページのドメインを指定する必要があります。ドメインについてもCognitoで提供されるもの(東京リージョンであれば「https://○○○.auth.ap-northeast-1.amazoncognito.com」)を使用することもできますが、前提のとおり既存の静的サイトがあれば独自ドメインもRoute 53で設定済みかと思います。そこで今回は認証ページにカスタムドメインとして取得済みの独自ドメインを設定するために、事前に以下を済ませておきます。

静的サイトをホストしているCloudFrontディストリビューションを指定したエイリアスレコードを作成します。作成するレコード名は、例えば静的サイトが「www.example.com」であれば「auth.example.com」のように静的サイトとは別名で作成します。

  • 認証 ページ に 接続 する 際 に 使用 する ACM 証明 書 を 作成

静的サイト構築時にワイルドカード証明書を作成している場合はそのまま流用できます(ACM証明書はバージニア北部リージョン/us-east-1で発行されているはずです)。

Cognitoの設定

認証機能の追加が目的であるためユーザープールを作成します。認可のためのIDプールは使用しません。
サインインオプションは少なくとも1つ選択する必要があるため、今回は「Eメール」を選択します。
CloudFront+S3による静的サイトにCognito認証を追加してみた

MFAの方法としては「Authenticator アプリケーション」を選択します。その他の項目はデフォルトのままです。
CloudFront+S3による静的サイトにCognito認証を追加してみた

マネジメントコンソールに記載のとおり、「自己登録を有効化」すると認証ページから誰でも自分自身をユーザ登録できてしまうため、今回はチェックを外します。その他の項目はデフォルトのままです。
CloudFront+S3による静的サイトにCognito認証を追加してみた

パスワード を 再 設定 する 場合 など に cognito から メール を 送信 する 際 の 送信 元 を 設定 し ます 。 Amazon ses で メール を 送信 できる 状態 で あれ ば 、 以下 の よう に 任意 の 送信 元 から メール を 送信 でき ます 。
CloudFront+S3による静的サイトにCognito認証を追加してみた

以下の各種項目を設定します。

  • 任意のユーザープール名を入力
  • 今回はAPIを実装せずにCognitoで提供される認証ページを使用するため「Cognito のホストされたUIを使用」にチェック
  • 認証ページのためのドメイン設定として「カスタムドメインを使用」を選択
  • カスタムドメインには前述の事前準備で設定した認証ページ用のレコードを設定
  • ACM 証明 書 is 選択 も 事前 準備 で 作成 また は 確認 し た もの を 選択
  • 任意のアプリケーションクライアント名を入力
  • コールバックURL(認証後に遷移する先のURL)として、静的サイトのURLを入力
    CloudFront+S3による静的サイトにCognito認証を追加してみた

設定した内容を確認して問題なければ「ユーザープールを作成」を選択します。作成完了まで少し時間がかかります。

ユーザープールが作成されたら各種設定を行えるようになるので、検証用にユーザーを作成してみます。
CloudFront+S3による静的サイトにCognito認証を追加してみた

「 アプリケーション の 統合 」 タブ の 下部 に 先ほど 作成 し た アプリケーション クライアント が 表示 さ れ て いる の で 「 ホスト さ れ た UI を 表示 」 を 選択 し ます 。
CloudFront+S3による静的サイトにCognito認証を追加してみた

Cognitoが提供する認証ページが表示されます。ここまでの設定に問題がなければ、上記で作成したユーザ情報でログインしてコールバックURLに設定した静的サイトのページに遷移することが確認できます。

CognitoとCloudFrontの連携設定

上記までの設定が終わっても、静的サイトのURLに直接アクセスすれば認証ページは当然表示されません。
ここからは、静的サイトのURLにアクセスするとCognitoの認証ページに推移するように設定を追加していきます。

Getting started に 記載 の 内容 を 参考 に 前述 し た Node . js パッケージ を 取得 し て 設定 および ZIP 化 し ます 。

 mkdir test - cognito - At - Edge 
 CD   test - cognito - At - Edge 
 NPM install cognito - At - Edge 
 vi INDEX . js 
 ZIP - r test - cognito - At - Edge . ZIP * 

index.jsには以下を記載して保存します。

const { Authenticator } = require('cognito-at-edge');

const authenticator = new Authenticator({
  // Replace these parameter values with those of your own environment
  region: 'ap-northeast-1', // user pool region
  userPoolId: '(ユーザープールID)', // user pool ID
  userPoolAppId: '(クライアントID)', // user pool app client ID
  userPoolDomain: '(カスタムドメイン ※https://は不要)', // user pool domain
});

exports.handler = async (request) => authenticator.handle(request);

ユーザープールIDとクライアントIDは以下のとおりマネジメントコンソールで表示されています。
CloudFront+S3による静的サイトにCognito認証を追加してみた
CloudFront+S3による静的サイトにCognito認証を追加してみた
ソースコードにID情報を直接書いた状態になっていますが、Lambda@Edgeには諸々の制限があるため今回はこのまま進めます。

上記制限に記載のとおりLambda@EdgeではLambda関数をバージニア北部リージョンでデプロイする必要があります。任意の関数名を指定し、「デフォルトの実行ロールの変更」から「AWS ポリシーテンプレートから新しいロールを作成」を選択します。
CloudFront+S3による静的サイトにCognito認証を追加してみた

ポリシーテンプレートを開くと「基本的なLambda@Edgeのアクセス制限(CloudFrontトリガーの場合)」という項目があるので、こちらを選択して任意のロール名を設定して関数を作成します。
CloudFront+S3による静的サイトにCognito認証を追加してみた

Lambda関数ができたら先ほど作成したzipファイルをアップロードし、Lambda@Edgeにデプロイします。設定は以下のとおりで、「Distribution」には静的サイトに用いているCloudFrontディストリビューションを指定します。
CloudFront+S3による静的サイトにCognito認証を追加してみた

デプロイするとLambda関数の画面ではすぐに適用されたように見えますが、対象のCloudFrontディストリビューションはデプロイステータスになりますので、ステータスが「有効」に変わったことを確認してから静的サイトにアクセスします。
認証 ページ が 表示 さ れれ ば 完了 です 。
上手く動作しない場合は以下を確認すれば解決するかもしれません。

  • 認証 ページ を 追加 する 前 の ブラウザ キャッシュ is 残っ が 残る て い ない か
  • ブラウザの設定でサードパーティCookieの使用を許可しているか

終わりに

パラメータ設定のためにjsファイルを若干編集したものの、ほぼノーコードで静的サイトに対して認証を追加することができました。ただし、今回はユーザープールIDなどの情報をスクリプトに直接記載していますが本来は外部参照にすべきなので、そちらについては別途まとめたいと思います。
この 記事 が どなた か の お 役 に 立てる ば 幸い です 。