Lambda@Edgeを使用したCloudFrontのCognito認証を試してみた
こんにちは、データアナリティクス事業本部の八木です。
S3を利用してwebページを公開するユースケースは増えてきているのではないでしょうか。
ここにCloudFrontを挟んで高速化、HTTPS化するといったこともあるでしょう。
パブリックに公開したいページの場合はこの構成で良いのですが、社内ページなどを限定公開をしたい場合はIP制限やユーザ認証といった手段を用いる必要があります。
IP制限はAWS WAFを用いて比較的容易に設定ができますが、ユーザ認証は自前で実装する必要があります。
そんなユーザ認証の一例として、今回はAWS公式ブログを参考に、Cognitoユーザプールに登録されているユーザのみがWebページにアクセスできる構成を試してみました。
構成
だいぶ省略していますが、主に以下のフローを踏んでいます。
- ユーザがCloudFrontに対してWebページをリクエスト
- CloudFrontはLambda@Edgeを実行し、Cookieに含まれる認証情報を確認
- 初回はクライアントが認証されていない(Cookieに認証情報が含まれない)ため、ログインページ(Cognito)へのリダイレクトレスポンスを返却
- ユーザがメールアドレスとパスワードでログイン
- 認証情報とともにCloudFrontへのリダイレクトレスポンスをクライアントに返却
- 5によりブラウザは自動的にCloudFrontへリクエストを送信
- Lambda@Edgeで認証情報を取得
- 認証情報が正しいかCognitoへ確認
- 認証情報が正しければS3からページを取得
- クライアントへページを返却
以降ユーザから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