DVA

Cognito IDプールでゲスト/サインインユーザーで権限を分ける

スポンサーリンク
Cognito IDプールでゲスト/サインインユーザーで権限を分ける DVA
スポンサーリンク
スポンサーリンク

Cognito IDプールでゲスト/サインインユーザーで権限を分ける

Cognito IDプールは認証済みユーザーに加えて、未認証のゲストユーザーに対しても、一時的なクリデンシャルを生成することができます。
今回はゲスト・サインインユーザーに対して、異なる権限を与える構成を確認します。

構築する環境

AWS認定アソシエイト3資格対策~ソリューションアーキテクト、デベロッパー、SysOpsアドミニストレーター~ | 平山毅, 堀内康弘, 福垣内孝造, 岡智也, 池田大, 原江梨佳, 澤田拓也, 原俊太郎, 仲村勇亮, 上村祐輝, 鳥谷部昭寛 | 工学 | Kindleストア | Amazon
Amazonで平山毅, 堀内康弘, 福垣内孝造, 岡智也, 池田大, 原江梨佳, 澤田拓也, 原俊太郎, 仲村勇亮, 上村祐輝, 鳥谷部昭寛のAWS認定アソシエイト3資格対策~ソリューションアーキテクト、デベロッパー、SysOpsアドミニストレーター~。アマゾンならポイント還元本が多数。一度購入いただいた電子書籍は、K...
Diagram of change permissions for guest/sign-in users in Cognito ID Pool.

S3バケットを作成し、静的ウェブサイトホスティング機能を有効にします。
内部にHTMLファイルを設置して、コンテンツを用意します。

CognitoユーザープールのホストされたUIでサインイン機能を作成します。

Cognito IDプールでゲスト・サインインユーザーに権限を割り当てるように設定します。
具体的には、2つのLambda関数を作成し、それぞれ対応するユーザーが実行できるように設定します。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLに、CloudFormationテンプレートに加え、ブラウザスクリプト等を配置してます。

awstut-dva/03/003 at main · awstut-an-r/awstut-dva
Contribute to awstut-an-r/awstut-dva development by creating an account on GitHub.

テンプレートファイルのポイント解説

サインインユーザーとゲストユーザーで権限を分けるため、Cognito IDプールを設定を中心に確認します。

IDプールにゲスト・サインインユーザー用のIAMロールをアタッチする

Cognito IDプールでユーザーに権限を与えるためには、対応するIAMロールをアタッチするという方法になります。

Resources: IdentityPool: Type: AWS::Cognito::IdentityPool Properties: AllowUnauthenticatedIdentities: true CognitoIdentityProviders: - ClientId: !Ref UserPoolClient ProviderName: !Sub "cognito-idp.${AWS::Region}.amazonaws.com/${UserPool}" IdentityPoolName: !Sub "${Prefix}-IdentityPool" IdentityPoolRoleAttachment: Type: AWS::Cognito::IdentityPoolRoleAttachment Properties: IdentityPoolId: !Ref IdentityPool Roles: authenticated: !GetAtt IdentityPoolAuthenticatedRole.Arn unauthenticated: !GetAtt IdentityPoolUnauthenticatedRole.Arn
Code language: YAML (yaml)

IDプール本体は特別な設定を行いません。
ユーザープールと連携するように設定するだけです。

ポイントはIAMロールをアタッチメントです。
今回はサインイン・ゲストユーザーに別々の権限を割り当てますので、それぞれauthenticated・unathenticatedプロパティを使用して、IAMロールを設定します。

今回は以下のIAMロールを定義します。

Resources: IdentityPoolAuthenticatedRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: sts:AssumeRoleWithWebIdentity Principal: Federated: cognito-identity.amazonaws.com Condition: StringEquals: cognito-identity.amazonaws.com:aud: !Ref IdentityPool ForAnyValue:StringLike: cognito-identity.amazonaws.com:amr: authenticated Policies: - PolicyName: IdentityPoolAuthenticatedPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - lambda:InvokeFunction Resource: - !Ref AuthenticatedFunctionArn IdentityPoolUnauthenticatedRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: sts:AssumeRoleWithWebIdentity Principal: Federated: cognito-identity.amazonaws.com Condition: StringEquals: cognito-identity.amazonaws.com:aud: !Ref IdentityPool ForAnyValue:StringLike: cognito-identity.amazonaws.com:amr: unauthenticated Policies: - PolicyName: IdentityPoolUnauthenticatedPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - lambda:InvokeFunction Resource: - !Ref UnauthenticatedFunctionArn
Code language: YAML (yaml)

ConditionプロパティでIAMロールを引き受けるための条件を設定します。
詳細は以下のページをご確認ください。

ロールの信頼とアクセス権限 - Amazon Cognito
Amazon Cognito の信頼ポリシーの例。

Policiesプロパティで、付与する権限を定義します。
Lambda関数を指定して実行を許可します。

実行するLambda関数

Cognitoとは関係ありませんが、Lambda関数の定義を確認します。

Resources: AuthenticatedFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${Prefix}-AuthenticatedFunction" Runtime: python3.9 Role: !GetAtt LambdaRole.Arn Handler: index.lambda_handler Code: ZipFile: | import datetime def lambda_handler(event, context): return str(datetime.date.today()) UnauthenticatedFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Sub "${Prefix}-UnauthenticatedFunction" Runtime: python3.9 Role: !GetAtt LambdaRole.Arn Handler: index.lambda_handler Code: ZipFile: | import datetime def lambda_handler(event, context): return str(datetime.datetime.now().time())
Code language: YAML (yaml)

インラインで実行するコードを記載します。
Lambda関数の定義方法の詳細については、以下のページをご確認ください。

