こんにちは id:masutaka26 です。
少し前に、Heroku の worker Dyno 上で動く、Chrome のクローラで IP アドレスを固定化出来ないか調査しました。
実装は見送られましたが、想定よりも難しく調査に時間がかかったので、この記事に残しておきます。
方法だけ知りたい方は、下の方にある「手順」をご覧ください。
Heroku Add-on を比較する
今回は Proximo と QuotaGuard 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_MASK
や QUOTAGUARDSTATIC_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 せずに済みます。よかったらどうぞ。
- https://github.com/masutaka/heroku-buildpack-proximo
- https://github.com/masutaka/heroku-buildpack-qgtunnel
- https://github.com/masutaka/heroku-buildpack-qgsocksify
[コラム] 固定 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 のダッシュボードに進み、Settings
→ Setup
とクリックします。
(4) さらに Tunnel
→ Create Tunnel
とクリックします。
(5) Remote Destination
にクロール先を、Local Port
は 4443、Transparent
は true に設定します。Encrypted
は設定しません。
(6) トンネルが出来ました。
- 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-chrome と heroku-buildpack-chromedriver を使っています。環境変数 GOOGLE_CHROME_SHIM
は /app/.apt/usr/bin/google-chrome
です。
(8) 左側の Outbound
をクリックし、SOCKS5 url を Heroku の環境変数 QUOTAGUARDSTATIC_URL
に上書きします。
(9) 左側の Tunnel
から Download Configuration
をクリックし、.qgtunnel
ファイルをリポジトリに commit します。
(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 アドレス対応は出来るだけ避けたほうが良いと思いますが、どうしても必要な時にこの記事が参考になれば幸いです。