ALBのmTLSによるクライアント証明書の検証とAWS WAFの動作順序を調べてみた

ALBのmTLSによるクライアント証明書の検証とAWS WAFの動作順序を調べてみた

Clock Icon2025.02.15

はじめに

mTLS(相互認証)を有効化し、AWS WAFを関連付けたALBにおいて、正しいクライアント証明書を持たないユーザーからのアクセスがAWS WAFまで到達するのか気になったので検証してみました。

また、AWS WAFの配置位置についても、ALBの前段ではなくALB後段で検証が行われることを確認したいと思います。

想定している挙動を図にしました。
Group 2040

おそらく間違っているだろうと思われる挙動も図にしてみました。
Group 2041

それではやってみます。

先に結論

先に結論を書きます。
検証の結果、以下が確認できました

  • クライアント証明書なしのアクセスはALBのmTLS認証で失敗
  • 認証失敗したリクエストはAWS WAFまで到達しない

最初に書いた図だと、想像していた挙動の図ですね。
Group 2040

準備

検証用のALBは以下の設定としています

  • mTLSを有効化
  • mTLSは検証モード
  • 認証成功時は固定レスポンスを返す

AWS WAFはリクエストを検証するルールとして、マネージドルールのAWSManagedRulesAmazonIpReputationListを設定しています。

クライアント証明書を持たないユーザーでALBへリクエスト送信

まずは正しいクライアント証明書を持たないユーザーでアクセスしてみます。

$ curl https://hogehoge.com
curl: (35) Recv failure: Connection reset by peer
* Host hogehoge.com:443 was resolved.
* IPv6: (none)
* IPv4: 54.248.4.87, 52.198.94.68
*   Trying 54.248.4.87:443...
* Connected to hogehoge.com (54.248.4.87) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/pki/tls/certs/ca-bundle.crt
*  CApath: none
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* Recv failure: Connection reset by peer
* OpenSSL SSL_connect: Connection reset by peer in connection to hogehoge.com:443
* Closing connection
curl: (35) Recv failure: Connection reset by peer

正しいクライアント証明書を持っていないため、TLS接続が失敗しています。

CloudWatchでメトリクスを確認

CloudWatchのメトリクスからALBに通信が到達していることを確認します。
CloudWatch メトリクスでは今回接続を行ったALBにおいて以下のメトリクスが確認できました。

各メトリクスはTCP接続の総数とTLSエラーによってTLS接続に失敗した数を表しています。
HTTP_Fixed_Response_Countなど、認証が成功してレスポンスを返したことが分かるメトリクスはありません。
メトリクスから、リクエストはALBに到達したものの、クライアント証明書の検証失敗によりTLS接続が確立できなかったことが確認できます。

AWS WAFのログを確認

次にAWS WAFでリクエストの検証が行われていなければAWS WAFまでリクエストが到達していないことが確認できます。
ではコンソール画面より直近のトラフィックを確認します。
CleanShot 2025-02-15 at 17.44.58@2x

トラフィックはありませんね。
念のためCloudWatchのログも確認します。
CleanShot 2025-02-15 at 18.24.45@2x

ログストリームが作成されたというログ以外はありません。
これでAWS WAFまではリクエストが到達せず、AWS WAFでの検証は発生していないことがわかります。
また、AWS WAFはALBの前段に位置していないことも確認できました。

正しいクライアント証明書でリクエストを送信

では、次に正しいクライアント証明書を使ってリクエストを送信し、ALBとAWS WAFの検証が成功してレスポンスが返ってくることを確認します。

 curl https://hogehoge.com \
    --key client_key.pem \
    --cert client_cert.pem \
    -v
* Host hogehoge.com:443 was resolved.
* IPv6: (none)
* IPv4: 54.248.4.87, 52.198.94.68
*   Trying 54.248.4.87:443...
* Connected to hogehoge.com (54.248.4.87) port 443
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/pki/tls/certs/ca-bundle.crt
*  CApath: none
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS handshake, CERT verify (15):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256 / prime256v1 / rsaEncryption
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=hogehoge.com
*  start date: Feb 15 00:00:00 2025 GMT
*  expire date: Mar 16 23:59:59 2026 GMT
*  subjectAltName: host "hogehoge.com" matched cert's "hogehoge.com"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M02
*  SSL certificate verify ok.
*   Certificate level 0: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
*   Certificate level 1: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
*   Certificate level 2: Public key type RSA (2048/112 Bits/secBits), signed using sha256WithRSAEncryption
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://hogehoge.com/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: hogehoge.com]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.5.0]
* [HTTP/2] [1] [accept: */*]
> GET / HTTP/2
> Host: hogehoge.com
> User-Agent: curl/8.5.0
> Accept: */*
>
< HTTP/2 200
< server: awselb/2.0
< date: Sat, 15 Feb 2025 09:39:48 GMT
< content-type: text/plain; charset=utf-8
< content-length: 9
<
* Connection #0 to host hogehoge.com left intact

リクエストが成功してレスポンスが返ってきていることが確認できます。

AWS WAFのログ確認

AWS WAFでリクエストが検証されていることも確認します。
まずはコンソール画面を確認します。
CleanShot 2025-02-15 at 18.51.04@2x

リクエストが検証されてAllowd(許可)されていますね。
(試しにcrulを3回実行したので、数字は3になっています)

CloudWatchでログも確認します。
CleanShot 2025-02-15 at 18.51.27@2x

こちらでもリクエスがAWS WAFに到達して検証されていることが確認できました。

まとめ

想定通り、mTLSを有効にしたALBではAWS WAFに転送する前にクライアント証明書の検証を行い、検証に失敗したリクエストはAWS WAFへは転送されないことが確認できました。
また、同時にAWS WAFはALBの前段でリクエストを検証するのではなく、ALBが受けたリクエストをAWS WAFに転送していることも確認できました。
AWS WAFのトラフィック検証フローについては、公式FAQでも同様の説明がされています。

ALBのmTLSはトランスポート層のセキュリティで、クライアントとALB間のコネクションを確立するフェーズで検証されます。
ALBの後続にリクエストが転送されるのはコネクションが確立された後になります。
今回の検証で、ALBのTLSハンドシェイク中にクライアント証明書の提示がされなかった場合はTLS接続が失敗して、後続のAWS WAFにもリクエストが転送されなかったことが確認できました。

余談ですが、ALBのコンソール画面からAWS WAFをアタッチしようとすると以下のような記載がありました。
CleanShot 2025-02-15 at 16.49.18@2x

ターゲットの前と書かれていますね。
このことからもAWS WAFはALBの前ではなく、ALBとターゲットの間であると読み取れます。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.