🔒

Herokuで固定IPを使用する方法 - QuotaGuardの活用

2024/11/21に公開

はじめに

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を選択しました。

導入手順

  1. 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アドレスをホワイトリストに登録して使用します。

  1. アドオン追加後、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クライアントとの互換性が高い

この実装で無事通信できました!気持ちいい!

実運用での注意点

  1. SSL設定: 本番環境ではrejectUnauthorized: trueに設定し、適切な証明書を使用することを推奨します。

  2. IP確認: QuotaGuardは2つの固定IPを提供します。どちらのIPからもアクセスがある可能性があるため、両方をホワイトリストに登録する必要があります。

  3. プラン選択: トラフィック量に応じて適切なプランを選択しましょう。開発環境でのテストも含め、利用には適切な有料プランの選択が必要です。プランについては公式サイトでご確認ください。

  4. Heroku Schedulerとの連携における注意点: 当社の実装では、Heroku Schedulerを使用して1日1回PostgreSQLへのリクエストを行うバッチ処理を実装しています。この際、ローカル環境からQuotaGuardを経由したリクエストをトリガーすると、想定以上の通信が発生することがあります(公式サポートにも問い合わせましたが、原因はわからず...)。しばらく放置すると正常な通信頻度に戻りますが、月間の通信回数制限を超過するリスクがあるため、開発・テスト時もなるべくHeroku Scheduler経由での実行を推奨します。

まとめ

QuotaGuardを活用することで、Herokuの柔軟性を維持しながら、固定IP制限のあるサービスとも安全に連携することができます。当社の事例でも、この方法でセキュアなデータ連携を実現できました。

TamaT LLC

Discussion