Cognitoで認証されたユーザーだけがAPI Gatewayを呼び出せるオーソライザーを使ってみた

2020.09.30

はじめに

API Gatewayは、デプロイする時にエンドポイントが割り当てられます。エンドポイントはグローバルに公開されている為、誰でもアクセス可能な状態です。グローバル向けに公開するAPIGatewayであればこのまま使用して良いですが、利用者が限定される場合は制限が必要です。

リソースポリシーでAWSアカウントやIPアドレスなどで制限することもできますが、バックエンドのAPIとして利用するなら認証されたユーザだけがアクセス可能なAPIとして使用する方法がシンプルと考えてAPI Gateway オーソライザーを試してみました。

構成図

Cognitoユーザープールで認証されたユーザがCognitoユーザープールトークンを使ってAPI Gatewayを呼び出す構成です。

 

 

Cognitoユーザープールの作成

まずは認証基盤となるCognitoユーザープールを作成します。

基本的にはデフォルトの設定で問題ありません。ユーザープールを作成できたらプールIDを控えておきます。 次にアプリクライアントからアプリクライアントを追加します。

 

アプリクライアント名は任意で入力します。クライアントシークレットは今回不要なのでチェックを外します。認証フローの設定で「認証用の管理 API のユーザー名パスワード認証を有効にする (ALLOW_ADMIN_USER_PASSWORD_AUTH)」にチェックをいれます。これはCognitoユーザ認証時にIDトークンを使用します。今回は管理者権限でIDトークンを取得するのでチェックを入れいます。取得方法は後述します。最後に「アプリクライアントの作成」をクリックします。

表示されるアプリクライアントIDを控えておきます。

ユーザーの作成

認証で利用するCognitoユーザーを作成します。

アカウントのステータスがFORCE_FORCE_CHANGE_PASSWORDとなっています。作成したCognitoユーザーはパスワード変更が必須なので、今回は管理者権限でパスワードをセットします。

弊社ブログを参考にパスワードをセットしました。

AWS CLIを使ってCognitoユーザーステータスのFORCE_CHANGE_PASSWORDをCONFIRMEDにしてみる

アカウントのステータスが、CONFIRMEDとなっていればOKです。

API Gatewayの作成

REST APIで作成していきます。petstoreというサンプルAPIのドキュメントが用意されているのでインポートします。

APIドキュメントに基づき、リソースパス、メソッドなどが定義されただけの状態です。アクションから「APIをのデプロイ」をクリックします。

デプロイステージを作成、選択します。ステージを利用することでAPIを環境毎やバージョン毎にデプロイを管理することができます。例えば、開発中のAPIステージパスをdev、本番のAPIステージパスをprodとした場合、APIエンドポイントのパスで分けることができます。

  • https://api-id.execute-api.region.amazonaws.com/dev
  • https://api-id.execute-api.region.amazonaws.com/prod

今回はdevとしてAPIをデプロイします。

devステージがデプロイされてAPIエンドポイントが割り当てられました。

エンドポイントにアクセス(オーソライザーなし)

エンドポイントにアクセスすると正常なレスポンスが返ってきます。アクセスコントロールを設定していないので誰でもアクセスできるので、Cognitoを使ったオーソライザーでアクセスを制限していきます。

Cognitoオーソライザーの設定

オーソライザー画面から「新しいオーソライザーの作成」をクリックします。

タイプはCognito、Cognitoユーザープールに作成したユーザープールIDを選択します。トークンのソースはAuthorizationとします。Cognitoユーザープール認証成功時にユーザープールトークンで取得できるIDトークンを使ってAPIを呼び出すことができます。IDトークンはAurhorizationヘッダーに設定されている為、トークンのソースをAuthorizationと入力し、作成します。

作成されたオーソライザー単体でテストができるので実際にユーザープールトークンを取得してテストしてみます。認可トークンを空欄でテストすると401のレスポンスが返ってきます。

次にAWS CLIでIDトークンを取得する為、CognitoユーザープールID、アプリクライアントIDを指定して実行します。(実際の出力とは異なり、ランダムな文字列に置換しています)


