Linux上でGreenbone Vulnerability Management(OpenVAS)をセルフホスト:本番運用6ヶ月のレビュー

Security tutorial - IT technology blog
Security tutorial - IT technology blog

デプロイ手法の比較:ベアメタル vs ソースビルド vs Dockerコンテナ

6ヶ月前、私たちのセキュリティチームは高額な商用脆弱性スキャナーのリプレイスに着手しました。社内のDebian 12サーバー上に、セルフホスト型のGreenbone Vulnerability Management(GVM / OpenVAS)環境を立ち上げたのです。

GVMを調べたことがある方ならご存知の通り、これは単一のモノリシックなバイナリではありません。OpenVASスキャナーエンジン(openvas-scanner)、管理デーモン(gvmd)、Webインターフェース(gsa)、認証情報サービス(gsad)、一時的なKVSとしてのRedis、バックエンドのPostgreSQLデータベースといった、相互に依存し合うマイクロサービスの集合体です。

本番環境へ投入する前に、ステージング検証環境で3つのデプロイ戦略をテストしました。

  • OS標準のパッケージリポジトリ(ベアメタル / APT): DebianやUbuntuのパッケージメンテナーによる更新は、アップストリームのリリースより数ヶ月遅れることがよくあります。最初のテスト期間中、OSのセキュリティパッチ適用によってlibgvm共有ライブラリが破損し、PostgreSQLのスキーマとの整合性が崩れてしまいました。その結果、スキャンキューが停止し、丸半日の検証作業が無駄になりました。
  • ソースコードからのビルド: 各デーモンを手動でコンパイルすれば、コンパイル時フラグやカスタムライブラリのパスを細かく制御できます。しかし、継続的な運用保守のオーバーヘッドは過酷を極めます。フィード更新の同期、CMake・Rust・Clangツールチェーンの追従、動的リンクエラーのトラブルシューティングなどにより、毎月8〜12時間ものエンジニアリング工数が日常的なアップデートだけで奪われていきました。
  • Docker Composeによるコンテナ化スタック: 最終的に、これが明確な勝者となりました。GreenboneはGreenbone Community Feedと同期された公式コンテナイメージをメンテナンスしています。各コンポーネントは内部Dockerブリッジネットワークと共有Unixドメインソケットを介して隔離されたコンテナ内で動作します。データベースのスキーママイグレーションやフィードの同期も、専用のヘルパーコンテナが自動的に処理してくれます。

本番環境でOpenVASを運用するメリットとデメリット

この半年間、12のステージングクラスタ、4つの内部VLAN、24台の外部向けリバースプロキシを対象に、週次の定期スキャンを実施してきました。その中で見えてきたプラットフォームの優れた点と、頭を悩まされた課題を挙げます。

メリット

  • ホスト単位のライセンス費用がゼロ: 商用のエンタープライズツールでは、アクティブなIPアドレス1個につき年間30〜50ドルが請求されることが珍しくありません。セルフホスト型GVMなら、予算の制約を気にすることなく、450台以上の一時的なステージングインスタンスや内部サブネットを定期的にスキャンできます。
  • 充実したコミュニティ脆弱性フィード: Greenbone Community Feedは毎日更新され、150,000件以上のネットワーク脆弱性テスト(NVT)が提供されています。運用3ヶ月目だけでも、外部監査員に指摘される前に、14個の脆弱なOpenSSLパッケージ、3個の脆弱なSSH暗号スイート、複数の未パッチなNginxリバースプロキシヘッダーを検知できました。
  • 厳格なデータ局所性(データローカリティ): スキャン対象、認証スキャン用のログイン情報、ネットワークトポロジーマップが、プライベートデータセンターの外へ送信されることは一切ありません。

デメリット

  • 高いメモリおよびCPU負荷: OpenVASは非常にリソースを消費します。完全なNVTフィードをパースしてRedisにインデックス化するだけで、起動直後に約4GB〜6GBのRAMを必要とします。2つの/24サブネットに対して並行スキャンを実行した際には、割り当てていた8 vCPUすべてのCPU使用率が95%まで跳ね上がりました。
  • フィード同期の不安定さ: アップストリームのコミュニティフィード用rsyncミラーは、トラフィックのピーク時にレートリミットがかかったり接続が切断されたりすることがあります。適切なリトライロジックと永続ボリュームによるキャッシュを用意していなかった当初は、自動実行される日次同期ジョブが月に2回ほど失敗していました。
  • ポリシータスクの調整には相応の手間がかかる: 「Full and Fast」のようなデフォルトのスキャンプロファイルは、ステートフルインスペクションやレートリミットを実施しているファイアウォールに過剰なトラフィックを浴びせてしまいます。実際、初期設定時にはエッジファイアウォールがスキャンパケットの半分をSYNフラッド攻撃と誤検知してドロップしてしまいました。ポートリストやスキャンのタイミングパラメータを調整し、ノイズのない安定したスキャンを実現するまでに3週間を要しました。

推奨構成:ハードウェアおよびアーキテクチャ要件

