前提条件
マイクロサービスをdocker composeで動かしていました。
Ruby on RailsでできたAPIサーバーのRailsのバージョンを6.1.4.1に上げました。
するとAPIサーバーは 403 Forbidden
を返すようになりました。
奇妙なことに、ホストOSからリクエストを送ると 200 OK
が返ってきます。
Dockerコンテナで起動している別のWebアプリケーションから、Dockerコンテナで起動しているAPIサーバーを呼び出すと 403 Forbidden
が返ってきます。
また、403 Forbidden
を返すときはAPIサーバーのコンテナでログが出力されません。
ユージュアル・サスペクツ
最初の容疑者 Docker
Dockerで動かすと上手く動かないので、DockerとDocker Composeを疑いました。 次のような項目を確認しました。
- docker-compose.ymlのポートの設定
- Railsの起動コマンドの
-b 0.0.0.0
オプション
不審な点はありません。
第二の容疑者
つぎに、APIサーバーと通信するクライアントにRest Clientを使っていたので、これを疑いました。 なにか問題があるのかもしれません。
RestClient::Request.execute method: :post, url: url, payload: payload
を、Net::HTTP
で次のように置き換えてみました。
uri = URI(url) req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json') req.body = payload.to_json res = Net::HTTP.start(uri.hostname, uri.port) do |http| http.request(req) end
特に変わらず 403 Forbidden
が返ってきます。
もう、クライアント側のWebアプリケーション自体が邪魔です。 クライアント側のDockerコンテナに入って、irbを起動して次のようにHTTPリクエストを送ってみました。
Net::HTTP.get(URI('http://lodqa_bs:3000/searches'))
POST
リクエストを作るのが面倒だったので、とりあえず GET
リクエストを送信してみました。
対象はAPIサーバーですが、管理用のページもあります。
すると、こんな感じのHTML(整形してあります)が返ってきました。
<body> <header> <h1>Blocked host: lodqa_bs</h1> </header> <div id=\"container\"> <h2>To allow requests to lodqa_bs, add the following to your environment configuration:</h2> <pre>config.hosts << \"lodqa_bs\"</pre> </div> </body>
名探偵はひらめきました。 ひらめいたっていうか、Railsからの「設定を変えろ」というメッセージを読みとりました。
犯人
もうね、「Blocked host rails」でググれば犯人特定ですよ。 犯人はRails 6.0から導入された「DNSリバイディング攻撃対策」でした。 とはいえ、証拠は必要です。 「DNSリバイディング攻撃対策」では、承認済みのホスト名を登録すれば回避できるようです。
config/environments/development.rb
に
config.hosts << 'lodqa_bs'
を追加して、200 OK
が返ってくれば万事解決です。
ところが返ってくるのは 403 Forbidden
です。
ポート番号の指定が必要かとかproductionモードで動かしていたかとか悩みました。
設定を変えて試してみました。
結果、現象を整理すると、
config/environments/development.rb
に
config.hosts.clear
と書いたり
config/application.rb
に
config.middleware.delete ActionDispatch::HostAuthorization
を書いたら 200 OK
が返ってきます。
つまり、機能全体を無効化すれば200 OK
が返ってきます。
やはり、犯人はこいつです。
しかし、なぜ lodqa_bs
は追加できないのでしょうか?
残された謎
名探偵は灰色の脳細胞の力を使って次のissueを見つけました。
RFCではホスト名に_
を使うことが許可されていますが、多くのDNSサーバーやネットワークでは_
をホスト名に使えません。
ドメイン名としても有効ではありません。
このためRailsではconfig.hosts
に_
を含むホスト名が指定されても無視します。
というわけで、ホスト名、というか 「docker-compose.yml
で指定するサービス名」を lodqa_bs
から lodqa-bs
に変更して、万事解決しました。
めでたしめでたし。
slack上の記録によると調査開始が11:29、完了が14:17。約3時間の探偵ごっこでした。