Cognito+Lambda@EdgeでCloudFrontの配信コンテンツに認証をつける

概要

  • Cognito+Lambda@Edgeをつかって、CF配信に認証をつけたい
  • cognito-at-edgeを使用する
  • ものすごいハマってしまったので、将来の自分の為に残す

とても参考にさせていただきました

oji-cloud.net

yomon.hatenablog.com

CF作成

配信はCF+S3で実施する。

S3作成

  • S3バケットを作成(リージョンは東京で作った)

CF作成

  • CF作成し、オリジンをS3指定する
  • OriginAccessControlで制御する

{
    "Version": "2008-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::gamecontainer-ot-content/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::012345678901:distribution/XXXXXXXXXX"
                }
            }
        }
    ]
}

これでS3➡CFのアクセスができるようになる。
CFのディストリビューション名でアクセスをして確認してみると良い

Lambda@Edgeを作成

github.com

こちらのライブラリをそのまま使う

npm init
npm install cognito-at-edge
npm install dotenv

一応dotenvと組み合わせたけど、これは本質ではない。本来ならSecretManager使うとか、環境変数に入れるとかするべきかも。

require('dotenv').config();

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

const authenticator = new Authenticator({
  // Replace these parameter values with those of your own environment
  region: process.env.REGION, // user pool region
  userPoolId: process.env.USERPOOLID, // user pool ID
  userPoolAppId: process.env.USERPOOLAPPID, // user pool app client ID
  userPoolDomain: process.env.USERPOOLDOMAIN, // user pool domain
});

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

Cognito作成

Cognitoは今回はメールアドレスとパスワードの認証で作成。
これは任意でOKのはず。最初はお試しでメールパスワードの認証がわかりやすい。

アプリクライアントの確認

デフォルトでアプリクライアントが作成されているはず

これのWebと名前書いたやつを使おう。(どっちでもいけるのか?)

アプリクライアントの設定

ここが本番。

以下を設定する

このAuthorization code grandopenidをチェック忘れていてひどくハマった・・・

L@Eの設定

Lambda@Edgeに記載する情報がそろったので、.envを記載する

.envを用意する

REGION=ap-northeast-1
USERPOOLID=ap-northeast-1_hogehoge
USERPOOLAPPID=userpoolappid
USERPOOLDOMAIN=domain.auth.ap-northeast-1.amazoncognito.com

Lambdaは必ずバージニア北部で作成する必要があります(Lambda@Edgeとして登録する際の条件)

以下、Lambdaをデプロイするときのコマンド例

zip -r function.zip .env index.js package-lock.json package.json node_modules
aws lambda update-function-code --function-name function-name --zip-file fileb://function.zip --region us-east-1 --profile myprofile
  • USERPOOLID
    • Cognitoのユーザプールの名前。似たような名前が記載されているはず
  • USERPOOLAPPID
    • これがさっきのアプリクライアントID USERPOOLDOMAIN
    • Cognitoの認証エンドポイントを独自にドメインを決められるので、その名前。

👆で設定できる。Cognitoのドメインのものを使う場合は早い者勝ちになる。

Lambda@Edgeの設定

  • Lambda@EdgeはCFのビューワリクエスに張り付ける
  • ちなみに、ビューワリクエストにLambda@Edgeを貼るということは、リクエストが呼ばれるたびにLambda@Edgeが動くことになる。お金の心配したくなる
    • オリジンリクエストにはったLambda@Edgeは、レスポンスをCFがキャッシュしてくれるときには呼ばれない
    • キャッシュをしっかり効かせてやると、静的ページであればほとんどLambda@Edge呼ばれないっていう感じになるはず

Lmabda@Edgeの設定

Lambdaの画面から、「バージョン」を選択し、「新しいバージョンを発行」を実施して、新バージョンを作る

「トリガを追加」からCF選ぶ

  • ディストリビューションを選ぶ
  • CloudFrontイベントは「ビューアーリクエスト」を選ぶ
  • Lambda@Edgeへのデプロイを確認をチェックする(これチェックしないとデプロイできない)

確認

CFのデプロイはおそらく5分くらいで終わるので、デプロイ後にCFのディストリビューション名称でアクセスして確認する

Cognitoのログイン画面が出てきて、ログイン求められるはず。作ったユーザでログインできればOK