Amazon Verified Permissions のアイデンティティソース機能を使って、Cognito ユーザープールのトークンベースで認可してみた

2023.08.09

いわさです。

先日、Amazon Verified Permissions を使った認可リクエストを試してみました。

その際には認可リクエストに手動でプリンシパルを指定し、is-authorizedコマンドで認可リクエストを送信するというものでした。

Amazon Verified Permissions ではアイデンティティソースという機能があって、本日時点では Cognito ユーザープールを連携することが出来ます。
これにより、Cognito で認証時に取得した ID トークン(あるいはアクセストークン)をis-authorized-with-tokenコマンドへ送信することで、トークンを使った認可リクエストを実行することが出来ます。

本日はこちらの機能を実際に試してみました。
エラーが出て苦戦しましたが、簡単な認可リクエストが確認出来るところまで出来たので紹介します。

何をしてくれるのか?

前述の記事ではis-authorizedコマンドでプリンシパルなどのコンテキスト情報を送信する必要があるため、自分でトークンの解析と必要な情報を抽出し、ポリシーストアで想定されているスキーマ構成と手動でマッピングを行う必要があります。

is-authorized-with-tokenコマンドでは、プリンシパル情報は引き渡す必要はなく、トークン(ID トークン、アクセストークン)をコマンドにそのまま引き渡すことで、ポリシーからトークンクレームにアクセスしてポリシーを評価することが可能です。

なお、本日時点でサポートされている IdP は Cognito ユーザプールのみとなっています。
そのため、Cognito 以外の IdP ではis-authorized-with-tokenを使わずに、自分でトークンから情報の抽出とマッピングを行った上でis-authorizedを実行する必要があります。

利用シーンとしてイメージしやすいのは API Gateway と Cognito ユーザープールを使って Lambda オーソライザーで認可処理を実装するシーンです。
従来は次のようにトークンから必要な情報を抽出し Lambda オーソライザー内に認可ロジックを実装するか、あるいは動的な制御が必要な場合は外部のデータストアにアクセスする場合もありました。

Verified Permission を使う場合は Lambda オーソライザーからトークンを渡して、Verified Permissions で評価された結果に基づいてオーソライザーでポリシーを作成することが出来ます。

アイデンティティソースの作成方法

ここでは前提として Amazon Cognito ユーザープールを作成済みとします。
Amazon Verified Permissions でポリシーストアを作成した後に、対象ポリシーストアのメニュー内で「ID ソース」から構成することが可能です。

対象リージョンと Cognito ユーザープールの ID を入力します。
指定したプリンシパルタイプにトークンがマッピングされますが、本日はユーザープールやクライアントの評価のみを行っているので、任意のプリンシパルタイプを指定しました。

トークンを使って認可リクエスト

ではここから認可リクエストを送信してみましょう。
今回は AWS CLI で Cognito ユーザプールに対して認証を行い、取得した ID トークンを使ってis-authorized-with-tokenコマンドを実行してみましょう。

「Avp internal call validation failed」エラーが発生

まず、単純にトークンだけ引き渡して試してみたところ次のようなエラーが発生しました。

% cat withtoken.json
{
    "policyStoreId": "6d8kf1Pte9UXazrE8BGf1T",
    "identityToken": "eyJraWQ...lMJVUHwFg"
}
% aws verifiedpermissions is-authorized-with-token --cli-input-json file://withtoken.json

An error occurred (ValidationException) when calling the IsAuthorizedWithToken operation: Avp internal call validation failed

アクセストークンで試してみても同じようなエラーが発生しました。
しかもエラーメッセージからも原因がよくわからずで、心が折れそうになりました。

期限切れのトークンで試してみる

トークンはいずれ有効期限を迎えるわけですが、その際には別のエラーが発生しました。

% aws verifiedpermissions is-authorized-with-token --cli-input-json file://withtoken.json

An error occurred (ValidationException) when calling the IsAuthorizedWithToken operation: Token validation failed: ExpiredSignature

このエラーメッセージはわかりやすいですね。
どうやらトークン自体の評価は出来ていそう?

登録されていないユーザープール

次に、ユーザープールを登録せずにトークンを送り付けたところ、また別のエラーメッセージが発生しました。

% aws verifiedpermissions is-authorized-with-token --cli-input-json file://withtoken.json

An error occurred (ValidationException) when calling the IsAuthorizedWithToken operation: Input is not valid

ちょっとエラーメッセージがわかりにくいですが、ID ソースの構成変更によってエラーメッセージの内容が変わっているので、このことからトークンの送信方法は悪くなさそうです。
それ以外の要素(他に必要な情報がある or ID ソースの構成方法に誤りがある)に問題があるように思えました。

そして適当なパラメータを追加してみたところ評価結果を取得することが出来ました。

% cat withtoken.json
{
    "policyStoreId": "6d8kf1Pte9UXazrE8BGf1T",
    "action": {
        "actionType": "Action",
        "actionId": "1111"
    },
    "resource": {
        "entityType": "hoge",
        "entityId": "aaaa"
    },
    "identityToken": "eyJraWQiOi...JVUHwFg"
}
% aws verifiedpermissions is-authorized-with-token --cli-input-json file://withtoken.json
{
    "decision": "DENY",
    "determiningPolicies": [],
    "errors": []
}

ドキュメントにもどれが必須なのか記載がないように思えましたが、いくつかのパターンを試した限りではおそらくactionresoucreが必須です。

登録されたユーザープールで許可されたクライアント

ここでユーザープールを追加し、任意のプリンシパルやリソースを許可するポリシーを追加しました。

トークン付きで認可リクエストを送信したところ次のレスポンスを取得することが出来ました。

% aws verifiedpermissions is-authorized-with-token --cli-input-json file://withtoken.json
{
    "decision": "ALLOW",
    "determiningPolicies": [
        {
            "policyId": "Nhi81KzXBGXBooJg5eRPHU"
        }
    ],
    "errors": []
}

おお。

登録されたユーザープールで許可されていないクライアント

ここで、許可されたユーザープールかつ、許可されていないクライアントで取得したトークンを送信してみましょう。
ユーザー自体は先程と同じユーザーです。

% aws verifiedpermissions is-authorized-with-token --cli-input-json file://withtoken.json

An error occurred (ValidationException) when calling the IsAuthorizedWithToken operation: token audience validation failed

audienceの検証に失敗していますね。
どのトークンでも受け付けるわけでなく、指定したユーザープールの特定クライアントのみを受け付けることが確認出来ています。

さいごに

本日は Amazon Verified Permissions のアイデンティティソース機能を使って、Cognito ユーザープールのトークンベースで認可してみました。

ポリシーで細かい制御まではまだ検証していませんが、まずはユーザープール(+ クライアント)を登録し、登録されたクライアントのトークンのみが許可されることを確認することが出来ました。
次回以降はカスタムクレームなどを指定したポリシー制御を実行してみたいと思います。