ALB + Cognito で作るユーザー認証

11月 8, 2021ACM,AWS,Azure,Cognito,ELB

概要

はじめに

  • Webアプリケーションのセキュリティ対策として、不正アクセスを防御することは必要です。不正アクセスの防御には、WAF(Web Application Firewall)やIPフィルターなどを使用する方法もありますが、今回はALB(Application Load Balancer)にユーザー認証を実装する方法を紹介します。
  • AWSドキュメントによれば、ALB のユーザー認証は、OIDC(OpenID Connect)準拠の外部ID プロバイダー(IdP)を利用するパターンと、Cognito のユーザープールを利用するパターンがあります。今回は、後者のALBにCognito のユーザープールを利用したユーザー認証を実装します。
  • 上記の他に、ユーザー認証には、IDaaS(例: Auth0、Okta、OneLogin)を利用する方法やLambdaなど独自で実装する方法がありますが、Cognitoを利用することで手軽にユーザー認証が実装できます。

 

Cognito とは

  • Amazon Cognito は、API ベースで実装されるWebアプリ、モバイルアプリに認証機能を提供します。ユーザーは、ユーザー名とパスワードを使用して直接サインインするか、Facebook、Amazon、Google、Apple などのサードパーティーを通じてサインインできます。
  • Cognito には、ユーザープール ID プールの機能があります。
    • ユーザープールは、Amazon Cognito のユーザーディレクトリです。独自のユーザーディレクトリ or 外部ID プロバイダー(IdP)経由のログインに基づき、アプリへアクセスするためのトークンを提供します。
    • ID プールは、Cognito ユーザープール or 外部ID プロバイダー(IdP)経由のログインに基づき、AWS のサービスにアクセスするための一時的な AWS 認証情報を提供します。

 

ALB + Cognito でBasic認証ライクな認証を構築する

システム構成

  • 今回作成する構成は、以下となります。独自で認証機能を実装する場合、Lambda、Database など組み合わせ、認証機能の開発が必要になりますが、ALB + Cognito を利用すれば、以下の通りシンプルな構成で実現可能です。

 

ALB を準備する

  • 先ず、ALB/EC2 を準備します。 ALB はinternet-facing にて作成し、HTTPS のリスナー作成およびSSL証明書を設定します。バックエンドはEC2 でなくとも構いません。

 

  • 次に、ALB の名前解決のため、Route 53 にレコード登録を行います。DNSレコードの登録は、レコードタイプ “Aレコード" かつ “ALIAS" を選択します。レコードタイプにCNAME を指定した場合は、後続のCognito 独自ドメインの利用に支障があります。詳細は後述します。
  • 最後に、WebブラウザからWebサーバーにアクセスできることを確認します。以下の例では、ALBのDNSに"niikawa-test.example.com" のFQDNを使用しています。アクセスした結果、テスト用に準備した"Hello World" が表示されました。

 

  • ALB作成やACM 証明書発行の具体的な手順は、下記記事を参照ください。

 

 

Cognito のユーザープールを作成する

  • Amazon Cognito のコンソールにアクセスし、「ユーザープールの管理」を選択します。

 

  • 次に、「ユーザープールを作成する」を選択します。

 

  • ユーザープールの「プール名」を入力します。ユーザープールの作成方法は、「デフォルトを確認する」を選択します。

 

  • 設定値を確認し、「プールの作成」を押します。なお、「属性」で設定するサインインオプション、属性オプションは、プール作成後は変更できません。ユーザープール作成前に、サインインに関する設定が目的に合致することを確認しましょう。
  • また、ユーザーにサインアップさせるのではなく、管理者の作成を必須とする場合、ユーザーのサインアップを許可する設定に「管理者のみにユーザーの作成を許可する」を選択します。
  • 以下の通り、ユーザープールが作成されました。

 

サインインページに独自ドメインを設定する

