ロードバランサ — 間に入った箱が、何を書き換えているか
ロードバランサを入れた翌日、レート制限が全利用者をまとめて弾いた。ログの送信元も全部同じ。間に入る箱は接続を終端し、元の情報はヘッダーに移る。
先に読んでおくとよい記事
この記事の進み方
What — 間に入る箱は、接続を終端する
ロードバランサやリバースプロキシは、通信を素通しにしません。利用者との接続をそこで受け止め(終端し)、別の接続を自分で作ってバックエンドへ送ります。
利用者と話しているのはロードバランサ。アプリと話しているのもロードバランサ。アプリから見える相手は、最初から最後までロードバランサだけ。
- 終端
- そこで接続を一度受け止めること。TLS を終端すると、その先は別の接続になる。
- X-Forwarded-For
- 元の送信元 IP を伝えるヘッダー。間に入った箱が追記していく。標準化されたものに Forwarded がある。
- ヘルスチェック
- 振り分け先が正常かを定期的に確かめる仕組み。失敗が続くと振り分けから外す。
- アイドルタイムアウト
- 通信が無いまま接続を保持する上限時間。上流と下流でずれると切断の事故になる。
元の情報は、ヘッダーに移っている
利用者の IP、使われたプロトコル(http / https)、元のホスト名。どれも接続からは分からなくなり、ヘッダーに移ります。
| 知りたいもの | 接続から | ヘッダー |
|---|---|---|
| 利用者の IP | ロードバランサの IP になる | X-Forwarded-For |
| http か https か | バックエンドへは http のことが多い | X-Forwarded-Proto |
| 利用者が入力したホスト名 | 書き換わることがある | X-Forwarded-Host / Host |
X-Forwarded-Proto を読まないと、https で来たのに http だと思い込み、http:// へリダイレクトして無限ループになる、という事故が起きます。
ロードバランサの後ろにあるアプリで、IP アドレスごとのレート制限をかけています。ロードバランサを入れた直後から、全利用者がまとめて制限に引っかかるようになりました。なぜですか?
Why — なぜヘッダーをそのまま信じてはいけないか
X-Forwarded-For を読めば解決、とはいきません。このヘッダーは、利用者が自分で付けられます。
$ curl https://example.com/api/login -H "X-Forwarded-For: 1.2.3.4"
アプリが素直に先頭の値を使うと、攻撃者はリクエストごとに違う IP を名乗れます。レート制限は無意味になり、ログには偽の IP が残り、IP による遮断も効きません。
右から数える
X-Forwarded-For は、間に入った箱が右へ追記していく形です。
X-Forwarded-For: 1.2.3.4, 203.0.113.45, 70.132.1.9
↑偽装 ↑本物の利用者 ↑CDN が見た送信元
(利用者が勝手に付けた)
信頼できるのは、自分が置いた箱が付けた値だけです。CDN とロードバランサの2段なら、右から2つ目が利用者の IP です。
つまり、自分の構成で間に何段あるかを数え、その数だけ右から取るのが正しい読み方です。段数を間違えると、偽装された値を掴みます。多くのフレームワークには「信頼するプロキシの数」を設定する仕組みがあり、その設定こそが判断そのものです。
ヘルスチェックは、浅すぎても深すぎても事故になる
ロードバランサは、振り分け先が生きているかを定期的に確かめます。この確認の深さが、障害の形を決めます。
ポートが開いていれば正常とみなす
TCP connect 10.0.3.12:3000- 見つけられる故障
- プロセスの停止だけ
- 誤って外すこと
- ほぼ無い
- 見逃す故障
- **応答を返せない状態**
- 向いている場面
- HTTP 以外のサービス
- –プロセスは生きているがイベントループが詰まっている(design/io-concurrency)状態を見逃す
- –デプロイの途中で起動はしたが準備が終わっていない、も通してしまう
- –壊れた1台に流し続けると、利用者の一定割合だけがエラーになる
浅いと壊れたサーバーに流し続け、深いと依存先の障害で全台が同時に外れる。深さは「そのサーバーが仕事をできるか」に合わせる。
アプリは X-Forwarded-For の先頭の値を、利用者の IP として使っています。どんな問題が起きますか?
演習 — まず自分で判断する
解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。
利用者の IP を、正しく取れるようにするには?
- 構成は 利用者 → CDN → ロードバランサ → アプリ の2段
- IP はレート制限、不正アクセスの調査、地域の統計に使う
- CDN とロードバランサは自分たちが契約・設置したもの
- アプリは複数のフレームワークで書かれた3つのサービスに分かれている
- 過去に、偽装された IP がログに残っていたことがある
- · どこから先が自分の管理下か
- · ヘッダーの何番目を読むべきか、それをどう決めるか
- · 3つのサービスで、同じ判断を繰り返さない方法
「朝からログインできない」という問い合わせを受けたサポート担当に、何が起きたかを説明してください
- 相手は IP アドレスという言葉は知っているが、ロードバランサは知らない
- 復旧は10分で終わり、原因も分かっている
- 同じ問い合わせが来たときに、何と案内すればよいかを知りたがっている
読み終わりましたか?
読了にすると、これを前提とする記事がロードマップで開放されます。