ランタイム環境はPython3.9を選択し、それぞれ以下を実行するように設定します。

  • サインインユーザー用関数:本日の日付を返す。
  • ゲストユーザー用関数:現在の時刻を返す。

ブラウザスクリプト

JavaScriptを使用して、サインイン後のCognito機能を実装します。
AWS SDK for JavaScript v3を使用してブラウザスクリプトを作成する手順は、以下のページをご確認ください。

本ページでは、ゲスト・サインインユーザーの振り分けに関する内容を中心に取り上げます。

IDトークン取得

今回の構成では、OAuthフローにImplicit Grant(暗黙の付与)を設定しています。
Implicit Grantですと、URLパラメータからIDトークンを取得することができます。
サインインユーザーの場合、以下のコードでIDトークンを取得することができます。

const params = new URLSearchParams(location.hash.slice(1)); const idToken = params.get("id_token");
Code language: JavaScript (javascript)

詳細は以下のページをご確認ください。

ユーザーに応じてLambdaクライアント作成

Lambda関数にアクセスするために、クライアントオブジェクトを作成します。
ポイントはIDトークンの有無によって、対応を分ける点です。

import { CognitoIdentityClient } from "@aws-sdk/client-cognito-identity"; import { fromCognitoIdentityPool } from "@aws-sdk/credential-provider-cognito-identity"; import { LambdaClient, InvokeCommand } from "@aws-sdk/client-lambda"; import { toUtf8 } from "@aws-sdk/util-utf8-browser"; let lambdaClient; let functionName; if (idToken) { lambdaClient = new LambdaClient({ region: REGION, credentials: fromCognitoIdentityPool({ client: new CognitoIdentityClient({ region: REGION }), identityPoolId: IDENTITY_POOL_ID, logins: { [`cognito-idp.${REGION}.amazonaws.com/${USER_POOL_ID}`]: idToken } }), }); functionName = FUNCTION_NAME_AUTHENTICATED; } else { lambdaClient = new LambdaClient({ region: REGION, credentials: fromCognitoIdentityPool({ client: new CognitoIdentityClient({ region: REGION }), identityPoolId: IDENTITY_POOL_ID }), }); functionName = FUNCTION_NAME_UNAUTHENTICATED; }
Code language: JavaScript (javascript)

サインインユーザーの場合、先述のコードによって、IDトークンの取得できます。
ですからそのトークンを使って、クライアントオブジェクトを作成します。

一方ゲストユーザーの場合、サインインしていませんから、IDトークンを取得できません。
ですからIDトークンを使わない形で、クライアントオブジェクトを作成します。

このクライアントオブジェクト時に、IDプールにアタッチしたIAMロールに基づいたクリデンシャルが使われます。
つまりユーザーに応じた権限が設定されているということです。

Lambda関数実行

この後の処理は共通です。
クライアントオブジェクトを使ってLambda関数を実行します。

(async () => { const response = await lambdaClient.send( new InvokeCommand({ FunctionName: functionName }) ); document.getElementById("function-result").innerText = toUtf8(response.Payload); })();
Code language: JavaScript (javascript)

Lambda関数を実行し、実行結果をHTMLに埋め込みます。
先述の通り、クリデンシャルで付与された権限の範囲内で関数を実行します。

HTMLファイル

参考にHTMLも確認します。

<html> <head></head> <body> <h1>index.html</h1> <p id="function-result"></p> <ul> <li> <p><a href="https://[domain].auth.ap-northeast-1.amazoncognito.com/login?response_type=token&client_id=[client-id]&redirect_uri=[redirect-url]/index.html">Sign In</a></p> </li> <li> <p><a href="https://[domain].auth.ap-northeast-1.amazoncognito.com/logout?client_id=[client-id]&logout_uri=[redirect-url]/index.html">Sign Out</a></p> </li> </ul> <script type="text/javascript" src="./main.js"></script> </body> </html>
Code language: HTML, XML (xml)

クラス名がfunction-resultのpタグ内に、Lambda関数の実行結果を埋め込みます。

サインイン・サインアウト用のURLを設置します。
リダイレクトURLはこのindex.htmlを指すように設定します。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

S3バケットにコンテンツを設置する

S3バケットにHTML・JavaScriptファイルを設置します。

Two files are uploaded to the S3 bucket.

この2ファイルがサインイン/サインアウト後のコンテンツです。

検証:ゲストユーザーでアクセス

準備が整いましたので、実際にコンテンツにアクセスします。
以下のURLにアクセスします。

https://s3-ap-northeast-1.amazonaws.com/dva-03-003/index.html

Functions for guest users were executed.

現在の時刻が表示されました。
これは現時点ではサインインしていませんので、ゲストユーザーとして本ページにアクセスしていることになり、ゲストユーザー用のLamabda関数が実行されたということです。

検証:サインインユーザーでアクセス

続いてサインアップ/サインイン処理を行います。
詳細は以下のページをご確認ください。

サインアップ/サインインが完了しましたら、改めて本ページにリダイレクトされます。

Functions for Sign-in users were executed.

現在の日付が表示されました。
これはサインイン処理によって、IDトークンが生成され、サインインユーザー用のLambda関数が実行されたということです。

(参考)IDプール

参考までに、ここまでの手順で生成されたIdentityを確認します。

Two Identities have been created.
Two Identities have been created.

ご覧の通り、2つのIdentityが作成されていることがわかります。
つまりサインインユーザーだけでなく、ゲストユーザー用のIdentityも生成され、それを使ってゲスト用のLambda関数が実行されたということです。

まとめ

ゲスト・サインインユーザーで権限を分ける方法を確認しました。
具体的には、IDプールでゲスト・サインインユーザー用のIAMロールをアタッチした上で、IDトークンの有無によって処理を分岐させる方法です。

タイトルとURLをコピーしました