電通総研 テックブログ

電通総研が運営する技術ブログ

Amazon CognitoでAPIGatewayに認証をつける(後編)

こんにちは。コミュニケーションIT事業部 ITソリューション部の英です。

普段はWebアプリやスマホアプリの案件などを担当しています。あと、趣味でAIを勉強しています。

いつもはAI関連の記事を書いていますが、今回はAWSの認証サービスであるAmazon Cognitoについて検証します。
近々案件で使いそうなので、そのための予習です。

さて、前回はトークン発行までのフローを解説しました。
今回はこれらのトークンを使用して、AWS上のリソースに対するアクセス制御を行うための設定をしていきます。
前回の記事

今回の構成はこちらです。

(引用元:ユーザープールと共に API Gateway と Lambda を使用してリソースにアクセスする)


#ここから本題

STEP1:API用のLambda関数を作成する

APIGatewayを経由して、このLambda関数を呼びだすことにします。
パラメータで変数を受け取って、その中身を返却するだけのシンプルな作りです。

import json

def lambda_handler(event, context):
    # イベントのログを出力
    print("Received event: " + json.dumps(event, indent=2))
    
    # リクエストボディからデータを抽出
    body = json.loads(event.get('body', '{}'))
    
    # データの抽出
    key1 = body.get('key1')
    key2 = body.get('key2')
    
    # データの処理(ここでは単純に受け取ったデータをレスポンスに含める)
    response_message = f"Received key1: {key1}, key2: {key2}"

    # アクセストークンが有効である場合のレスポンス
    response = {
        'statusCode': 200,
        'body': json.dumps({
            'message': 'Access token is valid. Hello from Lambda!',
            'response_message': response_message
        })
    }
    
    return response

STEP2:APIGatewayを作成する

AWSコンソールで新しいAPIを作成しましょう。

STEP3:オーソライザーを作成する

オーソライザーのタイプはLambdaかCognitoかを選択できます。
今回はCognitoを選択しましょう。
より細かな検証を行いたい場合は、Lambdaでカスタムロジックを書くことができます。
トークンのソースにAuthorizationを指定するのを忘れないようにしてください。

「オーソライザーをテスト」でIDトークンの検証ができます。
Cognitoから受け取った「id_token」を貼り付けて実行すると、個人に紐づく情報が出力されます。
これをクレーム(claims)といいます。

IDトークンの中身については以下の公式リファレンスを参照してください。
ID トークンの使用

STEP4:APIキーを作成する

APIを呼びだすために必要なAPIキーを発行します。
開発、検証、本番と環境ごとにAPIキーを発行しましょう。
今回は1つだけ作成します。

STEP5:メソッドを作成する

今回はPOSTで受け取って、Lambdaを起動する設定にします。
STEP1で作成した関数を指定しておきましょう。

APIキーを必須とし、リクエストバリデーターではヘッダーを検証する設定にしておいてください。(Authorization)

STEP6:使用量プランを作成する

ここではAPIの同時リクエスト数などを設定できます。環境ごとに設定することができます。
これとは別にAPIの性能はクォータも影響してきますので、環境ごとの設定を確認し、必要であれば引き上げ申請を行いましょう。
使用量プランの API レベルとステージレベルのスロットリング目標の設定

STEP7:プランにAPIキーを追加する

STEP6で作成したプランにAPIキーを追加します。
これでステージ(dev)とAPIキーの紐づけが完了しました。

APIのエンドポイントは環境ごとに吐き出されます。

STEP8:リクエスト用のスクリプト作成

今回はCloud9で作成したPythonスクリプトからAPIをコールします。ここの手順はPostmanでも何でもいいです。
分かりやすいようにAPIキーやトークンをベタ打ちしていますが、本番開発では暗号化したり、環境変数に登録するなど対策してから使用してください。

import requests
import json

# API GatewayのエンドポイントURL
api_url = 'https://(APIのエンドポイント)/dev'

# 取得したIDトークン(※前回の記事を参照)
id_token = '(Cognitoから受け取ったid_token)'

# APIキー
api_key = '(APIキー)'

# API Gatewayに送信するデータ
data = {
    'key1': 'dentsu',
    'key2': 'soken'
}

# ヘッダーの設定 (Authorizationでid_tokenを渡します、x-api-keyでAPIキーを渡します)
headers = {
    'Content-Type': 'application/json',
    'Authorization': id_token,
    'x-api-key': api_key
}

# デバッグ情報の表示 (必要に応じて使用してください)
#print("Sending request to API Gateway...")
#print(f"URL: {api_url}")
#print("Headers:")
#for key, value in headers.items():
#    print(f"  {key}: {value}")
#print("Payload:")
#print(json.dumps(data, indent=2))

# POSTリクエストを送信
try:
    response = requests.post(api_url, headers=headers, data=json.dumps(data))
    response.raise_for_status()  # HTTPエラーが発生した場合に例外をスロー

    # レスポンスの表示
    print(f'Status Code: {response.status_code}')
    print('Response Headers:')
    for key, value in response.headers.items():
        print(f'  {key}: {value}')
    print('Response Body:')
    print(response.json())

except requests.exceptions.RequestException as e:
    print(f"Request failed: {e}")
    if e.response is not None:
        print(f"Response Code: {e.response.status_code}")
        print(f"Response Body: {e.response.text}")

STEP9:検証

パターン1:正常系
まずは、すべての情報が正しい場合のリクエストを実行してみます。
ステータスコード200で返ってきていることが確認できます。
POSTで投げた値(dentsu,soken)もLambda側で受け取れていることが確認できます。

パターン2:異常系(不正なid_token)
id_tokenに適当な文字を加えて実行してみます。
頭にIjyou(いじょう)を足しました。

401(Unauthorized)が返ってきました。
Cognitoオーソライザーが正しく機能しているようです。
このユーザー(id_token)は認証済みではないといっています。

パターン3:異常系(不正なAPIキー)
api_keyに適当な文字を加えて実行してみます。
頭にIJyou(いじょう)を足しました。

403(Forbidden)が返ってきました。
APIキーが正しく機能しているようです。
APIキーが無効だといっています。

今回はこれ以上の検証をしませんが、その他のゲートウェイレスポンスについては公式のリファレンスを参照してください。

ゲートウェイレスポンスのタイプ

さいごに

APIGatewayとCognitoを統合する方法を解説しました。
今回はCognitoオーソライザーを使用して、id_tokenのみ確認しましたが、access_tokenも検証したい場合はLambdaオーソライザーを選択して独自に検証ロジックを記述する必要があります。
API Gateway Lambda オーソライザーを使用する

これからもAWS関連の検証記事をたくさん書いていきます。
↓ のスターを押していただけると嬉しいです。励みになります。

最後まで読んでいただき、ありがとうございました。

私たちは一緒に働いてくれる仲間を募集しています!

コミュニケーションIT事業部

執筆:英 良治 (@hanabusa.ryoji)、レビュー:@nakamura.toshihiro
Shodoで執筆されました