1
/
5

CloudFront導入とCognitoで認証した話

テクノロジーグループの冨田です。

北欧、暮らしの道具店とクラシコムのコーポレートサイトにCloudFrontを導入しました。
以前から画像についてはCloudFrontやimgixを利用し配信していました。
今回はサイト自体を配信するようにしました。

背景

2022年8月に東証グロース市場へ上場しました。

  • メディアへの露出が増えたため、突発的なアクセスがきても耐えられるようにしたい。
  • 既に導入していたCloudFront Security Savings Bundleでコストを抑えたい。

という動機からCloudFrontを導入しました。

やったこと

Cognitoによる認証

クラシコムの検証環境(ステージング環境)はALBでCognitoによる認証をかけており、社員のみアクセス可能にしていました。
今回ALBの前段にCloudFrontを導入しましたが、そのままの構成でCloudFrontを前段に置いてしまうと社員以外もキャッシュされた内容がCloudFrontで閲覧可能になってしまいます。

検証環境(ステージング環境)と本番環境でなるべくインフラの構成を合わせておきたいのでLambda@Edgeでcognito-at-edgeをデプロイし、Cognitoでの認証をかけました。

Lambda@Edgeの制約で下記の点ではまってしまいました。


GitHub - awslabs/cognito-at-edge: Serverless authentication solution to protect your website or Amplify application
This Node.js package helps you verify that users making requests to a CloudFront distribution are authenticated using a Cognito user pool. It achieves that by looking at the cookies included in the request and, if the requester is not authenticated, it wi
https://github.com/awslabs/cognito-at-edge


ALBへのリクエストの制限

CloudFrontを用意したため、ALBに直接アクセスされてしまうと用意した意味がありません。

CloudFrontからALBへのアクセスはリクエストにカスタムHTTPヘッダを付与し、カスタムヘッダが付与されているものだけに応答するようにしてあります。
2022年2月からCloudFront マネージドプレフィックスリストが用意されたため、ALBのセキュリティグループで、CloudFrontからのインバウンドHTTPSアクセスのみを許可するようにしました。
また、万が一に備えてステージング環境においてはALBでもCognitoによる認証は引き続きかけています。

Application Load Balancers へのアクセスを制限する
Elastic Load Balancing の Application Load Balancer によって提供されるウェブアプリケーションやその他のコンテンツには、CloudFront はオブジェクトをキャッシュしてユーザー(閲覧者)に直接提供し、Application Load Balancer の負荷を軽減できます。CloudFront は、レイテンシーを削減し、分散型サービス拒否 (DDoS) 攻撃を吸収することにも役立ちます。ただし、ユーザーが CloudFront をバイパスして、Appli
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/restrict-access-to-load-balancer.html

はまったこと

クライアントのIPアドレス、スキーマの取り扱い

ECS Fargate上でNGINXとphp-fpm、Laravelを利用しています。

NGINXのアクセスログでクライアントIPアドレスやリクエストスキーマを記録しています。
また、Laravel上でもクライアントIPアドレスやリクエストスキーマを利用しています。

クライアントのIPアドレスはNGINXで `real_ip_header X-Forwarded-For;` リクエストヘッダ、 `set_real_ip_from 192.168.1.0/24;` で信頼できるアドレス、 `real_ip_recursive on;` で信頼されない最後のアドレスを取得するようにしていました。

CloudFrontのIPアドレスはJSON形式で公開されていますが不定期に変更されるため、`set_real_ip_from`を自動的に更新するのは少し面倒です。

クラシコムではインフラのアドバイザーとしてカヤックの藤原さんにアドバイス、レビューをしていただいています。
`CloudFront-Viewer-Address`や`CloudFront-Forwarded-Proto` リクエストヘッダを利用すれば良いとアドバイスをいただきました。

`CloudFront-Viewer-Address`はIPアドレスとポート番号が含まれているため、IPアドレスのみを利用したい場合には分割する必要があります。

