Lambda@Edgeを使用したCloudFrontのCognito認証を試してみた

2023.03.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、データアナリティクス事業本部の八木です。

S3を利用してwebページを公開するユースケースは増えてきているのではないでしょうか。
ここにCloudFrontを挟んで高速化、HTTPS化するといったこともあるでしょう。

パブリックに公開したいページの場合はこの構成で良いのですが、社内ページなどを限定公開をしたい場合はIP制限やユーザ認証といった手段を用いる必要があります。
IP制限はAWS WAFを用いて比較的容易に設定ができますが、ユーザ認証は自前で実装する必要があります。

そんなユーザ認証の一例として、今回はAWS公式ブログを参考に、Cognitoユーザプールに登録されているユーザのみがWebページにアクセスできる構成を試してみました。

構成

だいぶ省略していますが、主に以下のフローを踏んでいます。

  1. ユーザがCloudFrontに対してWebページをリクエスト
  2. CloudFrontはLambda@Edgeを実行し、Cookieに含まれる認証情報を確認
  3. 初回はクライアントが認証されていない(Cookieに認証情報が含まれない)ため、ログインページ(Cognito)へのリダイレクトレスポンスを返却
  4. ユーザがメールアドレスとパスワードでログイン
  5. 認証情報とともにCloudFrontへのリダイレクトレスポンスをクライアントに返却
  6. 5によりブラウザは自動的にCloudFrontへリクエストを送信
  7. Lambda@Edgeで認証情報を取得
  8. 認証情報が正しいかCognitoへ確認
  9. 認証情報が正しければS3からページを取得
  10. クライアントへページを返却

以降ユーザからCloudFrontへのリクエストを行うと、Lambda@EdgeはCookieを確認し、認証されていればWebページ(S3オブジェクト)の取得を許可します。

実際には②と⑦の関数は別になっており、⑧と⑨の間で一度リダイレクトが入ります。
より細かいフローは元の公式ブログに載っているため、そちらをご参照ください。

やってみた

リソースの作成

今回はAWSから提供されているSAMを使ってリソースを作成します。

こちらのリンクからSAMを開き、リソースを作成します。
ここでリージョンがバージニア北部になっていることをご確認ください。Lambda@Edgeで利用するLambda関数はバージニア北部で作成しておく必要があります。

「アプリケーション設定」の「EmailAddress」パラメータにCognitoに予め登録したいメールアドレスを入力します。(あとから追加することも可能です)

その他の項目はデフォルトのままで作成を行います。
しばらくするとデプロイが完了しました。

サンプルページをホストするS3バケット、S3バケットをオリジンとしたCloudFront、CloudFrontにアタッチするLambda@Edge関数、Cognitoユーザプールが作成されています。


Cognitoユーザプールには、SAMの作成時に指定したメールアドレスでユーザが作成されています。

Webサイトにアクセス

それではCloudFrontにアクセスしてみます。ディストリビューションのドメインはCloudFrontのコンソールから確認できます。

URLにアクセスすると、初回はCookieに認証情報がないため、Cognitoのログインページにリダイレクトされました。

「リソース作成時に指定したメールアドレス」と「メールアドレスに届いた初回パスワード」を入力します。
認証に問題がなければ新規パスワード設定を要求されます。

ログインするとCloudFrontにリダイレクトされ、S3にホストしているWebページが表示されました。

以降はリロードを行っても、認証情報が有効な間はログイン工程を踏むことなくページを閲覧することができます。

Chromeの開発者ツールからCookieを確認すると、認証情報が保存されていることも確認できます。

ユーザの追加

現在ログインできるユーザは1人だけになっています。

他のユーザも追加するにはCognitoユーザプールでユーザを作成する必要があります。
ユーザプール詳細画面→ユーザータブ→ユーザーを作成から新たなユーザを作成します。

追加したいユーザのメールアドレスを入力し、追加を行います。

新たなシークレットウィンドウを開き、CloudFrontにアクセスします。すると先ほどと同様にログインページにリダイレクトされました。

新たに作成したユーザのメールアドレスとパスワードを入力すると、ログインすることができました。

注意したいこと

今回使用したテンプレートは数年前に作成されたものですので、本番運用では最新の推奨設定に変更すると良いでしょう。

まず、作成されたLambda@Edgeの関数はNode.js 14でした。Node.js 14は2023/4/23にEOLを迎えるため、最新のLTSバージョンに乗り換える方が良いでしょう。

また、CloudFrontからS3へのアクセス制限にOAI(Origin Access Identity)が利用されていますが、こちらは現在非推奨となっており、代わりに OAC(Origin Access Control)の利用が推奨されています。

最後に

今回はLambda@EdgeとCognitoを利用してCloudFrontアクセスのユーザ認証を行ってみました。
社内限定でWebページを公開するなど、利用者を限定したい場合に非常に便利そうでした。
一方でテンプレートを利用しているとはいえ、自前実装となるため、ある程度のコードの知識は必要でしょう。

以上、八木でした!

参考リンク

Authorization@Edge using cookies: Protect your Amazon CloudFront content from being downloaded by unauthenticated users | Networking & Content Delivery
aws-samples/cloudfront-authorization-at-edge: Protect downloads of your content hosted on CloudFront with Cognito authentication using cookies and Lambda@Edge