ブログ

Dockerによるマルチテナント分離のステップバイステップ設計図

ホスティングのオーバーヘッドを抑えながら、Dockerでマルチテナントのワークロードを分離。名前空間、cgroup、ネットワークポリシー、ランタイムの堅牢化の設定方法を解説します。

概要

複数のクライアントキャンペーンや社内Web資産向けに共有インフラを運用していると、ホスティングコストやデータセキュリティをめぐって経営陣との摩擦が生じがちです。Dockerコンテナは専用仮想マシン(VM)に代わる軽量な選択肢ですが、デフォルト設定のままでは深刻な分離ギャップが残ります。真のマルチテナンシーを実現するには、カーネル、プロセス、ネットワーク、ストレージの各レベルで意図的な境界線を設ける必要があります。本ガイドでは、Linuxネイティブの分離プリミティブを活用し、マルチテナントDocker環境をセキュアにするための実践的な5ステップのフレームワークを提供します。リソースクォータの適用、プロセス権限の制限、コンテナネットワークのセグメンテーション、適切な分離ティアの選択方法を学びましょう。この設計図に従うことで、テナント環境を保護しながら、非技術部門のステークホルダーに対してもインフラ予算の妥当性を明確に説明できるようになります。

ある日、技術に詳しくない上司が先月のクラウドホスティングの請求書を手にあなたの席へやって来ます。コストが増加しているにもかかわらず、同時期に行われた新製品のローンチ時に、優先度の高い複数のランディングページでレイテンシのスパイクが発生していました。なぜマーケティング資産でサーバーを共有しているのか、クライアントのデータは漏洩していないのか、そしてなぜすべてのキャンペーンごとに専用の高価な仮想マシンを立ち上げられないのか、説明を求められます。

すべてのデジタル資産に個別の仮想マシン(VM)を割り当てれば「ノイジーネイバー(近隣騒音)」問題は解消しますが、運用予算はあっという間に底をついてしまいます。標準的なDocker構成は、単一のOSカーネル上で複数のサイトを実行することでコスト問題を解決しますが、デフォルトのままでは危険な分離の隙間が残ります。1つのテナントアプリケーションで暴走スクリプトや不正アクセスが発生した場合、そのホスト上に同居するすべてのアプリケーションが危険にさらされることになります。

このステップバイステップの技術設計図を活用して、Dockerで厳格なマルチテナント分離を構成しましょう。システム安定性の維持、テナントデータの分離、そして技術的なインフラ選定を経営陣にとって明確なビジネス価値へと変換するために、これら5つの運用ステップを実装してください。


1. コントロールグループ(cgroup)による厳格なリソースクォータの適用

すべてのコンテナに対して、CPU、メモリ、ディスクI/Oの上限を直ちに明示的に設定してください。複数のテナントが1つのホストを共有している場合、制限のないコンテナはシステムリソースを奪い合います。1つの暴走したデータベースクエリや高トラフィックのキャンペーンがホストのメモリプール全体を消費し、LinuxのOut-Of-Memory(OOM)キラーを発動させて任意のシステムプロセスを強制終了させてしまう恐れがあります。

Linuxのコントロールグループ(cgroups)は、各コンテナが消費できる計算リソース量を制御します。デプロイ定義にこれらの制限を直接適用してください。