独自ドメインの設定

  • 事前に、ACM のバージニア北部のリージョンにSSL証明書の作成が必要です。
  • ユーザープール作成後、Cognitoのサインインページに独自ドメインを設定します。「アプリの統合」→「ドメイン名」を選択します。
  • 「ドメインの使用」ボタンを押します。ドメイン名、ACM の証明書を指定し、「変更の保存」ボタンを押します。以下は、「変更の保存」ボタンを押した後の画面です。

 

  • 数分経過後に、「CREATING」の右にあるアイコンをクリックし、再読み込みを行います。ドメインのステータスが ACTIVE に変わりました。以下は、ACTIVE に変わった後の画面です。
  • 画面下部に表示されているエイリアスターゲットの DNS名を使用し、Route 53 にCNAME のレコードを登録します。

 

注意事項

  • サインインページに独自ドメインを設定する際に注意事項があります。サインインページに割り当てる独自ドメインには、サブドメインを作成して割り当てることです。例えば、ALBに割り当てたFQDNが “niikawa-test.example.com" の場合、サインインのページは、"auth.niikawa-test.example.com" を割り当てます。理由は、下記ドキュメントに記載の通り、DNS には“Aレコード" が設定されている必須条件があります。そのため、事前準備で登録したALB のDNS に、レコードタイプ “Aレコード" かつ “ALIAS" を選択した理由はこの必須条件を解消するためです。

引用元: Amazon Cognito Developer Guide

  • A web domain that you own. Its root must have a valid A record in DNS. For more information see Domain Names.
  • The ability to create a subdomain for your custom domain. We recommend using auth as the subdomain. For example: auth.example.com.
  • もしドメインを設定する際に、DNSにAレコードが設定されていなければ、下記のエラーメッセージが表示されます。
    • Custom domain is not a valid subdomain. Was not able to resolve the root domain. please ensure an A record exists for the root domain.

 

ユーザープールにアプリクライアントを作成する

  • ALB にアクセス権限を提供するため、ユーザープールにアプリクライアントを作成します。「アプリクライアント名」を入力し、「アプリクライアントの作成」ボタンを押します。

 

  • アプリクライアント ID が表示されました。

 

アプリクライアントを設定する

  • ID プロバイダを選択します。
  • コールバック URLには、パス「/oauth2/idpresponse」の付加が必要になります。今回は、サインアウト URLは指定しません。
  • OAuth フローには、「Authorization code grant」、OAuth スコープには、「openid」を選択します。
  • 「変更の保存」を押します。

 

ALB のリスナールールに認証を設定する

  • ALB を選択し、リスナータブを開きます。対象リスナーの「ルールの表示/編集」を選択します。

  • 編集のマークを選択し、ルールの編集を行います。ルールのTHEN に登録されている既存の転送先は、削除します。

  • ルールのTHEN にて「アクションの追加」→「認証…」を押します。
  • 「認証」に「Amazon Cognito」、「Cognito ユーザープール」に作成済みのユーザープールのプール ID、「アプリクライアント」に作成済みのアプリクライアントのアプリクライアント ID を選択します。

  • 「転送先」にターゲットグループを選択します。「更新」ボタンを押します。

注意事項

  • ユーザープールに独自ドメインが設定されていなければ、リスナールールに認証が選択できません。また、同様にユーザープールにアプリクライアントが設定されていなければ、リスナールールに認証が選択できません。

 

  • アプリクライアントの設定がされていなければ、リスナールールの更新時に下記のエラーが表示されます。前述のアプリクライアントの設定において、ID プロバイダ、コールバック URL、OAuth フローおよびスコープを設定します。
    • OAuth flows must be enabled in the user pool client

 

