Herokuで固定IPを使用する方法 - QuotaGuardの活用
はじめに
Herokuは柔軟なスケーリングを実現するため、動的なIPアドレスを使用します。これにより、インスタンスの起動や停止を効率的に行えますが、外部システムとの連携時にIP制限が課題となることがあります。
当社でも、あるプロジェクトで外部のPostgreSQLデータベースにアクセスし、ヘッドレスCMSにデータを加工してPOSTするバッチ処理の開発時に、この課題に直面しました。
今回は、この課題をQuotaGuardを使って解決した方法をご紹介します。
なぜHerokuは固定IPを持たないのか
Herokuはコンテナベースのプラットフォームで、アプリケーションは「Dyno」と呼ばれる軽量なコンテナ上で実行されます。スケーラビリティとリソースの効率的な利用のため、これらのDynoは動的に作成・破棄され、そのたびにIPアドレスも変更されます。
この仕組みは通常のWebアプリケーション運用では利点となりますが、IP制限のある外部システムとの連携時には課題となります。
アドオンの選定プロセス
固定IP実現のためのHerokuアドオンとして、主に以下の3つを検討しました:
- QuotaGuard
- Fixie Socks
- Proximo
検討の結果、以下の理由からQuotaGuardを採用しました:
- Fixie Socksは、先人の実装事例から仕様面での課題が指摘されていました。
- ProximoはTCP/IP接続に対応していないため、PostgreSQL接続には適していませんでした。
- 色々と試行錯誤した結果、QuotaGuardの導入でなんとか固定化に成功しました。ドキュメントも充実していました。
解決策:QuotaGuardの導入
QuotaGuardは、Herokuアプリケーションに固定IPアドレスを提供するアドオンです。以下の3種類のサービスが用意されています:
- QuotaGuard: 動的IPセット経由でのルーティング
- QuotaGuard Static IP's: 固定IPアドレス経由でのルーティング
- QuotaGuard Shield: HIPAA準拠の高セキュリティ固定IP
今回のケースでは、PostgreSQLへの接続に固定IPが必要なため、QuotaGuard Static IP'sを選択しました。
導入手順
- HerokuのCLIを使用して、QuotaGuard Staticを追加します:
$ 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]
アドオンの追加が完了すると、固定IPアドレスが表示されます。これらのIPアドレスをホワイトリストに登録して使用します。
- アドオン追加後、
QUOTAGUARDSTATIC_URL
という環境変数が自動的にアプリケーションの設定に追加されます。この環境変数には、プロキシリクエストに使用する完全なURLが含まれています。これを控えておき、Node.jsの環境変数に追加します。以下のコマンドで確認できます:
$ heroku config:get QUOTAGUARDSTATIC_URL
http://user:pass@static.quotaguard.com:9293
この環境変数の値には、以下の情報が含まれています:
- プロキシサーバーのホスト名
- 認証情報(ユーザー名とパスワード)
- ポート番号
これらの情報を使用して、次のステップではアプリケーションの接続設定を行います。
QuotaGuardのコンソール画面からも確認できます。
実装例:Node.jsでの接続設定
今回の実装では、socksjs
というライブラリを使用しました。このライブラリは、SOCKS5プロキシを通じたTCP接続を簡単に実現できる点が特徴です。特に、PostgreSQLクライアントとの親和性が高く、安定した接続を実現できました。
const pg = require("pg");
require("dotenv").config();
const SocksConnection = require("socksjs"); // socksjsを使用
const url = require("url");
const fs = require("fs");
// QuotaGuardのURL(環境変数)からプロキシ情報を抽出
const quotaGuardUrl = process.env.QUOTAGUARDSTATIC_URL;
const proxy = url.parse(quotaGuardUrl);
const auth = proxy.auth;
const username = auth.split(":")[0];
const pass = auth.split(":")[1];
// SOCKS接続のオプション設定
const sockOptions = {
host: proxy.hostname,
port: 1080, // SOCKS5用のポート
user: username,
pass: pass,
};
// PostgreSQL接続情報
const pgServer = {
host: process.env.DB_HOST,
port: process.env.DB_PORT,
};
// socksjsを使用してSOCKS接続を確立
const sockConn = new SocksConnection(pgServer, sockOptions);
const connectionConfig = {
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
stream: sockConn, // socksjsのコネクションを使用
ssl: {
rejectUnauthorized: false,
ca: fs.readFileSync("getPostgreSQL/cert/root.crt").toString(),
},
};
const client = new pg.Client(connectionConfig);
socksjs
の使用により、以下のメリットが得られました:
- TCPレベルでの接続をシンプルに実装可能
- PostgreSQLクライアントとの互換性が高い
この実装で無事通信できました!気持ちいい!
実運用での注意点
-
SSL設定: 本番環境では
rejectUnauthorized: true
に設定し、適切な証明書を使用することを推奨します。 -
IP確認: QuotaGuardは2つの固定IPを提供します。どちらのIPからもアクセスがある可能性があるため、両方をホワイトリストに登録する必要があります。
-
プラン選択: トラフィック量に応じて適切なプランを選択しましょう。開発環境でのテストも含め、利用には適切な有料プランの選択が必要です。プランについては公式サイトでご確認ください。
-
Heroku Schedulerとの連携における注意点: 当社の実装では、Heroku Schedulerを使用して1日1回PostgreSQLへのリクエストを行うバッチ処理を実装しています。この際、ローカル環境からQuotaGuardを経由したリクエストをトリガーすると、想定以上の通信が発生することがあります(公式サポートにも問い合わせましたが、原因はわからず...)。しばらく放置すると正常な通信頻度に戻りますが、月間の通信回数制限を超過するリスクがあるため、開発・テスト時もなるべくHeroku Scheduler経由での実行を推奨します。
まとめ
QuotaGuardを活用することで、Herokuの柔軟性を維持しながら、固定IP制限のあるサービスとも安全に連携することができます。当社の事例でも、この方法でセキュアなデータ連携を実現できました。
Discussion