Cloud Armorで「正当なトラフィック」を守り抜く――レートリミッティングの現場的解釈
システムを運用していると、必ずと言っていいほど直面する「想定外のトラフィック」という悪夢。それは攻撃者の執拗なブルートフォースかもしれませんし、あるいは仕様を読み違えたクライアントの「行儀の悪い」再試行ロジックかもしれません。
ロードバランサ(GCLB)の最前線でこれらを食い止めるのが、Google Cloud Armorのレートリミッティングです。今日は、教科書的なマニュアルには載っていない、現場でハマりがちなポイントを交えながら、この強力な武器の使い方を深掘りしていきましょう。
—
なぜ「429 Too Many Requests」が重要なのか
RFC 6585で定義された 429 Too Many Requests ステータスコード。これは単なるエラーではなく、サーバーからの「今はこれ以上受け付けられないから、少し落ち着いてくれ」という切実なメッセージです。
Cloud Armorでレートリミッティングを有効にすると、設定した閾値を超えたリクエストに対して、GCLBが即座にこのコードを返します。バックエンドのアプリケーションに到達する前に境界で遮断することで、貴重なCPUやメモリリソースを保護し、本来の正当なユーザーへのレスポンス速度を維持する。これがSREとしての第一の防衛線です。
—
レートリミッティングの基本パラメーターを理解する
Cloud Armorの設定画面や gcloud コマンドで設定する際、以下のパラメータが肝になります。
rate-limit-threshold: 指定した期間内に許容するリクエスト数。interval: 期間(例:60 seconds)。enforce-on-key: これが最も重要です。何を単位に「頻度」をカウントするかを決めます。
IP アドレス単位で制限するのが最も一般的ですが、APIの場合は ALL(全体)や HTTP-HEADER(特定のAPIキーなど)を指定することで、より柔軟な制御が可能になります。
設定例:特定のIPからの攻撃を防ぐ(CLI)
以下は、特定のパスに対して1分間に100リクエストを超えたIPを遮断する設定です。
# セキュリティポリシーを作成
gcloud compute security-policies rules create 1000 \
--security-policy=my-policy \
--expression="request.path.matches('/api/v1/login')" \
--action=rate-based-ban \
--rate-limit-threshold-count=100 \
--rate-limit-threshold-interval-sec=60 \
--conform-action=allow \
--exceed-action=deny-429 \
--enforce-on-key=IP
—
現場で遭遇する「罠」とトラブルシューティング
レートリミッティング導入時に、必ずと言っていいほど直面する問題が「誤検知」です。
1. 共有IP環境の落とし穴
オフィスや大学、あるいはNATゲートウェイ経由のトラフィックを IP 単位で制限すると、その背後にいる全ユーザーがまとめて遮断されます。「特定のAPIキー」や「セッションID」を HTTP-HEADER に指定してキーにするのが、API設計における賢い選択です。
2. クライアント側の再試行ロジック
429 を受け取ったクライアントが、即座にリトライを繰り返すと状況は悪化します。クライアント側の実装には、必ず「指数バックオフ」を組み込むよう、フロントエンドやモバイルアプリのチームと握っておきましょう。
以下は、Pythonでレートリミットを考慮したリクエスト送信のサンプルです。
import requests
import time
def call_api_with_retry(url):
while True:
response = requests.get(url)
# 429 Too Many Requests の場合の処理
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 5))
print(f"制限超過。{retry_after}秒待機します...")
time.sleep(retry_after)
continue
return response
# 実行
call_api_with_retry("https://api.example.com/data")
—
デバッグと監視の重要性
Cloud Armorが「今、誰をブロックしているのか」を確認するには、Cloud Logging(旧Stackdriver)が欠かせません。以下のクエリで、実際に 429 を返しているトラフィックを確認できます。
# Cloud Logging 用のクエリ例
jsonPayload.enforcedSecurityPolicy.name = "my-policy"
jsonPayload.enforcedSecurityPolicy.outcome = "DENY"
httpRequest.status = 429
設定したルールが適切かどうかは、導入初期は rate-limit-threshold をあえて緩めに設定し、ログを観察しながら徐々に締め上げていくのが、本番環境での鉄則です。
—
最後に:防御は「余白」が大事
ネットワークエンジニアとして言えることは、レートリミットは「システムを守るためのクッション」であり、それ自体が目的ではないということです。
過剰に制限を厳しくすれば、UXは確実に低下します。しかし、何もしなければシステムはダウンし、全ユーザーに迷惑がかかる。そのバランスを取るために、Cloud Armorのようなインフラレベルでの制御と、アプリケーション側での適切なエラーハンドリング(Retry-Afterヘッダーの活用など)を組み合わせるのが、現代のクラウドネイティブな開発スタイルなのです。
皆さんのインフラが、今日も平穏無事に稼働し続けることを願っています。それでは、また次回の深掘りでお会いしましょう。
コメント