🚀

【初心者向け】ALB・Cognito連携をCloudFormationで作ってみる

2024/09/21に公開

はじめに

こちらの記事で実装したALBとCognitoをCloudFormationで連携する方法をまとめます。
掲載しているCloudFormationテンプレートのファイルはこちらから確認できます。


赤枠部分の内容になります

対象読者

  • ALBとCognitoを連携させたい人
  • CloudFormationで実現させたい人

前提条件

  • Route53のパブリックホストゾーンを作成済み
  • ACMでSSL証明書を取得済み
  • ALB、Cognitoについての基礎的な知識を習得済み
  • CloudFormationの基礎的な構文を理解できる方

手順

1. Cognitoユーザープールの作成

ユーザープールの作成

AWSTemplateFormatVersion: 2010-09-09

Resources:
  # ユーザープール作成
  UserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      UserPoolName: test # ユーザープール名
      UsernameAttributes:
        - email # Eメールでのサインインを有効化する場合はemailを指定
      AccountRecoverySetting: # ユーザーがパスワードを忘れた場合の対処
        RecoveryMechanisms:
          - Name: verified_email
            Priority: 1
      EmailConfiguration:
        EmailSendingAccount: COGNITO_DEFAULT
      MfaConfiguration: 'ON' # MFAの有効化設定
      EnabledMfas:
        - SOFTWARE_TOKEN_MFA # アプリケーションでのMFA
      AutoVerifiedAttributes:
        - email
    UpdateReplacePolicy: Retain
    DeletionPolicy: Delete

今回はeメールアドレスでのユーザー作成にしております。
電話番号でのユーザー登録の場合はUsernameAttributesphone_numberを設定してください。

ユーザープールドメイン

# ユーザープールドメイン作成(Cognitoドメインを作成)
  UserPoolDomain:
    Type: AWS::Cognito::UserPoolDomain
    Properties:
      Domain: bedrock-1234 # ドメイン名は各自で自由に設定してください
      UserPoolId: !Ref UserPool

アプリクライアント

 # ユーザープールにアプリクライアントを作成
  UserPoolClient:
    Type: AWS::Cognito::UserPoolClient
    Properties:
      ClientName: test-app-client
      GenerateSecret: true # クライアントシークレット
      RefreshTokenValidity: 30
      CallbackURLs: # コールバックURL。Route53で取得したFQDN + /oauth2/idpresponseを入力する。
        - https://hogehoge.com/oauth2/idpresponse
      ExplicitAuthFlows:
        - ALLOW_ADMIN_USER_PASSWORD_AUTH
        - ALLOW_USER_SRP_AUTH
        - ALLOW_REFRESH_TOKEN_AUTH
      UserPoolId: !Ref UserPool
      SupportedIdentityProviders:
        - COGNITO
      AllowedOAuthFlows:
        - code
      AllowedOAuthFlowsUserPoolClient: true
      AllowedOAuthScopes:
        - openid
        - email
        - phone

Outputs:
  UserPool:
    Value: !GetAtt UserPool.Arn
    Export:
      Name: user-pool-arn
  UserPoolClient:
    Value: !GetAtt UserPoolClient.ClientId
    Export:
      Name: user-pool-client-id
  UserPoolDomain:
    Value: !GetAtt UserPoolDomain.CloudFrontDistribution
    Export:
      Name: user-pool-domain

CallbackURLsには、ユーザーがログインする際にコールバックされるドメイン名を記述します。
Route53でhogehoge.comというパブリックホストゾーンを取得している場合、https://hogehoge.com/oath2/idpresponseというドメイン名を記載します。

2. ALBのリスナールールの変更

次に、ALBのリスナーにCognito認証を設定します。これにより、ALBにアクセスしたユーザーは、Cognitoのログインページにリダイレクトされ、認証後にアクセスが許可されます。

# Listener
  ALBListenerHTTPS:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref ALB
      Port: 443
      Protocol: HTTPS
      Certificates:
        - CertificateArn: !Ref ACMCertificateArn
      SslPolicy: !Ref ELBSecurityPolicy
      DefaultActions:
        # Cognitoへのルーティング
        - AuthenticateCognitoConfig: 
              UserPoolArn: { Fn::ImportValue: user-pool-arn }
              UserPoolClientId: { Fn::ImportValue: user-pool-client-id }
              UserPoolDomain: bedrock-1234
              OnUnauthenticatedRequest: authenticate
          Order: 1
          Type: "authenticate-cognito"
        # ターゲットグループへのルーティング
        - TargetGroupArn: !Ref TargetGroupResource
          Order: 2
          Type: forward
  • Type: authenticate-cognito : ALBリスナーの認証方式としてCognitoを指定しています。
  • UserPoolArn : CognitoユーザープールのARNです。!GetAttを使ってCognitoユーザープールのARNを取得します。
  • UserPoolClientId : CognitoクライアントIDを指定します。
  • UserPoolDomain : Cognitoのドメインを指定します。
  • OnUnauthenticatedRequest: authenticate : 未認証のリクエストがあった場合にCognitoで認証を行うよう指定します。
  • forward : 認証が成功した場合、リクエストをターゲットグループに転送します。

3. 動作確認

CloudFormationよりスタックを作成後、パブリックホストゾーンに登録した
FQDNにブラウザよりアクセスします。以下のSign in画面が表示されれば成功です。

Sign in

ユーザーが未作成であるため、Sign upのリンクをクリックして、eメールアドレスとパスワードを設定して、ユーザーを作成します。

Sign up

eメール検証を設定しているため、設定したeメールアドレス宛に転送されたコードを
確認して入力します。

多要素認証を有効化しているため、Authenticatorアプリに登録し、多要素認証を設定します。

まとめ

今回はCloudFormationを用いてALB + Cognito連携を実装しました。
CloudFormationの場合、クロススタックで実装していかないとファイルが大きくなりすぎて
管理が煩雑になるように感じました。
連携する際に必要となるパラメータ情報を調査するのにかなり時間がかかってしまったので、
同じようなところで躓いた方のサポートになれば幸いです。
今後はTerraformでも同様の連携機能を実現していきたいと思います。

Discussion