$ aws cognito-idp admin-initiate-auth --user-pool-id CognitoユーザープールID --client-id アプリクライアントID --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME=ユーザ名,PASSWORD=パスワード
{
    "ChallengeParameters": {},
    "AuthenticationResult": {
        "AccessToken": "z4wkX7ofGpQoRdToxhptFfEGbsutXMDFPXEyGTMA6bBUdowKqyEvGdYQC2XCFAVn8dvizk3YKMxGqCRZd4wveyBvBNLDeJ4o.NrYprkBt8DWxXTBp2MQAPQtKaXpCp7FvueRpZuMWcNFQbNmykuHsbG4hbLNDiV2LJMCJc8TB3pded9eE8owRMtw2J3dXfiarc4Bbh9v3z4hvHA4Ys4DTEQD9EAFfaZUpRM9hvrjDqBm3dTi2kvNMEBvdFDTuuiMybdzkBtPFZsJyGWuUeXLv42s6VeQNKTpWHdRWBBgME3iwiDfkaaA8r3ZPtCq9afW4FKutKTxxv7Erb248MtrCXDpA9Kaui8GQuY3XavJNmBENRvMgYWtdYYeVyL6A4EjFQfhKQGvE6JgUT6muWuXzEprU8QFdcfQg7ZVQDvLGWreYkeiHLXMpEzvFNkpNZ3b3MKgnKEWKk3qZPPJnzo3C9NLMkKDRXhrzEofJcTRMbZia799N3xEpad3cxRsRCWeB8YxNZPeAsM3bgWfezeuKTQuJ8GcUdTLTCdfmREMNu87M7LAasDQv3KDDYtiXuY7kh6XwUTRqBNkEkkLXgZkCynRHgtwPx2DQN9vjzyym6UAwK7p7AtWUv9bYJfn.z4!LrktYeHV@R3P39W3-xaBDQXtTDo3TwUJtG7ytNuRRXK-GqXdJ!uQqWb4*p2dd47E2Znb_4z8XEBwhB9Mz4rqCYYo-87oEn7pnfs.QbXNNxu6KLTCR@sFq9douiumiXG.nn@bHvdK*Zu28z-aF6UgYVVVZpn.i4b3!d-jQUWsBe4-GPUx2TVenjKvfZWUyTt7kk62jxA8e7HggwF74_@dcQtRfXAXUfe2w_sfU_Fa_TZrvf9ep*8JYXTjGUJP9Z8L7HBP8!Uywq7Umv-2X-2B3BZscUCZwqd9j!2oQKtdC*mA9mqmjb*rkrZxin-kCiju_tDVjQgfNCyFs8EqPko3",
        "ExpiresIn": 3600,
        "TokenType": "Bearer",
        "RefreshToken": "WjX8nLsKt.w2tgM*@y9uK-*dtLLa*ksjLh!w!e7EX*-CjaKd.KA@zo!v9Xpfnn.vGE7qCFTyKj..P8tfozYLnD-y7.z7jw3WwJqm3x4byC9rNRFUoPFKptsjeEZy!Cbmv_AL2y-*BQxeLrDyqGfXWC_tbdyWA.Kyr8LGvJzg8baVNkvsbMJ4wvZU-U6bLVE6od*w3pxqBEL7.93mGcf4DxRrVmk8xGBCi!qn7sjYbqfcyB!TJgh!Q2wNa*bGJRLmHT9yRUk@XKn9fxowHL!PY4dyRJ7T*st*BnTAyWWyAvNRPnBFCDX3V@yKWDUwp4i2*URKpW93MJG848e3_oiU3y8QivqFbfN_LkewETBwgjeWeJtQ-TTT9TjJesQWr_eoH!pFj_qz.ysUh*jQb*oUzdUkofE.MP*8eh*YAM7EHHxnGeGjmkGvAfKMH2uTgr_TkAUiZn!u@R.czKQF9mzXVstxtaa3FMCNAivQpPN.H@hgnM.aRtuuuf8vJrkvoLEvPLBVa_gz7ZsEV3Pvjwf.ZPCmF9uyo8LBgMwqJ-.MNFawD47GPXK_CBdWb*BqfJgcRN!Arrgd@EPBFgRTKNzNFU3jq@E4aUua@mrENTKRz!YgQkCMKjvm-b7daTqY6@-L_izhM7bJWfoTqwGKiGuKu-V.vdciJtyhBof9cLF@-esGYxz*ofcR*-2WUMzkfjRuFGy6ZxY@!P6__jK-_unTPEpd6*u6ckV9pvFpryo.sMD4RWhyJwzukTuxvHE7VpnNuma27MB2orKrUfdf9h_j-r2e2H*WUYQYxhJXtDL_e7aeUiPMrbqv3z*M.eJVG!MBZcL8eD-Uq.4TDQnB9E2tensov!Adnv@V.cv3TpdcdR!C*ErsAoHbVe4WkCU.zj_jx6oTJa-qhkch@9khgjg.!7hha-Hc2Ty4gyFbz@m6g*NPvjGAw7cdN.9-s4of.NAmio2Jy2M6oc7XEkh@CTQwnqvyfTizUx!i*iRH-ZTdXc7PzdowbQYa.VLdauN8oNxtizTwLQ@j_YDB@eBmw-cRtL7!K!GPDqUpzkKQaGvwK8t!8gub4uoxDiGPced!J-9dHwtZV3ZueX6@2HWNsC4VyFb_Fv6J_g2Jj*KFzRMP.H-Uce4_KBRLC@nB6YqTVV.ua3Gs-giJBTowGUEThWCJko!TtinKM8hkU@YkV.RE4MLy*gLpvz*y@EdAdLnsn7QP@XDed8wqr96YD.jHp-!kmWG.7NGi-Y*-.G4sV.cqD3pW-PNe7nh9MNkUweo9At7Ajjab6oAdhTNw8@J_fmoCgm.tPbtuzLAa7dHrn7VPnwRJNpX*CgJjCiy4DqpJq_XbbpweGqi@wAG7mt9KMvE3eRBJbFYcQV-CTAJvkfTg9dRbXmy9t!87odiQfv4u9F-amMef_-m!fPeEqPUN6VoM*TjLTY!LA4W@9vW2!R8fVHQCV78VPw3mxsWa2M_r3osXu3XyZ_TJE3HPQtyLhFb-2VX3kYmEMgoPPYkYQsx_McQypT79dyLsRChP4u6r87ygHUHufKPusPnENHhsfb_B.fp7Em_yZKtuWW3HE_wpJLXdLM6jnw.B!78GWupLdDP8khYv@tiTVzpyJz3KNT7kV2NzTf9pGtnyqnmT-NTXCvBqzEv-YyWaoU_FA*iJQHUvcfKRuxdvR*_XWCxb4ggwQAGENZ8EkqbzZT@9frE2-LuGetCe4aC7QD3uWcdg7xnpJqbj2@PfC!JKsamEtn",
        "IdToken": "ZfKuFhtjdffejvrPHJGhHY6ndhxqZRD4feMNRnLAWDbrj6BCkCVoXx8PJsK6DCb7xCi6UBEmzsXHJwfCcREim88tcoh9wtxeRB7tsqTVX8rtCV9XzNKYTjZBBgUFY7zFqQpLJerVnjy2yPu63Kfa4fpZpdgrJGKTusVEwRxLGEgc6ebYr7DnDkbJxtTUjJfKtAitE2kk9zXLEmCtjJGqrPfCWHqayJ6imwtKuVQ2ahDtmH2Dx8mDE9Anb8XnbzqTPZJFvTgKAdEmGMVgb6WRVc3haVaUTmM7riQ9ypNCC7RQEeLoJYzFJgMktH8RYbJLvP4zwsedTjGusR2AEHJTAgmZVEueVweLZ3wJPCrtT2gxguFfZsrJbLiZ7ogmDVKX3sMjZVUiW7Dp7zcgkRG4XZFzU884FAnfaevZjJGnUrU28GuPyZRD3uhJjsXwry2tUvrmsHuXxBktB7bgYP4HEK89uUdNuGFqnHyzLpQZ6gchMiAnhN26sdjxzaCMRbusURE36bhcikrQYazpFQeW67gDsFkJNq6FUTQ4xs8q2hZhPXoYQkCGCLHmYQk8yGKJkD74pBeLiZaKKKxWspnCMUaZZzpYmHeytiNrPp2w3efdXPNuvwV2tv9T3omTvdko2DkkPrNkDfMwwtVr9zGPp3rJV7yztdAftBKjjWCNZ4vwFucsCrdnTvC33kB3fe4vGRtrrT6EcPYQiemuLevyD9bBJM7XzmEwobiPjpD9VLLRbpAGUFH4jgzqWN6JfcKjwzCdjekmJgUj2FcMrmYkxQ4YjMJAvJs4eXaLyCTENxbgxpuzUMRzancMPgknTkVA3vaRmkkDQDfYuBZRnqrCyWuCvNHxHiahsDU4zNoMF3Lk492NTMAfnWXJTwdBCY6sugZgu37PDN2gRQLLiLZqQsJTrHKUGVxigw3mssAp6kEAoJc2ec"
    }
}

IdTokenをコピーしてテスト画面の認可トークンに貼り付けてテストすると200のレスポンスが確認できます。

 

オーソライザーをAPI Gatewayのメソッドに設定します。今回は「/」パスのGETメソッドリクエストをクリックします。なお、メソッド毎にオーソライザーを設定しないとリソースパスを指定してアクセスできてしまうので注意してください。

認可の編集ボタンをクリックし、作成したオーソラザーを選択してチェックします。これでオーソライザーの設定が完了です。再度devステージにAPIのデプロイします。

エンドポイントにアクセス(オーソライザーあり)

エンドポイントにアクセスすると今度は認可されていないので表示されません。

ModHeaderなどを使ってAuthorizationヘッダーと値をセットすると認可されてアクセスできます。

さいごに

Cognitoユーザープールを使ったAPI Gatewayのアクセス制御のご紹介でした。複数のアクセス制御から利用用途にあわせて、適切なアクセス制御を使って管理していきましょう。