Feedforce Developer Blog

フィードフォース開発者ブログ

Heroku で Chrome を使ったクローラの IP アドレスを固定する

こんにちは id:masutaka26 です。

少し前に、Heroku の worker Dyno 上で動く、Chrome のクローラで IP アドレスを固定化出来ないか調査しました。

実装は見送られましたが、想定よりも難しく調査に時間がかかったので、この記事に残しておきます。

方法だけ知りたい方は、下の方にある「手順」をご覧ください。

Heroku Add-on を比較する

今回は ProximoQuotaGuard Static を検討し、最終的に QuotaGuard Static を採用しました。

💡 他に Fixie, Fixie Socks, Guru301 などがあるようです。

以下、その理由です。

開発組織

Proximo は https://github.com/pirateradio を見た感じ @ddollar の個人開発のようです。この方は foreman などを作っており、多分すごい人です。

QuotaGuard Static は https://www.quotaguard.com/ によると Alpine Shark, LLC のようです。会社のほうがちょっとだけ安心できます。

実装

Proximo は 1 つのようですが、QuotaGuard Static は 2 つの Proxy サーバで冗長化されているようです。Proxy サーバが落ちる確率は低いかもしれませんが、冗長化されているに越したことはありません。

🔗 https://devcenter.heroku.com/articles/proximo#provisioning-the-proximo-add-on

$ heroku addons:create proximo:development
Adding proximo to sharp-mountain-4005... done, v18 ($5/mo)
Your static IP address is 10.9.8.7

🔗 https://devcenter.heroku.com/articles/quotaguardstatic#provisioning-the-add-on

$ heroku addons:create quotaguardstatic:starter
-----> Adding quotaguardstatic:starter to sharp-mountain-4005... done, v18 (free)
-----> Your static IPs are [10.11.12.13, 14.15.16.17]

プラン

QuotaGuard Static は無料プランがあるので始めやすいです。Proximo のプランは $5/mo からです。

ちなみにどちらも PROXIMO_MASKQUOTAGUARDSTATIC_MASK という環境変数を設定すると、一部のレンジの送信だけこれらのサービス経由にすることができ、料金を節約できます。

💡 正確に書くと QUOTAGUARDSTATIC_MASK は後述する qgsocksify 用の環境変数です。

CLI のインストール

どちらも CLI が提供されており、必要に応じてインストールします。

Proximo はインストール元が http なのがイマイチでした。https に変えてもアクセス不可です。

$ curl http://downloads.proximo.io/proximo-stacklet.tgz | tar xz

QuotaGuard Static は普通に https でインストール出来ます。

$ curl https://s3.amazonaws.com/quotaguard/qgtunnel-latest.tar.gz | tar xz
$ curl https://s3.amazonaws.com/quotaguard/quotaguard-socksify-latest.tar.gz | tar xz

Heroku Buildpack

今回の調査の過程で Heroku Buildpack を作りました。バイナリファイルをリポジトリに commit せずに済みます。よかったらどうぞ。

固定 IP アドレスへの私見

IP アドレスを固定化したいのは、どんなケースでしょうか。

多くはセキュリティ要件だと思いますが、私はあまり賛同できないです。

そもそも当該 IP アドレスは認証されておらず、所有者が変わることがあります。仕組み上それに気づくことは難しいため、逆にセキュリティリスクを増やすことになります。そういう意味では電話番号とよく似ています。

サービスのスケールの観点からもデメリットがあります。例えば Heroku から AWS に引っ越す時、固定 IP アドレスは変わってしまうでしょう。顧客との調整が必要ですし、間に開発会社が入っていると、より時間がかかります。

Chrome のクローラで IP アドレスを固定化する

今回のケースでは Heroku の worker Dyno 上に sidekiq が起動しており、selenium-webdriver 経由で Chrome が子プロセスとして起動し、クロールします。

sidekiq
└ Chrome
   ↓
   クロール先

試行錯誤の日々

当初は sidekiq 自体に qgtunnel や qgsocksify をラップしましたが、うまくいきませんでした。よく考えたら納得です。

