【本当にあったあまり怖くない話】設定は同じなのに Cacoo にログインできない。

こんにちは。 Cacoo チームのフアンフランこと、とおのぶです。ヌーラボの開発は、ユーザ向けに提供しているプロダクション環境と社内向けにβ機能を試せる2つの開発環境を使い分けています。今日はEC2-ClassicからEC2-VPCへ移行したときの話をします。本当にあった怖!…くない話(単純なミスです)です。

ログインできない

VPCへ移行済みのプロダクション環境と同様の構成で、開発環境の移行が完了しました。さっそく利用できる!はずです。しかし、下の動画のように、ログインできない状態になってしまいました。https://cacoo.com/signinで認証すると、本来ならばhttps://cacoo.com/diagramsに遷移するはずが、どこにも遷移せずにhttps://cacoo.com/signinに戻ってきてしまいます。

なんということでしょう!

構成と原因について

色々とチェックしましたが、どれも単体だと問題なさそうです。各設定の連携部分を見直すことにします。基本的な構成はfrontにNginxとbackにTomcatとなっています。それぞれの設定を見直します。

    Nginx.confの一部

    server {
        ...
    
        proxy_set_header      Host              $host;
        proxy_set_header      X-Real-IP         $remote_addr;
        proxy_set_header      X-Forwarded-Proto https;
        
        ...
    }

Nginxでは、X-Forwarded-ProtoヘッダーをTomcatに送ることで、Nginxまでは必ずhttpsを通信していることを約束してます。

server.xmlの一部

    <Server port="8005" shutdown="SHUTDOWN">
        ...
        
        <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
        
            <Valve className="org.apache.catalina.valves.RemoteIpValve" protocolHeader="x-forwarded-proto"/>
            ...
            
        <Host>
        ...
    </Server>

Tomcat には Valve というフィルター機構があり、 RemoteIpValve で Nginx から送られる X-Forwarded-Proto ヘッダーをみて https プロトコルとして処理をさせます。次に、アプリのコードを見て行きます。

Signinの擬似Code

    public void signin() {
        if (request.scheme != "https"){
            response.setRedirect(request.getContextPath());
        }
    }

httpで受け取ると、リダイレクトすることがわかりました。アプリでは、httpsで受け取ってないと判断していたため、リダイレクトされていました。

TomcatのRemoteIpValve の設定を詳しく見て行きます。ここで、RemoteIpValveの期待する動作と実際の動作を比較してみます。

期待する動作にするためにはどうすればいいのでしょうか。ドキュメントを詳しく読むと、上記では設定していなかったinternalProxiesプロパティがあり、以下のとおりの説明でした。

内部プロキシのIPアドレスと一致する正規表現。それらがremoteIpHeader値に表示される場合、それらは信頼され、proxiesHeader値には表示されません

逆を言うと、プロキシのIPアドレスと一致していない場合、信頼されずにhttpとしてTomcatに渡ります。これが原因でした。プロダクション環境では、デフォルト値の 10/8, 192.168/16, 169.254/16, 127/8, 172.16/12に該当したため、何もする必要はありませんでした。

解決

開発環境とプロダクション環境ではプライベートIPのレンジが異なり、RemoteIpValveinternalProxies のデフォルト値にプロダクション環境は該当していたが、開発環境では該当していなかった。そのため、httpsとして渡らず、ログインできない状態になっていた。

これを修正するには、以下のように internalProxiesに該当するレンジを書けばいいだけです。

        
            <Valve className="org.apache.catalina.valves.RemoteIpValve" 
                   protocolHeader="x-forwarded-proto"
                   internalProxies="192\.169\.\d{1,3}\.\d{1,3}"/>
            ...

RemoteIpValveの処理について詳しく知りたい方は、GitHubを詳しく見てください。

こんな感じで、ヌーラボではミドルウェアをガンガン使いこなすようなエンジニアを募集しています。

開発メンバー募集中

より良いチームワークを生み出す

チームの創造力を高めるコラボレーションツール

製品をみる