【新機能】AWS ELBのApplication Load Balancer(ALB)の認証機能でWebアプリにGoogle認証を追加する
ども、大瀧です。
本日、AWS ELBのApplication Load Balancer(ALB)に認証機能が追加されました。
ALBの認証機能では様々なことができるのですがCognito User Poolsや独自IdPとの連携は他のメンバーが記事を書きそうなので、本記事ではOpenID Connectの例としてGoogle Identity PlatformによるGoogleアカウント認証を設定する様子をご紹介します。
構成の概要
今回の構成図を示します。OpenID ConnectのAuthorization Code Flowに従うのですが、フローが複雑なのでALBの設定に関わるところだけざっくり解説します。
ALBへの初回(未認証)アクセスはGoogleのログイン画面にリダイレクトし、その画面でユーザーはGoogleアカウントで認証します。認証に通ると認証コードを付与して再度ALBにリダイレクトされ、その認証コードを使ってALBはGoogle APIとごにょごにょして最終的にユーザークレーム(ユーザー情報)を取得、ターゲット(EC2やECS)に転送するリクエストヘッダに付与します。クライアントにはセッションCookieを発行し、2回目以降はCookieを以て認証をスキップします。ごく一般的なフローですね。
必要なもの
- Googleアカウント
- ALBのHTTPSリスナに設定するTLS証明書(ACMでも持ち込みでも可)
ステップ1. Google Identity PlatformでのOAuth2.0 クライアントIDの発行
まずはGoogleのOpenID Providerを利用するために必要なOAuth2.0 クライアントIDを発行します。Googleアカウントでログインした状態でGoogle APIの管理コンソールにある認証情報にアクセスします。
[認証情報を作成]ボタンから「OAuthクライアントID」を選択します。
[アプリケーションの種類]では「ウェブ アプリケーション」を選択、任意の名前を設定し、承認済みのリダイレクトURIにはhttps://<ELBに設定するドメイン>/oauth2/idresponse
を入力、[作成]ボタンをクリックします。
クライアントIDとクライアントシークレットが表示されるので、コピーしておき[OK]をクリックします。
また、Google OpenID Providerの各エンドポイントは以下のURLのレスポンスとして一覧できるので、取得しておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | $ curl https: //accounts .google.com/.well-known /openid-configuration { "response_types_supported" : [ "code" , "token" , "id_token" , "code token" , "code id_token" , "token id_token" , "code token id_token" , "none" ], "subject_types_supported" : [ "public" ], "id_token_signing_alg_values_supported" : [ "RS256" ], "scopes_supported" : [ "openid" , "email" , "profile" ], "token_endpoint_auth_methods_supported" : [ "client_secret_post" , "client_secret_basic" ], "claims_supported" : [ "aud" , "email" , "email_verified" , "exp" , "family_name" , "given_name" , "iat" , "iss" , "locale" , "name" , "picture" , "sub" ], "code_challenge_methods_supported" : [ "plain" , "S256" ] } |
これでOKです。
ステップ2. ALBの設定
ステップ1の情報を元に、ALBにOpenID Connectによる認証を設定します。今回は既存のALBにHTTPSリスナを追加し、合わせて認証を有効にします。
EC2管理画面の[ロードバランサ]からALBを選択し、[リスナー]タブの「リスナーの追加」ボタンをクリックします。
リスナーの追加画面ではプロトコルを「HTTPS」、ポートはデフォルトの443番とします。デフォルトアクションの[+ アクションの追加]から「認証...」をクリックします。
[認証]では「OIDC」を選択、各項目はステップ1で確認したエンドポイントと取得したクライアントID/シークレットを貼り付けます。
画面を下にスクロールし、チェックマークをクリックして保存します。続いて再度[+ アクションの追加]から「転送先...」をクリックし、ターゲットグループを登録します。
その他、TLSのセキュリティポリシーやTLS証明書を選択し、右上の[保存]ボタンをクリックすれば設定完了です。
動作確認
では、WebブラウザからALBにアクセスしてみると...
おなじみのGoogle認証画面にリダイレクトされました!認証情報を入力すると...
ELBからターゲットのレスポンスが表示され、正常にアクセスできました。ちなみにこのURL(/dump
)ではリクエストヘッダをレスポンスにダンプするようWebアプリケーションを動作させており、ALBが付与するユーザークレームであるX-Amzn-Oidc-*
ヘッダが確認出来ますね。
JWTの検証
ターゲットに転送されるX-Amzn-Oidc-Data
ヘッダにはALBによって署名されたJWTのトークンが入るので、これをターゲット側で検証することが出来ます。検証で使う公開鍵は、以下のURLから取得出来ます。
https://public-keys.auth.elb.<リージョン名>1.amazonaws.com/<JWTヘッダのkid> |
$ curl https: //public-keys .auth.elb.ap-northeast-1.amazonaws.com /XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX -----BEGIN PUBLIC KEY----- MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEhnw6CUZ6i1mIvMx4CJmwObLc2QN81IML GDFqjFwet /7e9HDFFPG8I9/PSK4pVG6CZtt2m1bXAyOuwo +5xZPTGw== -----END PUBLIC KEY----- |
では、jwt.ioで検証してみます。Encodedにトークンをペーストするとデコードされたヘッダおよびペイロード(ユーザークレーム)が確認できます。
さらに[VERIFY SIGNATURE]の1つ目のテキストエリアに公開鍵をペーストすると「Signature Verified」と表示され、検証できました!
ELBのログ
ALBのアクセスログはS3に格納されます。今回の認証に係るログは以下のようになりました。
1 2 3 4 | h2 2018-05-31T04:59:51.812260Z app/<ALB名>/XXXXXXXXXXXXXXXX <リモートIP>:57497 - -1 -1 -1 302 - 206 543 "GET https://<ドメイン名>:443/dump HTTP/2.0" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 - "Root=1-XXXXXXXX-XXXXXXXXXXXXXXXX" "<ドメイン名>" "arn:aws:acm:ap-northeast-1:<アカウントID>:certificate/bef10a17-abf3-4aa1-a8fb-76416f9de10f" 0 2018-05-31T04:59:51.811000Z "authenticate" h2 2018-05-31T05:03:42.955191Z app/<ALB名>/XXXXXXXXXXXXXXXX <リモートIP>:57745 - -1 -1 -1 302 - 552 986 "GET https://<ドメイン名>:443/oauth2/idpresponse?state=XXXXXXXXXXXXXXXX&code=XXXXXXXXXXXXXXXX&authuser=0&session_state=XXXXXXXXXXXXXXXX&prompt=none HTTP/2.0" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 - "Root=1-5b0f822e-5824a8c6c44fa81b0da2cb48" "<ドメイン名>" "session-reused" -1 2018-05-31T05:03:42.459000Z "authenticate" h2 2018-05-31T05:03:42.992511Z app/<ALB名>/XXXXXXXXXXXXXXXX <リモートIP>:57745 <ターゲットのIP>:32771 0.001 0.003 0.000 200 200 718 1691 "GET https://<ドメイン名>:443/dump HTTP/2.0" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 arn:aws:elasticloadbalancing:ap-northeast-1:<アカウントID>:targetgroup/tg0/XXXXXXXXXXXXXXXX "Root=1-XXXXXXXX-XXXXXXXXXXXXXXXX" "<ドメイン名>" "session-reused" 0 2018-05-31T05:03:42.988000Z "authenticate,forward" h2 2018-05-31T05:03:43.121961Z app/<ALB名>/XXXXXXXXXXXXXXXX <リモートIP>:57745 <ターゲットのIP>:32771 0.001 0.003 0.000 404 404 19 120 "GET https://cdn-ssl-devio-img.classmethod.jp/wp-content/uploads/2016/02/favicon.ico HTTP/2.0" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 arn:aws:elasticloadbalancing:ap-northeast-1:<アカウントID>:targetgroup/tg0/XXXXXXXXXXXXXXXX "Root=1-XXXXXXXX-XXXXXXXXXXXXXXXX" "<ドメイン名>" "session-reused" 0 2018-05-31T05:03:43.117000Z "authenticate,forward" |
1,2行目が初回の認証周り、3,4行目はターゲットへの転送にかかるログですね。
まとめ
Application Load Balancer(ALB)の認証機能のひとつ、OpenID Connect連携の例としてWebアプリにGoogle認証をかける様子をご紹介しました。既存のWebアプリケーションに手軽にアクセス制限をかけられる、ナイス機能だと思います。ALBによるWebアプリケーションの構築に役立ててください。