株式会社ダイアログ Tech Blog

株式会社ダイアログのエンジニアチームが運営しています。

【Amplify】 APIGatewayのAuthorizerにCognitoを指定する

概要

AmplifyでOverride機能を利用してAPIGatewayのAuthorizerにCognitoを指定する方法をご紹介します。

課題

2022/3/10現在、Amplify CLIでは、APIGatewayのAuthorizerにIAMしか利用できません。AWSのコンソールからCognitoを指定したとしても更新した際にテンプレートで上書きされてしまい、設定したAuthorizerの情報が消えてしまいます。 そのため、Override機能を利用してAPIのCFnテンプレートを修正する必要があります。

手順

APIGateway・Cognitoのoverride.ts作成

CLIで以下のコマンドを実行し、override.tsを作成します

amplify override auth
amplify override api

override.tsの編集

Authでは、CognitoユーザープールのIDをエクスポートします。 エクスポート名は重複が許されないため、環境名を取得してユニークにしています。しかし、デフォルトではバグで取得できないため迂回しています。詳細は以下の記事をご覧ください。 Amplifyのoverride.tsで環境名を取得する

import { AmplifyAuthCognitoStackTemplate } from '@aws-amplify/cli-extensibility-helper';

export function override(resources: AmplifyAuthCognitoStackTemplate) {
  // override.tsでenv名を参照することはできない(バグ)。そのためamplify-metaからenv名を取得している
  // https://github.com/aws-amplify/amplify-cli/issues/9063
  const amplify_meta_json = require('amplify-meta.json')
  const env_name = amplify_meta_json.providers.awscloudformation.StackName.split("-").slice(-2, -1).pop()
  const export_user_pool_id = {
      description: "cognito user pool id",
      value: resources.userPool.ref,
      exportName: `exportUserPoolId-${env_name}`
  }
  resources.addCfnOutput(export_user_pool_id, "AuthCognitoUserPoolId")
}

AuthでエクスポートしたユーザープールIDを利用してAuthorizerを設定します。

import { AmplifyApiRestResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';

export function override(resources: AmplifyApiRestResourceStackTemplate) {
  const amplify_meta_json = require('amplify-meta.json')
  const env_name = amplify_meta_json.providers.awscloudformation.StackName.split("-").slice(-2, -1).pop()
  resources.restApi.body = {
    ...resources.restApi.body,
    "securityDefinitions": {
      "sigv4": {
        "type": "apiKey",
        "name": "Authorization",
        "in": "header",
        "x-amazon-apigateway-authtype": "awsSigv4"
      },
      "Cognito": {
        "type": "apiKey",
        "name": "Authorization",
        "in": "header",
        "x-amazon-apigateway-authtype": "cognito_user_pools",
        "x-amazon-apigateway-authorizer": {
          "type": "cognito_user_pools",
          "providerARNs": [
            {
              "Fn::Join": [
                "",
                [
                  "arn:aws:cognito-idp:",
                  {
                    "Ref": "AWS::Region"
                  },
                  ":",
                  {
                    "Ref": "AWS::AccountId"
                  },
                  ":userpool/",
                  {
                    "Fn::ImportValue": `exportUserPoolId-${env_name}`
                  }
                ]
              ]
            }
          ]
        }
      }
    },
  }

  //Authorizerはリソースの各メソッドに設定する必要がある
  let paths = resources.restApi.body.paths
  Object.keys(paths).forEach((key) => {
    let path = paths[key]["x-amazon-apigateway-any-method"]
    path.parameters = [
      ...path.parameters,
      {
        name: "Authorization",
        in: "header",
        required: false,
        type: "string"
      }
    ]
    path.security = [
      {
        "Cognito": []
      }
    ]
  });
}

まとめ

上記設定でAuthorizerにCognitoを使用することができます。 AmplifyのOverride用ヘルパーの情報が少なく、記載方法にとまどいましたのでどなたかの参考になれば幸いです。