AWSの部屋

AWS学習者向けのブログです

スポンサーリンク

Cognito ユーザープールをオーソライザーとして使って API Gateway のアクセスを制御する

はじめに

本日は Cognito ユーザープールを API Gateway のオーソライザーとして使ってみようと思います。

Cognito ユーザープール とは

以下のエントリーをご参照ください。

www.aws-room.com

オーソライザーを使うメリット

API Gatewayのエンドポイントはグローバルに公開されているおり、誰でもアクセス可能です。IPアドレスなどでアクセスを制御することもできますが、認証されたユーザだけがアクセス可能な API としてデプロイすることでセキュアな状態を維持することができます。

今回のゴール

Cognito 経由で REST API を使って S3 のバケット一覧を取得します

アーキテクチャ

手順

  1. ユーザープールの作成
  2. ユーザ登録
  3. IDトークンの取得
  4. IAMロール 作成
  5. Lambda 関数の作成
  6. API Gateway作成
  7. 動作確認

1. ユーザープールの作成

以下の設定でユーザープールを作成します。

項目
プロバイダーのタイプ Cognito ユーザープール
Cognito ユーザープールのサインインオプション E メール
パスワードポリシーモード Cognito のデフォルト
多要素認証 MFAなし
ユーザーアカウントの復旧 デフォルト
セルフサービスのサインアップ デフォルト
属性検証とユーザーアカウントの確認 デフォルト
属性変更の確認 デフォルト
必須の属性 email
属性変更の確認 デフォルト
E メール Cognito で E メールを送信
ユーザープール名 任意のユーザープール名
ホストされた認証ページ デフォルト
アプリケーションタイプ 秘密クライアント
ホストされた認証ページ デフォルト
アプリケーションクライアント名 任意のアプリケーションクライアント名
クライアントのシークレット クライアントのシークレットを生成しない
高度なアプリケーションクライアントの設定 デフォルト
属性の読み取りおよび書き込み許可 デフォルト

2. ユーザ登録

以下のようにユーザを作成します。

3. IDトークンの取得

このIDトークンを利用して API Gateway へアクセスしますので事前に取得します。

import boto3
import json

# CognitoIdentityProviderクライアント(Using Amazon Cognito user pools API)
idp_client = boto3.client('cognito-idp')

response = idp_client.admin_initiate_auth(
           UserPoolId = "xxx",
           ClientId = "xxx",
           AuthFlow = "ADMIN_NO_SRP_AUTH",
           AuthParameters={
               "USERNAME": "xxx",
               "PASSWORD": "xxx",
           }
 )

print(json.dumps(response, indent=2))

以下のようなイメージでIDトークンが取得できます(以下は値を加工しています)

{
  "ChallengeParameters": {},
  "AuthenticationResult": {
    "AccessToken": "eyJrlWcQT0_LDihkbBhWf_zaddMc6k1JEcd1hGlsyOV3D4n2qClnxlFaTDTFXZvM8gco8QX0W0_ib_Ium_4wnORiUAQQeoQK6hEZruY7IJ7EGfkTictJyQl5iOdxCnk7TYA",
    "ExpiresIn": 3600,
    "TokenType": "Bearer",
    "RefreshToken": "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.Io5wUP2Aw9ZTCnxO_xmzG-q6riAKfpdhmTLjnT6BGtRH2fowrNIg7XjueMFjztVlkXGqRr2zG1HJLe4azmomdJe1d7_-N61zgiBYG9MZI_1sF8Z",
    "IdToken": "eyJraWQiOiJiV3hrV3FOZ2lCdSsrZDJLWGwxa0JVdjlCSUVjRHZuUUg4YmlaTklSQWVJPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiIwNTYyNDVkOS03MzIwLTQzZDgtYWRiNC1kMzY3NDEyNGVjMzciLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaX99rEU6uHLA"
  },
  "ResponseMetadata": {
    "RequestId": "ed94d428-8120-4838-9429-49320925d7e6",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "date": "Sat, 19 Nov 2022 05:14:08 GMT",
      "content-type": "application/x-amz-json-1.1",
      "content-length": "4132",
      "connection": "keep-alive",
      "x-amzn-requestid": "ed94d428-8120-4838-9429-49320925d7e6"
    },
    "RetryAttempts": 0
  }
}

4. IAMロール 作成

「Lambda-S3Access」という AWS Systems Manager への権限を付与したロールを作成します。

5. Lambda 関数の作成

以下のように Lambda 関数を作成します。

項目
オプション 一から作成
関数名] get-s3-bucket-list
ランタイム] Python 3.9
アーキテクチャ] 86_64
既存のロール]] Lambda-S3Access
ソースコード

S3 のバケット一覧を取得します。

import json
import boto3

s3 = boto3.resource('s3')

def lambda_handler(event, context):

    bucket_list = []
    for bucket in s3.buckets.all():
        bucket_list.append(bucket.name)
    
    return bucket_list

6. API Gateway作成

以下のように API Gateway を作成します。

項目
API タイプを選択 REST API
プロトコルを選択する] REST
新しい API の作成 ] 新しい API
API cognito-authorizer
説明 任意
エンドポイントタイプ デフォルト
API 作成後

リソースを作成します。

「5. Lambda関数の作成」で作成した関数名を入力しメソッドを作成します。

Lambda 関数に自動的に API Gateway のトリガーが設定されます。

API をデプロイします。

デプロイ後にエンドポイントの URLが表示されます。

以下のようにオーソライザーを作成します。

「認可トークン」項目にIDトークンをコピーしてテストすると正常終了します。

リソース > メソッドリクエストを選択します。

作成したオーソライザーを選択し更新します。

再度API をデプロイします。

7. 動作確認

IDトークンなし

以下のように REST API を実行します。

curl https://m158t0jime.execute-api.ap-northeast-1.amazonaws.com/development

認証されていない旨のメッセージが返されました。

{"message":"Missing Authentication Token"}
IDトークンあり

以下のように REST API を実行します。(IDトークンは加工しています)

curl https://m158t0jime.execute-api.ap-northeast-1.amazonaws.com/development -H "Authorization: eyJraWQiOiJiV3hrV3"

S3 のバケット一覧を取得することができました。

["20220514-cloudfront-test", "20220521-web-hosting", "20220807-sqs-test", "20220809-endpoint-gateway", "20220809-vpc-endpoint", "20220810-s3-gateway-endpoint", "20220810-test-bucket", "20220812-rekognition-test", "aws-athena-query-results-370560102364-ap-northeast-1", "aws-cloudtrail-logs-370560102364-44d0a6db", "aws-presigned-url", "cf-templates-lxrja6wfp65n-ap-northeast-1", "data-lake-20210331", "log-from-kinesis-sanvarie", "test-queue-sanvarie"]

さいごに

少しとっつきにくい Cognito ですが、使いこなせば非常に便利なサービスですね。まだまだ触りのところしかわからないので引き続き勉強しようと思います。