[SNS] WAFを通したときの不具合様々

技術のお話し

めでたくインスタンスを立ち上げて遊んでるわけですが、当初の構成だといろいろ不具合が出ました。当初の構成はこんな感じです。

docker-mastodon

当初はこの構成で正常動作してると思っていたのですが、以下の不具合が発生してました。

  • 外部からブラウザUIで開いた場合、タイムラインが動的更新されない
  • 場合によっては、外部からブラウザUIでログインしようとすると失敗する

特に1番目の不具合は致命的で、これはマズイなと思ってUTMのライブログを調べてみるとこんなログが出てました。

2017:05:15-00:00:10 meiji reverseproxy: id=“0299” srcip=“<外部IP>” localip=“<我が家IP>” size=“39” user=“-” host=“<外部IP>" method="GET" statuscode="401" reason="-" extra="-" exceptions="-" time="12676" url="/api/v1/streaming/" server="elephant.bluecore.net" referer="-" cookie="remember_user_token=(省略); _mastodon_session=(省略) " set-cookie="-"

当初は/api/v1/streamingに対するサイトパスルーティングを通していないことで404エラーが帰ってきてることがわかり、早速修正したのですが、今度は何故か/api/v1/streamingに対して401返却が行われているんですね。これの原因がわからずう~んと悩む羽目に。

結局原因がわからないのと、その後DBが崩壊したこともあったりで、次作り直す際はだいぶ単純化した構成にしています。

logical_diagram_social-bluecore-net単にルーターでReverse NATしただけの構成。それで通常運転できるようになってたんですが、その後どうしても納得がいかなくて、ステージング環境を別途作ることに。そこにWAFを通すことにしました。

そして調査したんですが、以下の情報に行き着きました。

Streaming notification broken in a new installation

なんと、/api/v1/streamingに対する通信は「http://」ではなく「ws://」であるとのこと。nginxではそこは意識しなくていいみたいなのですが、今私が使ってるWAFのようなApacheベースのものの場合、ここのURLを正確に表現する必要があります。「ws://」ってのは何かな?って調べてみるとWebsocketとあり、どうやらプロトコル自体が違うみたいですね。たっはー、これがうまくいかない原因かと。

更に調べると、なんと今使ってるWAF、Websocketに対応する気がゼロみたいで。

Sophos-Ideas/websocket support for WAF

色んな人の雄叫びが垣間見られます。心の底から「F○○k!!」ってつぶやきそうになるのを堪えて読み進めてみると、以下のように対応すると良いことがわかりました。

UTMに対してSSHログインを行い、以下の通りにコマンドを実行してコンフィグファイルを開きます。

> su -
# cd /var/storage/chroot-reverseproxy/usr/apache/conf
# vi reverseproxy.conf

続いて、以下のように4000番ポートにアクセスする設定のURLを全て「ws://」に変えます。

KeepAlive On
ServerName meiji
ServerAdmin localYouser@gmail.com
Listen ***.***.***.***:443 https
<VirtualHost ***.***.***.***:443>
        ServerName elephant.bluecore.net
        SSLProxyEngine On
        SSLEngine On
        SSLCertificateFile /usr/apache/conf/ssl/REF_CaHosElephantbl.pem
        SSLCACertificateFile /usr/apache/conf/ssl/REF_CaHosElephantbl.CAs
        SSLCertificateKeyFile /usr/apache/conf/ssl/REF_CaHosElephantbl.key
        Include conf/waf/REF_WAFDefaultProfileBasic.rules
        RequestHeader set X-Forwarded-Proto https
        DocumentRoot /var/www/REF_RevFroElephantbl
        SetEnv proxy-initial-not-pooled
        <Proxy balancer://cd107d9706d71153bafd4ab15f1c6b5d>
                BalancerMember http://***.***.***.***:3000 status=-SE timeout=300
        </Proxy>
        <Proxy balancer://39b4eada215c97c750464aabd919c2b7>
                BalancerMember ws://***.***.***.***:4000 status=-SE timeout=300
        </Proxy>
        <Proxy balancer://93bb0dd069aa830c31eb1abaec665a2e>
                BalancerMember ws://***.***.***.***:4000 status=-SE timeout=300
        </Proxy>
        <Location "/">
                SetEnv proxy-aside-c
                ProxyPass "balancer://cd107d9706d71153bafd4ab15f1c6b5d/" lbmethod=bybusyness
                ProxyPassReverse "http://***.***.***.***:3000/"
                ProxyPassReverse "http://elephant.bluecore.net:3000/"
                SetOutputFilter AvScan;DEFLATE
                <RequireAll>
                        Require all granted
                </RequireAll>
                SetInputFilter AvScan
                AvScanEngines single
                AvScanSocketTimeout 90
                AvScanLogOnly On
                AvScanBlockUnscannable Off
                AvScanSizelimit 0
        </Location>
        <Location "/api/v1/streaming">
                SetEnv proxy-aside-c
                ProxyPass "balancer://93bb0dd069aa830c31eb1abaec665a2e/api/v1/streaming" lbmethod=bybusyness
                ProxyPassReverse "ws://***.***.***.***:4000/api/v1/streaming"
                ProxyPassReverse "ws://elephant.bluecore.net:4000/api/v1/streaming"
                SetOutputFilter AvScan;DEFLATE
                <RequireAll>
                        Require all granted
                </RequireAll>
                SetInputFilter AvScan
                AvScanEngines single
                AvScanSocketTimeout 90
                AvScanLogOnly On
                AvScanBlockUnscannable Off
                AvScanSizelimit 0
        </Location>
        <Location "/api/v1/streaming/">
                SetEnv proxy-aside-c
                ProxyPass "balancer://39b4eada215c97c750464aabd919c2b7/api/v1/streaming/" lbmethod=bybusyness
                ProxyPassReverse "ws://***.***.***.***:4000/api/v1/streaming/"
                ProxyPassReverse "ws://elephant.bluecore.net:4000/api/v1/streaming/"
                SetOutputFilter AvScan;DEFLATE
                <RequireAll>
                        Require all granted
                </RequireAll>
                SetInputFilter AvScan
                AvScanEngines single
                AvScanSocketTimeout 90
                AvScanLogOnly On
                AvScanBlockUnscannable Off
                AvScanSizelimit 0
        </Location>
</VirtualHost>

で、終わったらWAFサービスを再起動します。

# /var/mdw/scripts/reverseproxy restart

そして接続したらこう見えるようになりまする。

2017:05:26-01:18:54 meiji reverseproxy: id="0299" srcip="(外部クライアントIP)" localip="(サーバ外部IP)" size="0" user="-" host="(外部クライアントIP)" method="GET" statuscode="200" reason="-" extra="-" exceptions="-" time="9218" url="/api/v1/streaming/" server="elephant.bluecore.net" referer="-" cookie="remember_user_token=(省略); _mastodon_session=(省略)" set-cookie="-"

おお、無事200が返却されました。ウェブUIでも正常に動的更新が行われるようになりました。というわけで、どうやらMastodonはタイムラインの更新周りに関してWebsocketを使ってるということを理解しました。Webの時代ってどんどん移り変わり、仕組みも変わっていってるんだなぁということを実感。なかなか時代について行けぬ自分を自覚しました。

Tags:

No responses yet

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

PAGE TOP