こんにちは、ネクストモードの眞鍋です。
CloudFrontのオリジンにALBを設定したHTTPS構成を構築したところ、ALBへの直接アクセスは正常なのに、CloudFront経由のアクセスだけ502エラーが多発する事象に遭遇しました。
結論を先に言うと、犯人は「SNIとALBのデフォルト証明書の組み合わせ」でした。
この事例を、調査の過程も含めてご紹介します。
対象のサイトは、多言語化のためにSaaS型の翻訳プロキシを挟んだ、やや特殊な多段構成です。
| リソース | 役割 |
|---|---|
| CloudFront① | Webアクセスの入口。www.example.com を割り当て。デフォルトオリジンは翻訳プロキシ |
| 翻訳プロキシ(SaaS) | 多言語化サービス。リクエストを中継してCloudFront②へ |
| CloudFront② | 中継用。代替ドメイン名なし(xxx.cloudfront.net のまま)。オリジンはALB |
| ALB | origin.example.com をCNAMEで割り当て。HTTPSリスナーには複数ドメインの証明書を割り当てており、デフォルト証明書は別サービス用(CN=app.example.com) |
ALBに origin.example.com というドメインを割り当てているのは、CloudFrontを経由せずにALBへ直接アクセスするケースが存在するためです。
また、重要なポイントとして、CloudFront②のデフォルトビヘイビアは全ヘッダー転送(Hostヘッダーを含む)の設定になっていました。
origin.example.com をALBに割り当て、CloudFront②のオリジンドメインとして設定して構築したところ、監視ツールの「5xxErrorRate」アラートが多発しました。
https://origin.example.com)は正常に応答するorigin.example.comの証明書を割り当て済(SNI)まず、経路上の各リソースのログとメトリクスを確認しました。
OriginCommError)を確認。前段CloudFront①の502と発生時刻・件数が完全一致time-taken は1秒前後で、タイムアウト(30秒)ではなく接続段階の即時失敗
OriginCommError とALBにログがないことから、502の発生源はCloudFrontでほぼ確定し、
HTTPリクエストがALBに到達する前、TLSハンドシェイクの段階で失敗している可能性が高いと判断しました。
さらに、ALBの接続ログとVPCフローログを確認しました。
| ログ | 結果 | 意味 |
|---|---|---|
| ALBアクセスログ | エラーなし | HTTPリクエストは到達していない |
| ALB接続ログ | Failed:UnmappedConnectionError |
接続確立段階での失敗と整合 |
| VPCフローログ | 全件ACCEPT | SG/NACLによる拒否ではない |
「TLSハンドシェイクで失敗している」ことはほぼ確定しましたが、ログだけでは詳細な原因特定には至りませんでした。
原因はCloudFront②→ALBのTLSハンドシェイクにおける証明書検証エラーでした。
メカニズムを順に追うと次のとおりです。
xxx.cloudfront.net がSNIに入るxxx.cloudfront.net に一致する証明書が存在しないため、デフォルト証明書(CN=app.example.com)を返却するapp.example.com)は、オリジンドメイン名(origin.example.com)ともHostヘッダー(xxx.cloudfront.net)とも不一致 → 検証失敗 → 502(OriginCommError)
つまり、origin.example.com 用の証明書をALBのSNIの証明書リストに用意していても、CloudFront②からの接続ではSNIが cloudfront.net ドメインになるためその証明書は選ばれず、別ドメイン用のデフォルト証明書が返って検証に失敗していた、という構図でした。
対処はシンプルで、ALBのHTTPSリスナーのデフォルト証明書を origin.example.com 用の証明書に変更しました。
SNIに一致しない値(cloudfront.net ドメイン)が来てデフォルト証明書にフォールバックしても、そのデフォルト証明書がオリジンドメイン名と一致していれば検証は成功する、という仕組みを利用した形です。変更後、502は解消しました。
なお、より根本的な対策としては以下も検討が必要です。
X-Forwarded-Host 等のカスタムヘッダーで渡す「ALBへの直接アクセスは正常なのに、CloudFront経由だけ502になる」という一見不可解な事象でしたが、ひも解いてしまえば、CloudFrontの証明書検証ルールとALBのSNIによる証明書選択という、仕様どおりの振る舞いの組み合わせでした。
Hostヘッダーを転送している環境では、同じ事象を踏む可能性が十分にあります。
CloudFrontのオリジンにALBを設定する際は、ぜひALBのデフォルト証明書にも目を向けてみてください。