Cognito認証後にAPI Gatewayでクライアント証明書認証してみた

目的・やりたいこと

提案はcognitoを使ったauthenticator or SMS認証で提案していた
お客様では2要素認証の要素としてクライアント証明書での認証を想定しているが、お客様で一旦持ち帰り
内部でクライアント証明書認証を検証する

  • 現在の想定
    Cognitoでの認証 → Lambda → AppStreamのstackのURL発行

  • クライアント証明書による二要素認証の実現
    API Gateway + クライアント証明書での二要素認証 → Cognitoでの認証 → Lambda → AppStreamのstackのURL発行

CognitoのMFA機能ではクライアント証明書認証に対応していません。
https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/user-pool-settings-mfa.html
なので、Cognitoのユーザー認証+API Gatewayのクライアント認証は別物として実装するイメージ

①cognitoでuser / passwordで認証
②認証を突破できたらAPI Gatewayにアクセス
API Gatewayはクライアント証明書が入った端末からのみ接続が可能

③は参考サイトがあったので簡単にできたが、問題はどうやって①でログイン認証を行わせるか、そしてその①と③の両者をどうやって連携させるかで悩んだ。

 対象となる技術

  • Cognitoログイン
  • API Gateway
  • クライアント証明書

 条件(導入にあたって前提事項)

  • Cognitoドメインを作成する関係上、独自ドメインをあらかじめ取得しておく必要があります。ドメインは取るだけで十分です。ネームサーバの移管とかはいりません。自分はnozaki3.comを2つ目だったのでお名前.comで940円で自腹ゲットしました
  • また、API Gatewayでカスタムドメイン名を作成するので、もう一つ独自ドメインを取得しておく必要があります。そのドメインに対し、ACM証明書も必要になります。
  • クライアント証明書も必要になります。具体的な取得方法は参考URL2番目に記載してあります。

 参考URL

作業の流れ

 概要図

 事前作業

③のクライアント証明書認証API Gatewayを先に作成しておきます。
これは参考URL2番目が大いに参考になりましたので、詳しくはそちらを参照してください。
ただし、条件でも触れたように、カスタムドメインを作成しておく必要があります。
1.[カスタムドメイン名] > [作成]で以下の画面になります。

2.ドメイン名は実際に取得したドメインを入れる必要があります。
[相互TLS認証]にチェックを入れると、その下の[トラストストアURI]を入れる必要があります。
これはクライアント証明書で用いたCA証明書をpem形式に変換して、S3のどこかに置いてください。
ちなみに自分は以下コマンドでcerファイルをpem形式に変換しました。

$ openssl x509 -inform der -in ca.cer -out ca.pem

3.エンドポイント設定ではデフォルトの[リージョン]にしました。[エッジ最適化]を選ぶとCloudFrontを使うようです。
ACM証明書もいるので用意しておいてください。

4.カスタムドメイン名「https://aws-test-dk.com/」を作成し、クライアント証明書「client_certificate.pem」を用意しても、Macだとどうしても以下エラーが出るときがあります。

curl -E ./client_certificate.pem https://aws-test-dk.com/
curl: (58) unable to set private key file: './client_certificate.pem' type PEM

解決策としては以下のサイトが参考になりました。
2014-03-26:curl: (58) unable to set private key file

秘密鍵とクライアント証明書とCA証明書をばらばらにしてやったら上手くいったよ!」というのを発見。
これをヒントに .pem を作り直してやってみる。
$ openssl pkcs12 -in hoge.p12 -out client.pem -clcerts

$ openssl pkcs12 -in client_certificate.pfx -out client.pem -clcerts
Enter Import Password:
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

$ curl -E ./client.pem https://aws-test-dk.com/
Enter PEM pass phrase:
{"message":"Forbidden"}

アクセス先を作り込んでいないので、{"message":"Forbidden"}と出るのがここでは正解です。

次に①のcognitoでユーザー/パスワード認証画面を用意します。
これが苦労しました。Cognitoのログイン画面の作り方とかあまり載っておらず、かつログイン後に②API Gatewayに遷移しないといけないので、ここの作り込みをどうするかと
実はぴったりの参考サイトがあり、「参考URL」の1番目が役に立ちました。ユーザープールの作成手順からしてかなり細かく記載されています。その中でもいくつか以下に注意ポイントをピックアップします。

  • [アプリケーションを統合]の[ドメイン]でCognitoドメインを指定します。自分は「nozaki3.com」を取得して設定を入れました。Cognitoドメインの場合は.comドメインでないといけないようです。

  • ホストされたUIのコールバックURLの指定
    参考URLには「「許可されているコールバックURL」にhttp://localhostと入力しましょう。」とあるのですが、これを入れるとCognito認証後にhttp://localhostに飛ばされてしまいます。本件の要件はAPI Gatewayに飛ばすことなので、自分はAPI Gatewayの時に設定したカスタムドメイン名のURL(https://aws-test-dk.com/ )を入れるようにしたところ、意図通りCognito認証後にカスタムドメインAPI Gatewayに飛べるようになりました!

     

  • IDプールの作成は不要です。

  • あとはどうやってCognitoのログイン画面を出すかですが、[ホストされたUI]の右上に[ホストされたUIを表示]というボタンがあり、これをクリックすることで例のログイン画面に飛べました!

    1.クライアントIDを確認したのと同じ手順で、作成したユーザープールの詳細画面にアクセスして、「アプリケーションの統合」タブを開きます
    2.「アプリケーションクライアント名」に表示されているアプリケーションクライアントをクリックし、詳細画面を開きます
    3.「ホストされたUI」の「ホストされたUIを表示」をクリックします。するとサインイン画面が表示されます。「Sign Up」をクリックします

 検証手順

上記で設定した一連の手順①〜③を実行します。
1.https://nozaki3.auth.ap-northeast-1.amazoncognito.com/oauth2/authorize?client_id=5t34guugi6o4bdlreki9s41s8n&response_type=code&scope=aws.cognito.signin.user.admin&redirect_uri=https%3A%2F%2Faws-test-dk.com%2F
にアクセス

2.サインインのダイアログが出るので、アカウントを入力

3.証明書の選択画面が出るので、適切なクライアント証明書を選択

4.「{"message":"Forbidden"}」と出ればOKです。

 所要時間

1時間(①30分、③30分)

 ユースケース

Cognitoのユーザ認証+API Gatewayのクライアント認証で2要素認証したい場合