services:
  tenant_app:
    image: nginx:alpine
    deploy:
      resources:
        limits:
          cpus: '0.75'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M
  • メモリ上限(limits.memory: 厳格な上限を設定します。コンテナが512MBを超えた場合、カーネルはそのコンテナ内のプロセスを終了させ、隣接する他のテナントに影響を与えません。
  • メモリ予約(reservations.memory: ベースラインとなるメモリ割り当てを保証し、トラフィックの少ないアプリケーションでも安定したレスポンスを維持します。
  • CPU上限(limits.cpus: コンテナが利用できるCPUコアの最大割合を制限し、単一テナントによるCPUの枯渇を防ぎます。

技術系ではない経営陣にこのアーキテクチャを説明する際は、cgroupを「自動化されたデジタルの個別メーター」として例えると効果的です。オフィスビルの各テナントが主幹ブレーカーを落とすことなく個別の電気使用量を支払うのと同様に、cgroupを導入することで、ある高トラフィックなランディングページが原因で他のクライアントのリード獲得ポータルがダウンする事態を確実に防げます。アーキテクチャのトレードオフについての詳細は、マルチテナントアーキテクチャの設計に関するガイドをご覧ください。


2. 名前空間と非rootユーザーによるテナントプロセスの分離

コンテナプロセスをデフォルトのrootユーザーで実行してはなりません。標準的なLinuxコンテナ環境では、明示的に再マッピングされていない限り、コンテナ内のrootはホストカーネル上のrootに対応します。rootとして実行されているWebアプリケーションが攻撃者に侵害された場合、共有ホスト全体に対する昇格した権限を奪われてしまいます。

ユーザー名前空間と非rootでの明示的な実行により、プロセス分離を徹底してください。

  1. 非特権ランタイムユーザーの定義: Dockerfile内で専用の低特権サービスユーザーを作成します。
    FROM php:8.2-fpm-alpine
    RUN addgroup -g 10001 tenantgroup && \n       adduser -u 10001 -D -G tenantgroup tenantuser
    USER tenantuser
    
  2. ユーザー名前空間(userns-remap)の有効化: Dockerデーモン(/etc/docker/daemon.json)を設定し、コンテナのユーザーIDをホスト上の非特権範囲に再マッピングします。
    {
      "userns-remap": "default"
    }
    

Linux名前空間はシステムの可視性を分割します。プロセスID(PID)名前空間により、テナントAがテナントBに属するプロセスを参照、シグナル送信、または終了できないようにします。マウント(MNT)名前空間は各テナントに独立したファイルシステムビューを提供し、IPC名前空間は不正なプロセス間通信をブロックします。

ユーザー名前空間を再マッピングすることで、コンテナ脱出の攻撃経路を無力化できます。コンテナ内で自身をroot(UID 0)と認識しているプロセスも、ホストマシン上では非特権ID(UID 165536など)にマッピングされます。万が一エクスプロイトによってコンテナの障壁が突破されたとしても、攻撃者は非特権シェルの権限しか得られず、ホストの設定変更や隣接するテナントディレクトリへのアクセスはできません。


3. カーネル権限の削減と読み取り専用ファイルシステムの適用

利用可能なLinuxケーパビリティ(Capabilities)を最小限に削ぎ落とし、起動時にコンテナのルートファイルシステムをイミュータブル(不変)に設定します。デフォルトのコンテナランタイムは約十数のLinuxカーネルケーパビリティを付与しますが、その多くはWebアプリケーションにとって不要なものです。過剰なケーパビリティは、ネットワークルーティングの改ざん、ホスト時刻の変更、ファイルアクセス制御の回避などを狙う攻撃者に武器を与えることになります。

デフォルトのケーパビリティをすべて破棄し、運用に必要な最小限のフラグのみを再付与することで、ランタイムコンテナを保護します。

services:
  tenant_web:
    image: custom-nginx:latest
    read_only: true
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
    security_opt:
      - no-new-privileges:true
      - seccomp=default.json
    tmpfs:
      - /tmp:rw,noexec,nosuid,size=64m
      - /var/run:rw,noexec,nosuid,size=16m
  • cap_drop: - ALL: コンテナプロセスからすべてのカーネルケーパビリティを削除します。
  • cap_add: - NET_BIND_SERVICE: 特権ポート(80や443など)へのバインドのみを明示的に許可し、生ネットワークソケットの直接操作はブロックします。
  • read_only: true: コンテナのルートファイルシステム全体を読み取り専用としてマウントします。攻撃者は悪意のあるバイナリをダウンロードしたり、PHPスクリプトを改ざんしたり、Webサーバーの設定ファイルを変更したりできなくなります。
  • tmpfs: 一時ファイル(/tmpなど)に必要なメモリ上の一時ディレクトリを割り当てつつ、バイナリ実行(noexec)および権限昇格(nosuid)をブロックします。

セキュアコンピューティングモード(seccomp)フィルターやAppArmor、SELinuxなどのセキュリティモジュールを適用し、共有ホストカーネルに対して発行されるシステムコールをインターセプトして制限します。カスタムWebアプリケーションビルドを管理している場合は、デプロイパイプライン全体にわたるDockerコンテナの堅牢化の手順に従ってください。


4. テナント環境間のネットワーク分離

デフォルトのブリッジネットワークを無効化し、テナントスタックごとに独立したソフトウェア定義のカスタムブリッジネットワークを構築します。デフォルトでは、標準のDockerブリッジネットワーク上に配置されたコンテナ同士は、内部IPアドレスを通じて互いを検出し通信できてしまいます。1つのテナントのマーケティングマイクロサービスに脆弱性があった場合、そのホスト上にある他のすべての内部データベースやアプリケーションへのラテラルムーブメント(横展開)を許してしまうことになります。

テナントごとに独立したネットワークブリッジを定義し、トラフィックを完全に分離します。

networks:
  tenant_alpha_net:
    driver: bridge
    internal: true
  tenant_beta_net:
    driver: bridge
    internal: true
  public_gateway_net:
    driver: bridge

services:
  alpha_app:
    image: tenant_a_app:latest
    networks:
      - tenant_alpha_net
      - public_gateway_net

  alpha_db:
    image: mariadb:10.11
    networks:
      - tenant_alpha_net

  beta_app:
    image: tenant_b_app:latest
    networks:
      - tenant_beta_net
      - public_gateway_net

  beta_db:
    image: mariadb:10.11
    networks:
      - tenant_beta_net
  • テナント分離: alpha_appalpha_dbtenant_alpha_net経由でのみ通信します。攻撃者が内部サブネットをスキャンしたとしても、beta_appalpha_dbに到達することはできません。
  • Internalフラグ(internal: true: データベースネットワークが外部インターネットへ直接トラフィックをルーティングするのを防ぎ、インバウンドおよびアウトバウンドのアクセスをアプリケーションコンテナのみに制限します。
  • リバースプロキシゲートウェイ: イングレスプロキシのみがpublic_gateway_netに接続し、ホスト名に基づいて受信したHTTP/HTTPSリクエストを指定されたテナントコンテナにルーティングします。

より高度な環境を求める場合は、DockerのEnhanced Container Isolation(ECI)モードやSysboxなどのランタイムの導入を検討してください。これらは複雑な手動ネットワークスクリプトを組むことなく、より厳格なユーザー名前空間の境界や仮想化された/procおよび/sysファイルシステムを自動的に適用します。


5. 客観的なマルチテナント意思決定マトリクスの策定

すべてのデジタル資産に専用仮想マシンが必要であるという思い込みを見直しましょう。マーケティングリーダーは、ハードウェアレベルのVM分離こそが唯一正当化できるセキュリティモデルだと考えがちです。しかし実際には、軽量なランディングページや短期間のキャンペーンサイトに対して専用VMをプロビジョニングすることは、Webアプリケーションのセキュリティを向上させることなく、大幅なコスト膨張と運用の保守負担を生み出すだけです。

以下の比較マトリクスを活用してワークロードの要件を評価し、意思決定者に対して合理的なデプロイ戦略を提示しましょう。

分離ティア基盤技術セキュリティ境界リソースオーバーヘッド最適なユースケース
共有スタックコンテナ単一OS上の名前空間とcgroupOSレベルの論理的分離非常に低いアクセス数の多いLP、社内ステージング、一時的なキャンペーンサイト
堅牢化コンテナ(ECI / Sysbox)ユーザー名前空間、AppArmor、読み取り専用ルート高度なOSレベル分離&仮想化低い複数クライアントを扱う制作会社のホスティング、認証付きポータル、機密性の高いマーケティングフォーム
専用仮想マシン(VM)ハイパーバイザーによるハードウェア仮想化厳格なハードウェア/カーネルの分離高い決済処理、規制対象のHIPAA/PCIデータ、信頼できないカスタムコードの実行
ハイブリッド(専用VM内コンテナ)テナント固有VM内の堅牢化コンテナ多層ハードウェア&OS境界中〜高契約上専用環境の遵守が義務付けられているエンタープライズの重要顧客

インフラ予算を配分する前に、以下の明確な基準に照らして各プロジェクトを評価してください。

  1. データの機密性: クレジットカード情報や医療情報など、法規制の対象となるデータを保存するか? → 該当する場合は、専用VMにデプロイします。
  2. コードの信頼性: チームによって監査された標準コードか、それとも検証されていないサードパーティ製プラグインを許可するか? → 標準コードは堅牢化コンテナに適しており、未検証のサードパーティコードにはハイパーバイザーレベルの分離が必要です。
  3. 予算と運用期間: 季節限定のランディングページや主要な企業Webサイトの場合、堅牢化されたマルチテナントコンテナが最高のコストパフォーマンスを発揮します。

経営陣にインフラ計画を提案する際は、ティアに基づいた明確な論拠で提言を裏付けるために、クライアントに専用VMが必要なタイミングの評価に関するガイドもご参照ください。


まとめ:セキュリティ統制をビジネスROIへと変換する

マルチテナントDocker環境の保護に、エンタープライズ向けの大規模なクラウドアクティビティ予算は必須ではありません。必要なのは、オペレーティングシステムレベルの制御を規律を持って厳格に適用することです。

非技術部門のリーダー層とインフラの見直しを行う際は、これらの技術的構成を以下の3つの経営指標に落とし込んで説明してください。

  • コスト効率: マルチテナントコンテナを採用することで、個別のVMを立ち上げる場合に必要なコンピュートリソースのわずか数分の一で、何十ものマーケティングサイトをホストできます。
  • 稼働率の保護: コントロールグループ(cgroup)により、季節限定キャンペーンにトラフィックが急増しても、コアブランドサイトのパフォーマンスが低下することはありません。
  • 被害範囲(ブラスト半径)の極小化: 読み取り専用ファイルシステム、ケーパビリティの削除、分離されたネットワークブリッジにより、単一サイトで侵害が発生しても、隣接するクライアントのデータベースやホスト制御への波及を確実に遮断できます。

コンテナテンプレート全体にこれらのガードレールを体系的に導入しましょう。これにより、エンジニアリングのセキュリティ基準と経営陣の予算制約の双方を満たす、高性能で費用対効果の高いインフラを実現できます。

Sources (5)