Chrome に --proxy-server=http://<USERNAME>:<PASSWORD>@<HOSTNAME>:<PORT>--proxy-auth=<USERNAME>:<PASSWORD> を指定してもダメ。

どうやら少なくとも Chrome 73 ではセキュリティ上の理由から、コマンドラインオプションから認証情報を設定できないようです。認証なしプロクシなら大丈夫ですが、QuotaGuard Static は商用サービスなので認証は必須です。

ついに成功

ダメ元で QuotaGuard Static のサポートに聞いたら、方法を知っており、無事クロール先にアクセスすることが出来ました。

👇 Dyno とクロール先を SOCKS5 トンネルで繋ぎ、それ経由でアクセスします。

sidekiq
└ Chrome (4443 port)
   ↓ (SOCKS5 tunnel)
   QuotaGuard Static
   ↓ (SOCKS5 tunnel)
   クロール先 (443 port)

TCP アクセスならなんでも IP アドレスを固定化出来そうです。

手順

(1) 当該 Heroku App に QuotaGuard Static Add-on をインストールします。

(2) qgtunnel CLI もインストールします。前述の heroku-buildpack-qgtunnel を使うとお手軽です。

$ curl https://s3.amazonaws.com/quotaguard/qgtunnel-latest.tar.gz | tar xz

(3) Heroku のダッシュボードから、QuotaGuard Static のダッシュボードに進み、SettingsSetup とクリックします。

f:id:masutaka26:20190425193848p:plain

(4) さらに TunnelCreate Tunnel とクリックします。

f:id:masutaka26:20190425192905p:plain

(5) Remote Destination にクロール先を、Local Port は 4443、Transparent は true に設定します。Encrypted は設定しません。

f:id:masutaka26:20190425193342p:plain

(6) トンネルが出来ました。

f:id:masutaka26:20190425193614p:plain

  • 127.0.0.1:4443 へのアクセスは destination.example.com:443 へのトンネルになります
  • Transparent を有効したことにより、destination.example.com の DNS が 127.0.0.1 に上書きされました。destination.example.com:4443 へのアクセスは destination.example.com:443 と等価になります
  • すでに HTTPS を使っているため、Encrypted は必要ありません

(7) selenium-webdriver に与える Chrome のバイナリを qgtunnel でラッピングします。今回は以下のようなシェルスクリプト bin/google-chrome-qgtunnel を作り、selenium-webdriver に指定しました。

#!/bin/sh -eu

exec bin/qgtunnel "$GOOGLE_CHROME_SHIM" "$@"

💡 heroku-buildpack-google-chromeheroku-buildpack-chromedriver を使っています。環境変数 GOOGLE_CHROME_SHIM/app/.apt/usr/bin/google-chrome です。

(8) 左側の Outbound をクリックし、SOCKS5 url を Heroku の環境変数 QUOTAGUARDSTATIC_URL に上書きします。

f:id:masutaka26:20190425191501p:plain

(9) 左側の Tunnel から Download Configuration をクリックし、.qgtunnel ファイルをリポジトリに commit します。

f:id:masutaka26:20190425203447p:plain

(10) 以上の設定により、destination.example.com:4443 へのアクセスが destination.example.com:443 に変換され、且つ IP アドレスも固定されます。

なにかトラブルがあったら Heroku の環境変数 QGTUNNEL_DEBUG に true をセットして、ログを確認すると良いと思います。

QuotaGuard Static の注意事項

app.json の addons に quotaguardstatic を追加して、Review App を作ると Micro plan $19/mo で作られてしまいます。quotaguardstatic:starter とかにしても同じです。

QuotaGuard Static のサポートに聞いたところ、Heroku のアカウント単位で設定を変える必要があるそう。問い合わせが必要です。

まとめ

Heroku の worker Dyno 上で動く、Chrome のクローラで IP アドレスを固定化しました。

固定 IP アドレス対応は出来るだけ避けたほうが良いと思いますが、どうしても必要な時にこの記事が参考になれば幸いです。