技術

ServerlessFrameworkでCognitoをセットアップ

AWS Cognitoについて、まとめました。

Cognitoの使い所

Cognitoはユーザ認証ができる、AWSのマネージドサービスです。

WebアプリやAPIのユーザ認証などに使えます。手軽に導入できて、運用もユーザー名とemailを登録するだけなので運用コストも低いです。GUIで管理出来てSESとも連係できるので便利です。

最近の新規プロジェクトでは、認証部分をAmazon Cognitoでやることが多いです。

Cognitoの設定方法

Cognitoの導入方法や設定、管理方法はいろいろあります。

  • 手動 (AWSコンソール)
  • Terraform
  • AWS CDK
  • Serverless Framework

などなど。

Cognitoは一度設定してしまえば、設定変更することはほとんどありませんし、導入時も設定作業はそれほど多くないので手動でやってしまってもいいかと思います。

私はAPI Gatewayと同時に入れることが多いので、Serverless Frameworkでやることが多いです。

以下は、Serverless Frameworkでやる場合についてです。

Serverless Frameworkで設定する場合

考慮するべき点1 設定ファイルはAPIと分けるか?

Serverless Frameworkでやる場合、考えるべきポイントの1つに設定ファイルをメインと切り分けるかどうかというポイントがあります。

Serverless Frameworkは、deployコマンド実行時に –configオプションで設定ファイルを指定することができるので、設定をファイルを分けることができます。

–configオプションなしだと、serverless.ymlが設定ファイルとして読み込まれます。

serverless.ymlはメインとなるAPI GatewayやLambda関数などが設定することがほとんどです。Cognitoの設定変更はほとんどないので、APIをdeployする度にCoginitoのdeployを走らせたくありません。なので、できれば設定ファイルは、メインのserverless.ymlとは分けたいところです。

ちなみにですが、私はDynamoDBもServerless Frameworkで設定することが多いですが、こちらはAPI Gatewayと設定ファイルを分けています。

ただ、以下の理由から設定ファイルはAPI Gatewayと一緒にした方が良いです。

  • Cgnito IDとRest IDが相互参照できる
  • LambdaにトリガーにCognitoを設定できる

設定を分けると、これらのことができません。

CognitoやAPI Gatewayは作成時にIDが発行されます。LambdaでCognitoIDを参照したり、CognitoでAPI Gatewayを参照したいことがありますが、設定ファイルを分けるとそれができません。

deploy完了後に、configファイルなど作成して手動で書き込み、そのファイルを読み込んだり、Serverless Frameworkの設定ファイルを更新して再度deployを走らせる必要があります。

設定ファイルが一つだと、CognitoIDを環境変数などにセットできるので、このconfigファイルを手動で管理する必要がなくなります。

ただ、これは初回deploy時のみに必要なことなので、たいした問題でありません。

問題なのは、2番目のLambdaのトリガーにCognitoをセットすることができないことです。もちろん、deploy後にLambdaのコンソールから手動でセットはできるのですが、この設定はdeployの度に消えてしまいます。別途、deploy時にトリガーをセットするシェルスクリプトを実行するような仕組みが必要になります。

これが以外と面倒です。ここまでやるなら、最初から設定ファイルを一つにして、Serverless Framework内でやってしまうほうが良いです。

考慮するべき点2 TypeScriptで書くか、Yamlで書くか?

昔はServerless Frameworkの設定ファイルはYAMLだけだったのですが、今はtsファイルでも書くことができます。

これはどちらで書いてもいいと思います。

TSファイルのほうが管理しやすかったり可読性が高いですが、それだけのためにTypeScript環境を用意する必要はないでしょう。

TypeScriptのプロジェクトならtsファイルで、それ以外でYAMLでやって良いかと思います。

設定例

以下は、ごくシンプルな構成のCognitoをServerless Framewokでやる場合のサンプルです。

Cognitoの設定そのものは、メインとは別ファイルに切り出しします。

serverless-cognito-sample.yml

Resources:
  SampleUserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      AdminCreateUserConfig:
        AllowAdminCreateUserOnly: false
        InviteMessageTemplate:
          EmailMessage: 'Your name is {username} and temporary password is {####}.'
          EmailSubject: 'Your temporary password'
      UsernameAttributes:
        - email
      AutoVerifiedAttributes:
        - email
      EmailConfiguration:
        EmailSendingAccount: COGNITO_DEFAULT
      EmailVerificationMessage: "Your verification code is {####}"
      EmailVerificationSubject: "Your verification code"
      MfaConfiguration: "OFF"
      Policies:
        PasswordPolicy:
          MinimumLength: 8
          RequireLowercase: false
          RequireNumbers: false
          RequireSymbols: false
          RequireUppercase: false
          TemporaryPasswordValidityDays: 30
      UsernameConfiguration:
        CaseSensitive: false
      UserPoolAddOns:
        AdvancedSecurityMode: AUDIT
      UserPoolName: 'SampleUserPool'

  SamplePoolUserPoolClient:
    Type: AWS::Cognito::UserPoolClient
    Properties:
      ClientName: 'SampleUserPoolClient'
      ExplicitAuthFlows:
        - ALLOW_USER_PASSWORD_AUTH
        - ALLOW_ADMIN_USER_PASSWORD_AUTH
        - ALLOW_USER_SRP_AUTH
        - ALLOW_REFRESH_TOKEN_AUTH
      GenerateSecret: false
      LogoutURLs:
        - "http://localhost:3000"
      PreventUserExistenceErrors: ENABLED
      ReadAttributes:
        - email
        - name
      RefreshTokenValidity: 10
      SupportedIdentityProviders:
        - COGNITO
      UserPoolId:
        Ref: SampleUserPool
      WriteAttributes:
        - email
        - name

こちらは最低限の設定です。API GatewayのAuthorizerとして使いたい場合は、別途 Type: AWS::ApiGateway::Authorizer のResourcesを追加する必要があります。

このCognitoの設定ファイルをメインのserverless.ymlの方で呼ぶようにします。resourcesの箇所に以下の様に記載すれば呼び出すことができます。

resources:
  # cognito
  - ${file(./serverless-cognito-sample.yml)}

また、以下の様に書けば、CognitoIDをLambda関数の環境変数にセットすることができます.

environment:
  COGNITO_POOL_ID_SAMPLE: ${self:custom.CognitoUserPoolId.sample}

custom:
  CognitoUserPoolId:
    sample:
      Ref: SampleUserPool

まとめ

以上、Serverless FrameworkでCognitoをセットアップする場合についてでした。