LoginSignup
3
1

AWS CognitoとサードパーティーIDプロバイダのOIDC連携手順(IDプール編)

Posted at

はじめに

本記事では外部IDプロバイダ(以降IdP)とCognitoアイデンティティプール(以降IDプール)の連携方法について解説します。
なお、ユーザープールでの連携方法に関しては以下をご覧ください。
https://qiita.com/BanaoLihua/items/03b82da7deb109f73361

外部IdPを使用した際のシナリオ

公式ドキュメントには、Cognitoと外部IdPでのOIDC連携時には以下のような場面に対応していると記述されています。

  • IDプールを使用する場合(今回はこちらを紹介します!
    image.png

  • ユーザープールを使用する場合
    image.png

  • ユーザープールとIDプールを使用する場合
    image.png

APIGWではオーソライザーにユーザープールを使用することができます。

連携手順

前提

  • IdPが正常に機能すること
  • IDプール周りの権限を保持していること(※作成に当たってはIAM周りの権限も必要となります)

処理の流れ

処理の流れ.drawio (3).png

外部IdPへのリダイレクト応答およびIDトークン取得、IDプールへのアイデンティティID取得およびAWS一時クレデンシャルの取得はアプリケーション側で実装する必要があります。

1.IDプロバイダの追加

IAMへアクセスし、「アクセス管理」→「IDプロバイダ」→「プロバイダの追加」へ遷移します。
「プロバイダの設定」では以下を設定してください。

・プロバイダのタイプ
☑OpenID Connect
・プロバイダのURL
適宜記入し「サムプリントを取得」を押下
・対象者
クライアントIDを入力
image.png
「サムプリントを取得」押下時にエラーが出るもしくは変化が無い場合は、権限が足りていない可能性が高いです。

2.IDプールの作成

Cognitoへアクセスし、「IDプールを作成」へ遷移します。

IDプールの信頼を設定

・ユーザーアクセス
☑認証されたアクセス
・認証されたIDソース
☑OpenID Connect(OIDC)
image.png
image.png

許可を設定

・IAMロール
新規作成するか、既存のロールを選択
新規作成する場合は、最小限のアクセス許可となり、IAMロール名が必要となる
・IAMロール名(※新規作成する場合のみ)
適宜記入
image.png

IDプロバイダーを接続

・OIDC IDプロバイダー
「1.IDプロバイダ追加」で設定したIdPを選択
・ロール設定
☑デフォルトの認証されたロールを使用
・アクセスコントロールの属性
☑非アクティブ

プロパティを設定

・IDプール名
適宜記入
・基本認証
☐基本フローをアクティブ化

3.正常性確認

正常に作成したIDプールが機能しているか確認していきます。
アプリケーションで処理を作りこむ際はAWS SDKを使用する必要がありますが、以下の言語が対応しています。

  • .NET
  • Go
  • Java
  • JavaScript
  • Python
  • Ruby
  • PHP
  • C++

今回はJavaScriptを例に一部紹介します。

AWS CLIで確認する場合

認可コードの取得

外部IdPの認可エンドポイントへアクセスして認可コードを取得します。

IDトークンの取得

認可コードを使用して外部IdPのトークンエンドポイントへアクセスし、IDトークンを取得します。

IDプールでアイデンティティIDを取得する

以下を実行するとアイデンティティIDが取得できます。

// コマンド
aws cognito-identity get-id \
--identity-pool-id "<IDプールのID>" \
--logins '{"<設定したIdP>":"<IDトークン>"}'

IDプールのIDは以下から確認できます。
1005.png
設定するIdP名はユーザーアクセスタブの「アイデンティティプロバイダー」から確認できます。
image.png

// 実行結果
{
    "IdentityId": "ap-northeast-1:xxxxxxxxxxxxxxxxxxxxxxxx"
}

AWSクレデンシャルを取得する

// コマンド
aws cognito-identity get-credentials-for-identity \
--identity-id <アイデンティティID> \
--logins '{"<設定したIdP>":"<IDトークン>"}'
// 実行結果
{
    "IdentityId": "ap-northeast-1:xxxxxxxxxxxxxxxxxxxxxxxx",
    "Credentials": {
        "AccessKeyId": "xxxxxxxxxxxx",
        "SecretKey": "xxxxxxxxxxxx",
        "SessionToken": "xxxxxxxxxxxx",
        "Expiration": "2023-01-01T00:00:00+00:00"
    }
}

以上、AWS CLIでの一時クレデンシャル発行でした。

アプリケーションで実装する場合(Lambdaでnode.jsを使用)

認可コードの取得

アプリクライアントにアクセスする際、認可コードがパラメータに付与されていない状態だと外部IdPの認可エンドポイントへリダイレクト応答するようにします。

// 必要な変数を定義
const authorization_endpoint = "<認可エンドポイント>";
const response_type = "code";
const client_id = "<クライアントID>";
const redirect_uri = "<リダイレクト先(アプリクライアント)>";
const scope = "<スコープ>";
// 認可エンドポイントへリダイレクト応答
const redirect_response = {
  statusCode: 301,
  headers: {
    location: `${authorization_endpoint}?response_type=${response_type}&client_id=${client_id}&redirect_uri=${redirect_uri}&scope=${scope}`
  },
};
return redirect_response;

IDトークンの取得

取得した認可コードを使用してトークンエンドポイントへアクセスし、IDトークンを取得します。

// 必要な変数を定義
const token_endpoint = "<Trustbindのトークンエンドポイント>";
const grant_type = "authorization_code";
const redirect_uri = "<リダイレクト先(アプリクライアント)>";
const client_id = "<クライアントID>";
const client_secret = "<クライアントシークレット>";
const code = 認可コード;

// リクエストボディに変数を追加してトークンエンドポイントへPOSTリクエスト(fetch)
const params = new URLSearchParams();
params.append('grant_type', grant_type);
params.append('redirect_uri', redirect_uri);
params.append('client_id', client_id);
params.append("client_secret", client_secret);
params.append("code", event.queryStringParameters.code);
const postResponse = await fetch(token_endpoint, {
  method: "POST",
  body: params,
});

// レスポンスを整形してid_tokenのみ抜き出し
const data = await postResponse.json();
const id_token = JSON.parse(JSON.stringify(data)).id_token;

アイデンティティIDおよび一時クレデンシャルの取得

AWS SDKからCLIで行った操作と同じことができます。以下はJavaScriptの場合です。
詳細はAPIリファレンスのCognitoアイデンティティプールの項目を参照してください:
https://docs.aws.amazon.com/ja_jp/cognitoidentity/latest/APIReference/API_Operations.html

// アイデンティティID取得
var params = {
  IdentityPoolId: "<IDプールのID>" // ※必須
  AccountId: アカウントID,
  Logins: {
    "<IDプールに登録したIdP名>": "<IDトークン>"
  }
};
cognitoidentity.getId(params, function(err, data) {
  if (err) console.log(err, err.stack); 
  else     console.log(data);
});

// AWSクレデンシャル交換
var params = {
  IdentityId: "<アイデンティティID>", // ※必須
  CustomRoleArn: "<カスタムロールのARN>",
  Logins: {
    "<IDプールに登録したIdP名>": "<IDトークン>"
  }
};
cognitoidentity.getCredentialsForIdentity(params, function(err, data) {
  if (err) console.log(err, err.stack);
  else     console.log(data);
});
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1