NGINXのLua moduleを利用し分割しました。

【nginx】CloudFront, ALBどちらからのリクエストでも適切なremote_addrを取得する【php-fpm】 - Qiita

NGINXのオフィシャルのDockerイメージそのままではLua moduleは利用できないため、オフィシャルのドキュメントをもとにビルドしました。

運用は無事回っているもののデプロイ時にLua moduleのビルド時間がのびてしまいました。
今後の課題としてはビルド方法の見直しを行うか、OpenRestyのイメージを利用するか、CloudFront Functions側に任せようかなと思います。

CloudFront HTTP ヘッダーの追加
CloudFront がビューワーから受け取るリクエストに特定の HTTP ヘッダーを追加するように CloudFront を設定できます。これらの HTTP ヘッダーの値は、ビューワーリクエストの特性に基づいています。ヘッダーでは、ビューワーのデバイスタイプ、IP アドレス、地理的位置、リクエストプロトコル (HTTP または HTTPS)、HTTP バージョン、および TLS 接続の詳細に関する情報が提供されます。 これらのヘッダーを使用すると、オリジンまたは エッジ関数でビューワーに関する情報を受け
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/using-cloudfront-headers.html


カナリアリリースやメンテナンス

カナリアリリースやメンテナンス時にALBのリスナールール 送信元IPアドレス に 作業者のIPアドレスを設定して動作確認をしていました。
CloudFrontを経由することになり送信元IPアドレスがCloudFrontになってしまいました。

ALBのリスナールール の HTTPヘッダで ヘッダ名は `CloudFront-Viewer-Address` を指定し、比較文字列には 作業者のIPアドレスを指定しました、ポート番号はワイルドカード文字列を利用しました。

設定の例

203.0.113.1:*


Application Load Balancer のリスナールール
リスナーに対して定義したルールは、ロードバランサーが 1 つ以上のターゲットグループ内のターゲットにリクエストをルーティングする方法を決定します。 各ルールは優先度、1 つ以上のアクション、および 1 つ以上の条件で構成されています。詳細については、「 リスナールール 」を参照してください。 コンソールには、ルールが優先度順に表示されます。ただし、コンソールには各ルールのシーケンス番号が表示され、AWS CLI または Elastic Load Balancing API によって表示されるルールの優先順
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/listener-update-rules.html


並行運用

日中に旧ALBからCloudFrontへDNSの切り替えを行い、DNSのキャッシュが切れるまで並行運用を行いました。

DNSを変更して3分後には大半のトラフィックはCloudFront経由に切り替わったのですが、CATV系のプロバイダやBotは1週間経過しても旧ALBへのアクセスが続きました。

ALBも運用中にIPアドレスが変わることもあるということで旧ALBは退役させました。

ALB切替時のリクエスト数の変化

まとめ

CloudFrontの導入で7/12のテレビ東京系列のWBS(ワールドビジネスサテライト)でとりあげられたタイミングや、8/5の上場当日も無事乗り切ることができほっとしました。

一点悔やまれるのはALB側のWAFにレートリミットを設定してしまい、一部のリクエストをブロックしてしまいました。
今後も改善を重ね「サイトに快適・安全にアクセスできて当たり前」な状態にしていきたいと思っています。

クラシコムは上場しましたが、エンジニア7名体制でほぼ内製&運用しております。
まだまだシステムには改善の余地があるので外部SaaSなどの選定なども経験しやすいかなと思います。

また、バックエンドやネイティブアプリ中心に開発していた私ですがアドバイザーにレビューしていただけるので心強いです。

レコメンドやサイト内検索のチューニングやフロントエンドの最適化などなど やりたいことはいっぱいあるのでクラシコム、北欧、暮らしの道具店に興味を持った方はお気軽にご連絡ください。

株式会社クラシコム's job postings

Weekly ranking

Show other rankings