アクセス確認

  • ALBに割り当てたFQDN(例: https://niikawa-test.example.com/)へのアクセスを確認します。以下サインインの画面が表示されれば成功です。

 

注意事項

  • 500 Internal Server Error」が表示された場合、Cognitoのサインインページに設定した独自ドメインのDNS名が未だレコード登録されていないかもしれません。「アプリ統合」→「ドメイン名」にてエイリアスターゲットの DNS名を確認し、CNAME のレコードを登録します。

 

  • An error was encountered with the requested page.」のエラーが表示された場合、アプリクライアントの設定において、コールバック URLのパスに誤りがある可能性があります。前述のアプリクライアントの設定において、コールバック URLにパス「/oauth2/idpresponse」が付加されていることを確認します。

 

 

Cognito ユーザープールのユーザー作成方法

  • 先の手順で作成したユーザープールにユーザーを作成します。ユーザー作成は、「ユーザーの作成」or「ユーザーをインポート」のどちらかで行います。

 

個別にユーザーを作る手順

  • 「ユーザーの作成」を押し、個別にユーザーを作成します。ユーザー名、仮パスワード、E メールなどを指定します。

 

  • 指定したE メールのアドレスに、仮パスワードが送信されました。

 

 

  • ALBに割り当てたFQDN(例: https://niikawa-test.example.com/)へアクセスします。パスワードを変更します。

 

  • 無事に認証をpassし、テスト用のWebにアクセス確認が出来ました。

 

まとめてユーザーをインポートする手順

  • 「ユーザーをインポート」を押し、まとめてユーザーをインポートします。先ず、「CSV ヘッダーのダウンロード」を押し、テンプレートをダウンロードします。

 

  • 次に、CSV ファイルにユーザー情報を記入します。以下は、最低限の情報を記入した CSV のサンプルです。
name,given_name,family_name,middle_name,nickname,preferred_username,profile,picture,website,email,email_verified,gender,birthdate,zoneinfo,locale,phone_number,phone_number_verified,address,updated_at,cognito:mfa_enabled,cognito:username
,,,,,,,,,niikawa@example.com,TRUE,,,,,,FALSE,,,FALSE,niikawa

 

  • 次に、「インポートジョブの作成」を選択します。「ジョブ名」を入力し、IAM 名を指定します。(初回実行の場合はIAM のロール名を指定し、2回目以降の場合はIAM ロールを選択する)
  • 先ほど作成したCSV ファイルをアップロードします。最後に、「ジョブを作成する」を押します。

 

  • ジョブのステータスが「Created」になります。右端のメッセージにある「開始」を押します。次に、ジョブのステータスが「Pending」に変わるため、再読み込みのアイコンを押します。
  • ジョブのステータス「Succeeded」に変わり、右端のメッセージに「Import Job Completed Successfully.」が表示されれば成功です。

 

  • インポートがFailed となった場合は、CSV ファイルを修正します。エラーの理由は、CloudWatch Logs にて確認可能です。(以下の画面は、成功時のログとなります)
  • 例えば、CSV ファイルのファイル名を変更すると「The header in the CSV file does not match the expected headers. Use the GetCSVHeader API to get the expected headers.」のエラーとなります。ファイル名は、デフォルトの “headers.csv" を使用します。

 

  • インポートが完了しました。以下の通り、インポートジョブで作成されたユーザは、アカウントのステータスが「RESET_REQUIRED 」になります。

 

  • ALBに割り当てたFQDN(例: https://niikawa-test.example.com/)へアクセスします。ユーザーのログイン時に「Forgot my password」を押し、ユーザ名を入力後、「Reset my password」を押します。

 

  • メールに通知されたreset code を入力し、パスワードを設定します。

 

  • 無事に認証をpassし、テスト用のWebにアクセス確認が出来ました。

  • 上記方法であれば、管理者が複数ユーザーの初期パスワードを設定する必要なく、ユーザーは利用できます。

 

その他

  • サインインページのUI をカスタマイズすることも可能です。色々とお試しください。

 

参考資料

ACM,AWS,Azure,Cognito,ELB

Posted by takaaki