bungeecordでhaproxyを利用しつつ接続元のorigin ipを取得する方法
Java版minecraftサーバ(bungeecord+spigot)を運営されており、DDoS対策などでhaproxyをつかったリバースプロキシを利用されている方向けの記事です。
単純にリバースプロキシ(haproxy)を導入するだけだと、bungeecord上で各プレイヤーの接続元のIPアドレスが全てリバースプロキシサーバのIPアドレスになってしまいますので、何かと不都合がでます。proxycheck.ioなどと連携してVPN・プロキシ経由の接続をブロックするプラグインがまともに機能しなくなったり、IP-BANしたら全員入れなくなったり…
この記事では、リバースプロキシ環境配下でもプレイヤーの本来の接続元IPアドレス(これは英語文献ですと大体Origin IPなどと呼んでいます)をbungeecord上で識別できるようにするための設定方法をご紹介します。
ざっくりいうと、http(s)プロトコルでいうx-forwarded-forヘッダみたいなことができるということです。
・bungeecordのconfig.ymlを編集
・haproxyのhaproxy.cfgを編集
・【番外編】BotAttack防止設定
bungeecordのconfig.ymlを編集
proxy_protocolをfalse->trueに変更します。変更後は再起動で反映されます。
proxy_protocol: true
なお、この設定をすると以後後述の設定を施したhaproxy以外からは接続できなくなりますのでご注意ください。
haproxyのhaproxy.cfgを編集
/etc/haproxy/haproxy.cfg を編集します。変更後は再起動(systemctl restart haproxy とか。OSによる)で反映されます。
フォワード先のIPアドレスとポートを指定している箇所があるかと思いますが、そこのオプションに”send-proxy-v2”を追加します。
#--------------------------- # minecraft server gateway #--------------------------- listen minecraftsv01 bind 0.0.0.0:25565 mode tcp option tcplog balance roundrobin server mc01 <DestinationIP>:<DestinationPort> send-proxy-v2
【番外編】BotAttack防止設定
上述の設定でこの記事の本来の目標は達成されますが、上述のオプションを利用するとBotAttackに対して脆弱になりますので注意が必要です。
実際、私が運営している整地鯖にも今年(2019年)10月ごろにBotAttackによってサーバが非常に不安定となる事案が発生しました。
本来bungeecordには大量のログインリクエストによりサーバが過負荷となるのを防止するために、config.ymlに”connection_throttle”と”connection_throttle_limit”と呼ばれる、同一IPからの大量リクエストに対する応答を抑制するオプション*1が備わっているのですが、”proxy_protocol”がtrueとなってる環境では意図的に無効化されてしまう挙動となっているみたいです。
まとめると、bungeecordのconnection_throttle_limitが効いていなかった。これがちゃんと聞いてればボットネットによるログインアタック中も新規ログインは貼りにくくとも既存のセッションには影響しないんだが、今年2月のfixでproxy_protocol=trueにした時に限って無効化される挙動に書き換わってた。
— unchama うんちゃま (@tsukkkkkun) 2019年10月13日
この無効化される挙動は2019/3以降にリリースされたbungeecordに該当します。
ちな、今回の事象のトリガーとなったbungeecordのfixはこちらhttps://t.co/LeKI03DGFx
— unchama うんちゃま (@tsukkkkkun) 2019年10月13日
(ちなみに、元々私はこの仕組みを「IP関係なくbungee全体で大量ログインリクエスト発生時それをある程度リクエスト拒否してサーバ過負荷を抑える機能」と認識していたのですが、それはhaproxy環境下でたまたまそのように動作しただけで、その動作自体は不具合として認識されていたっぽいです。)
てか元々のconnection_throttle_limitの想定した動き違ったっぽいな。元々は同一の接続元IPからのリクエスト数を制限するものだったっぽい。それがhaproxy通したことで全部接続元が同じIPとして認識された結果、たまたまボットネットの攻撃に対して良い作用をしてただけっぽい
— unchama うんちゃま (@tsukkkkkun) 2019年10月15日
https://github.com/SpigotMC/BungeeCord/issues/2590
で、じゃあどう対策するんですか?という話 ですが、haproxy側で秒間のリクエスト数を制限することができますので、これを利用します。BotAttack中は新規ログインも張りづらくなる副作用は存在しますが、サーバ丸ごと過負荷に陥る事態は回避できますので、ログイン中のプレイヤーは快適にプレイし続けることが可能です。許容するリクエスト数は、サーバのログイン状況に応じて調整が必要です。
haproxy.cfgの編集例を記載しておきます。
#---------------------------------------------------------------------
# minecraft server gateway
#---------------------------------------------------------------------
frontend minecraft
mode tcp bind 0.0.0.0:25565
option tcplog
tcp-request inspect-delay 5s
acl too_fast fe_sess_rate gt 10
tcp-request content reject if too_fast
use_backend seichi
backend seichi
mode tcp server mc1 <DestinationIP>:<DestinationPort> send-proxy-v2
赤字の部分がミソで、上記の例ですと新規リクエストが秒間10回以上来た場合、以降のリクエストは自動的に拒否してくれます。
ちなみに、”fe_sess_rate"などのhaproxy上で設定できるパラメータに関しては公式ドキュメント↓にかなり詳細な説明があります*2ので、設定を突き詰めたい方は読んでみると良いかもしれません。
https://cbonte.github.io/haproxy-dconv/
いつも通り勢いで書き切りましたので、ここがわかりづらい・もっと聞きたいなどあればコメント欄にお寄せいただけますと泣いて喜びます。記事ネタリクエストもお待ちしております。