リソースのサイジングは、GVMデプロイの成否を分ける極めて重要な要素です。2GBや4GBのバースト型クラウドVPSで動かすのは現実的ではありません。フィードのコンパイル段階で、LinuxのOOM(Out Of Memory)キラーによってgvmdやRedisが強制終了されてしまいます。

  • コンピュート: 最低4 vCPU(複数のターゲットに対して並行スキャンを実行する場合は8 vCPUを推奨)。
  • メモリ: 16GB RAM(8GBが絶対的な下限値ですが、フィード更新時のバッファは残りません)。
  • ストレージ: 100GB SSD/NVMe(NVT定義、PostgreSQLのインデックス、過去のスキャンレポートにより、6ヶ月間の実運用後で約35GBを消費します)。
  • オペレーティングシステム: Debian 12 (Bookworm) または Ubuntu 22.04/24.04 LTS(Docker Engine 24以降およびDocker Compose V2が稼働していること)。
  • ネットワーク: 管理インターフェースは社内管理用のVLAN上に配置してください。リバースプロキシやVPNトンネルを介さずに、ポート9392を直接パブリックインターネットに公開することは絶対に避けてください。

実装ガイド:Docker ComposeによるGVMのデプロイ

このデプロイパターンにより本番ホストは安定し、ホストOSのカーネルアップグレードを何度もダウンタイムなしで乗り切ることができました。

1. ホストの準備とカーネルパラメータのチューニング

Redisが接続を切断することなくGVMの大量のソケットトラフィックを処理できるようにするには、特定のカーネル設定を適用する必要があります。Linuxホストにログインし、メモリのオーバーコミット設定を適用します。

# Redis用のメモリオーバーコミットを有効化
sudo sysctl -w vm.overcommit_memory=1
echo "vm.overcommit_memory = 1" | sudo tee -a /etc/sysctl.d/99-gvm.conf

# 専用ディレクトリ構造の作成
sudo mkdir -p /opt/greenbone-community-container
cd /opt/greenbone-community-container

2. データベースおよび管理者認証情報の保護

サービスを起動する前に、PostgreSQLバックエンドとプライマリWeb GUI管理者アカウント用に強力なパスワードを生成します。漏洩リスクのないサーバー用シークレットを生成する手段として、私はtoolcraft.app/ja/tools/security/password-generatorのパスワードジェネレーターを使用しています。すべてブラウザ内で完結して動作するため、データがネットワーク経由で送信される心配がありません。生成した文字列を、権限を制限した.envファイルに保存します。

cat << 'EOF' > .env
POSTGRES_USER=gvmd
POSTGRES_PASSWORD=ここに強力なPOSTGRESパスワードを入力
ADMIN_PASSWORD=ここに強力なADMINパスワードを入力
EOF
chmod 600 .env

3. マルチコンテナスタックの定義

Greenboneは公式のコミュニティ向けcompose定義を提供しています。デーモングループを管理するために、アップストリームのcomposeファイルをダウンロードして確認します。

# 公式のGreenbone Docker Composeマニフェストをダウンロード
curl -f -O https://greenbone.github.io/docs/latest/_static/docker-compose-22.4.yml
mv docker-compose-22.4.yml docker-compose.yml

docker-compose.ymlファイルを確認し、ポートバインディングがセキュリティポリシーに準拠しているか確認します。デフォルトでは、Greenbone Security Assistant(GSA)のWeb UIはホストのポート9392:80にバインドされます。このサービスはローカルホスト(127.0.0.1:9392:80)にバインドしたままにし、Nginxリバースプロキシ、WireGuardトンネル、またはSSHポートフォワーディングを介してTLSを終端することをおすすめします。

# すべてのGVMサービスをバックグラウンドで起動
docker compose -f docker-compose.yml up -d

4. 脆弱性フィードの同期

コンテナの初期化が完了したら、ネットワーク脆弱性テスト(NVT)、SCAPデータ、CERTデータを取得します。この初回の同期では、約4GBの脆弱性シグネチャがダウンロードされます。回線速度やミラーサーバーの混雑状況によって異なりますが、15〜45分程度かかります。

# 各コンポーネント間でフィードの同期を実行
docker compose -f docker-compose.yml exec -u gvmd gvmd greenbone-feed-sync --type GVMD_DATA
docker compose -f docker-compose.yml exec -u gvmd gvmd greenbone-feed-sync --type SCAP
docker compose -f docker-compose.yml exec -u gvmd gvmd greenbone-feed-sync --type CERT

5. 管理者アカウントの初期化とフィードの検証

.envファイルに保存した認証情報を使用して、Web GUIの管理者パスワードを設定します。

# 管理者アカウントを作成またはリセット
docker compose -f docker-compose.yml exec -u gvmd gvmd gvmd --user=admin --new-password="$ADMIN_PASSWORD"

続いて、PostgreSQLが脆弱性定義のインデックス作成を行っている間、管理デーモンのログを追尾します。

# フィード処理のログステータスを確認
docker compose -f docker-compose.yml logs -f gvmd

完了を示すメッセージ(Updating VTs in database... done (XXXXX VTs))が表示されるのを確認してください。その行が出力されたらブラウザを開き、https://your-server-ip:9392(またはリバースプロキシのURL)にアクセスしてadminとしてログインし、Configuration > Targetsから最初のスキャン対象サブネットを設定しましょう。

コンテナ化のアプローチを採用したことで、OpenVASは壊れやすくメンテナンスに追われる厄介者から、社内インフラを支える信頼性の高い独立した脆弱性検知エンジンへと生まれ変わりました。

Share: