API GatewayのオーソライザーにAmazon Cognitoを使ってみた件

記事タイトルとURLをコピーする

こんにちは SRE1課の冨塚です。

Amazon API Gatewayを構築する機会があり、Lambdaオーソライザーの設定をしたのですがLambdaの構築と各セットアップをしていてLambda以外のオーソライザーを使えるのか?とふと疑問に思いドキュメントを読んでいるとAmazon Cognitoユーザプールもオーソライザーにできらしいのでとりあえず試してみました。

作業概要

  • Cognitoの設定
  • Lambdaの作成
  • API Gatewayの構築
  • 動作確認

Hello Worldを返すLambdaを作成しAPI Gatewayから呼び出せるようにセットアップします。 Cognitoオーソライザーの設定は下記公式ドキュメントを参考にセットアップしていきます。

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html

Cognito構築

API Gatewayへのアクセスを許可ユーザ情報をCognitoを使って用意します。

  1. Cognitoのマネコンから「ユーザプールを作成する」を選択 f:id:swx-tomitsuka:20210301211405p:plain

  2. プール名を入力しデフォルトを確認するを選択 f:id:swx-tomitsuka:20210301211409p:plain

  3. 確認画面でアプリクライアントの設定 f:id:swx-tomitsuka:20210301211414p:plain

  4. 必要な項目を入力し「アプリクライアントの作成」を選択
    下記を実施しました

    • アプリクライアント名
    • クライアントシークレット生成のチェックをオフ
    • 認証用の管理API~ のチェックをオン f:id:swx-tomitsuka:20210301211417p:plain 内容に問題なければ作成をクリック
  5. ユーザプールの作成が完了したらプールIDを控え、次にユーザを追加 f:id:swx-tomitsuka:20210301211422p:plain

  6. ユーザ名と仮パスワードを入力します f:id:swx-tomitsuka:20210301211427p:plain

  7. ユーザ作成直後はステータスを確認
    ユーザ作成直後はステータスが"FORCE_CHANGE_PASSWORD"となり初期パスワードを設定しないと使えない状態です f:id:swx-tomitsuka:20210301211431p:plain

  8. 下記コマンドをaws cli で実行し作成したユーザにパスワードを設定
    控えていたプールIDとユーザに設定するパスワードを準備してください

      aws cognito-idp admin-set-user-password \
      --user-pool-id ap-southeast-1_XXXXXX \
      --username user01 \
      --password XXXXXXX \
      --permanent```
    
  9. 再度ステータスを確認
    コマンド実行後にユーザのステータスを確認すると"CONFIRMED"になっていることを確認してください f:id:swx-tomitsuka:20210301211436p:plain

  10. IDトークンを取得
    ユーザ認証が成功するとトークンを取得できます。このトークンを利用してAPI Gatewayへアクセスしますので事前に取得します。レスポンス内容のIdTokenの値を控えます。

リクエスト

    aws cognito-idp admin-initiate-auth \
    --user-pool-id ap-southeast-1_FUxxxxxxL \
    --client-id 79bxxxxxxxxxxxxxxxxxd7i \
    --auth-flow ADMIN_NO_SRP_AUTH \
    --auth-parameters USERNAME=user01,PASSWORD=dufUvO2!

レスポンス

    {
        "AuthenticationResult": {
            "ExpiresIn": 3600, 
            "IdToken": "eyJraWQiOiJtSj --snip-- ctaud1KQ", 
            "RefreshToken": "eyJjdHkiOiJKV1Qi --snip-- ekGdow", 
            "TokenType": "Bearer", 
            "AccessToken": "eyJraWQiOiI0 --snip-- LJglxpAlDI9nqtKneYSp5ETgog2j-Urw"
        }, 
        "ChallengeParameters": {}
    }

トークン取得までできればCognitoの設定が完了です

Lambda構築

"Hello World"を返すLambdaの作成します。作成方法については下記公式ドキュメンを参考に準備していきます。

「Hello, World!」 Lambda 関数

  1. Lambdaマネコンへアクセスし「関数の作成」を選択 f:id:swx-tomitsuka:20210301211439p:plain

  2. 「1から作成」を選択し下記項目を埋めて「関数の作成」をクリック

    • 関数名:GetStartedLambdaProxyIntegration
    • ランタイム:Node.js 14.x
    • 実行ロールの変更
      • 「AWSポリシーテンプレートから新しいロールを作成」
      • ロール名:GetStartedLambdaBasicExecutionRole f:id:swx-tomitsuka:20210301211445p:plain
  3. インラインコードエディタで下記コードを記載して「Deploy」を選択 f:id:swx-tomitsuka:20210301211450p:plain

    利用したコードは"Hello from Lambda!"を返す内容になっています

これでLambdaは完了です。

API Gatewayの構築

作成したLambdaをAPI Gatewayから読み出せるようにしていきます。下記公式ドキュメントの内容で準備していきます。

「Hello, World!」 API を作成する

上記ドキュメントの内容でAPI Gatewayの構築できたら次にオーソライザーの設定へ移ります。

  1. オーソライザーを作成
    API Gatewayの構築が完了したらオーソライザーの設定を実施します。下記項目を入力します。

    • 名前:CognitoAuth
    • タイプ:Cognito
    • Cognitoユーザプール:<作成したユーザプール>
    • トークンのソース:Authorization f:id:swx-tomitsuka:20210301211456p:plain
  2. 作成後にオーソライザーのテストを実施
    認可トークンの箇所にCognito構築の際に取得したユーザIDトークンを入力し「テスト」を選択します。トークンが有効であれば応答コードに200が返ってきます。 f:id:swx-tomitsuka:20210301211502p:plain 応答コードが403になる場合はトークンの有効期限が切れている場合がありますので、トークンを再度取得してください。

  3. リソース > メソッド からメソッドリクエストを選択 f:id:swx-tomitsuka:20210301211506p:plain

  4. 認可に作成したオーソライザーを選択し更新 f:id:swx-tomitsuka:20210301211510p:plain

  5. オーソライザーの設定が完了したらアクションから「APIのデプロイ」を選択 f:id:swx-tomitsuka:20210301211513p:plain

  6. APIのデプロイを実施
    デプロイされるステージは"新しいステージ"を選びステージ名は任意のものを入力してください。 f:id:swx-tomitsuka:20210301211517p:plain

  7. デプロイが完了したらURLを確認
    URLの呼び出しに記載されたURLに足してリクエストを投げますのでコピーしておきます。 f:id:swx-tomitsuka:20210301221147p:plain

これでAPI Gatewayの用意も完了です。

動作確認

必要なリソースの作成が完了したので実際に動作確認をしていきます。取得したIDトークンが1時間以上経過している場合は再取得するようにしてください。

IDトークンなし

  • リクエスト内容

      curl https://xxxxxxxx.execute-api.ap-southeast-1.amazonaws.com/auth/helloworld
    
  • 実行結果

      $ curl https://xxxxxxxx.execute-api.ap-southeast-1.amazonaws.com/auth/helloworld
    
      {"message":"Unauthorized"}
    

IDトークンがない場合はUnauthorizedエラーとなり403のエラーコードが返ってきます。

IDトークンあり

トークン内容は省略して記載しています

  • リクエスト内容

      curl https://xxxxxxxx.execute-api.ap-southeast-1.amazonaws.com/auth/helloworld \
      -H "Authorization: eyJraWQ --snip-- rIcEFXLKaaRiKqfB5A"
    
  • 実行結果

      $ curl https://xxxxxxxx.execute-api.ap-southeast-1.amazonaws.com/auth/helloworld \
      -H "Authorization: eyJraWQ --snip-- rIcEFXLKaaRiKqfB5A"
    
      "Hello from Lambda!"
    

トークン付きでAPI GatewayへアクセスするとLambdaの実行内容がレスポンスに含まれることが確認できました! いろいろ試行錯誤しましたがCognitoのユーザIDを使ってAPI Gatewayへのアクセスを制限されているところまでできました。

期限切れのIDトークンを使った場合

トークンの有効期限が切れている場合の動作もみてみます

  • リクエスト内容

      curl https://xxxxxxxx.execute-api.ap-southeast-1.amazonaws.com/auth/helloworld \
      -H "Authorization: eyJraWQ --snip-- Y3YscPoMl0ah0VLCRg"
    
  • 実行結果

      $ curl https://xxxxxxxx.execute-api.ap-southeast-1.amazonaws.com/auth/helloworld \
      -H "Authorization: eyJraWQ --snip-- rIcEFXLKaaRiKqfB5A"
    
      {"message":"The incoming token has expired"}
    

まとめ

Lambdaオーソライザーしか構成したことがなかったため、Cognitoでオーソライザーを設定する方法がわかったのでよかったです。IDトークンをどのように取得しAPIへアクセスさせるかは作り込む必要があると思いますがひとまず確認したかったことができたのでよしとします。

それではよいAWSライフをお送りください。

swx-tomitsuka (執筆記事の一覧)