ブログ

実際に独自のVMが必要なクライアントは?段階的Docker分離プラン

すべてのクライアントにVMを用意するのは過剰です。各テナントに必要な分離レベルを判断し、その決定を自動化する方法を説明します。

概要

クライアントが自社のデータが他のテナントからどれだけ隔離されているかを尋ねると、エージェンシーはしばしば慌ててしまいます。Dockerの名前空間とcgroupは実際の隔離を提供しますが、ハードウェア境界とは同じではありません。すべてのクライアントをVMで実行するのではなく(あるいはさらに悪いことに、すべてのクライアントを同じように扱うのではなく)、少数の隔離ティアを構築し、データの機密性、信頼性、コンプライアンスに基づいて各クライアントをいずれかのティアにマッチングさせます。ロックダウンされたコンテナ(非root、機能の削除、seccomp、読み取り専用ルート)はほとんどのサイトをカバーしますが、規制対象または敵対的なワークロードにはVMまたはコンテナインハイブリッドを使用します。この記事では、再現可能な決定フロー、比較表、そしてより多くの隔離が過剰である場合の正直な見解を提供します。

セールスコールで、新しいクライアントが「医療業界なので、データが他のクライアントから隔離されていることを示してください」と言い、あなたが他の何について話したいと思っているところですか?

これがエージェンシーの問題です。完璧なデプロイメントが1つあるのではなく、同じ信頼できるデプロイメントを、予算、リスクプロファイル、コンプライアンス要件が異なる12のクライアントに繰り返し適用することです。正直なバージョンはこうです。Dockerの分離は現実的ですが、特定的です。名前空間は各コンテナにプロセス、ネットワーク、ファイルシステムの独自のビューを提供します。cgroupはCPU、メモリ、ディスクI/Oを制限し、テナントが互いに枯渇させないようにします。しかし、それがもたらさないのは、コンテナとホストカーネルの間のハードウェア壁です。攻撃者がコンテナから脱出した場合、彼らはあなたが持っている唯一のカーネルの中にいます。この記事の残りは、その不快な事実を再現可能な決定に変えます。データの機密性と信頼性に基づいて各クライアントを分類し、ベースラインの強化プロファイルを適用し、侵害のコストがVMのコストよりも高い場合にのみVMに手を伸ばします。

待って、コンテナはすでに分離されているんじゃないの?

DockerはLinuxの名前空間とcgroupの上で動作しており、これらの言葉は実際の作業を行っています。名前空間はプロセスID、ネットワークスタック、マウントポイント、ユーザーを分離し、あるコンテナのプロセスが別のプロセステーブルを見られないようにします。cgroupは制限を設定します。コンテナに0.5 CPU、512 MBのメモリ、固定のブロックI/Oウェイトを与えると、それがそのまま割り当てられます。あるテナントの暴走ループは、隣人をダウンさせる代わりにスロットリングされます。制限を設定していない場合、cgroupの最も基本的な目的をスキップしていることになります。

コンテナAで単純なPHPアプリを考えます。それは独自のファイルシステム、独自のネットワークインターフェース、独自のPID 1を見ます。コンテナBも同じですが、異なるビューです。それが名前空間です。ここでメモリ制限をせずに放置すると、コンテナAはホストのRAMを埋め尽くし、コンテナBを遅くする可能性があります。それを防ぐためにcgroupが存在します。しかし、2つのコンテナは名前空間によって互いに分離されている一方で、ホストカーネルを共有しています。それがすべてのコンテナ脱出ストーリーの核心です。カーネルに到達するエクスプロイトは、そのホスト上のすべてのテナントに到達する可能性があります。

「Dockerは分離されている」という文は半分真実です。正確なバージョンは「Dockerは名前空間とcgroupで分離し、カーネルの脆弱性が爆発半径である」です。信頼できないコードを実行させるテナントを信頼する前に、その考えを少しの間考えてみてください。答えは「コンテナを使わない」ではありません。それは簡単なパニックです。答えはティアシステムです。

では、なぜ一部のクライアントは名前空間以上のものを必要とするのでしょうか?

正直な答えは、分離はスイッチではなく、スペクトラムであるということです。一方の端には、全員が事実上1つのアプリにいる完全に共有されたコンテナがあります。もう一方の端には、独自のカーネルを持つテナントごとのVMがあります。ほとんどのエージェンシーの仕事は、居心地の悪い中間にあります。中間は「Dockerで十分」と「全員にVMを実行する」の間の二択ではありません。

クライアントを右側に押し出すのは、その規模ではありません。それは4つの質問です。

  • 規制対象データを保存していますか?健康記録、カード支払い詳細、規制当局が機密と見なすものすべて。
  • そのテナントでの侵害が別のテナントへの現実的な経路を持っていますか?任意のコードを実行できるなら、はい。
  • コードとそれをデプロイする人々を信頼していますか?最安のフリーランサーを雇うクライアントは、あなたが知っている開発チームを持つクライアントと同じ信頼レベルではありません。
  • 契約に「専用」「分離」「プライベート」と書かれていますか?もし書かれていれば、すでにティアを約束しています。残りの仕事は正しいものを選ぶだけです。

まだこれらの質問に答えられない場合は、クライアントをベースラインティアに入れ、前提を書き留めてください。それはセキュリティ監査ではなく、オンボーディングのたびに繰り返す正気度チェックです。

セキュリティ監査を毎回行わずにクライアントごとに決定するには?

小さな表を作成し、それにコミットしてください。40のセルを持つマトリックスは必要ありません。4つのティアで、エージェンシーが見るほぼすべてのクライアントをカバーできます。

クライアントの位置実際に何がそれらを分けているかいつ使用するか
ティア1: 共有アプリ/コンテナアプリケーションロジックのみ内部ユーティリティ、低リスクデータ、全員が明示的に1つのログインシステムにいるプロジェクト
ティア2: 同じホスト、別々のコンテナ名前空間とcgroupほとんどのマーケティングサイト、お問い合わせフォーム、機密データなし
ティア3: ロックダウンされたコンテナティア2 + 非root、機能の削除、seccomp、読み取り専用ルート、ネットワーク分離Eコマース、PII、完全には信頼していないカスタムコード
ティア4: テナントごとのVMハイパーバイザーと別個のカーネルヘルスケア、金融、コンプライアンス文書、信頼できないコード、ノイジーネイバー

実際の運用ではこうなります。お問い合わせフォームとInstagramリンクを持つパン屋のクライアントはティア2に入ります。共有ホスト上の1つのコンテナ、デフォルトのDockerネットワーキング、リソース制限、完了です。顧客名、住所、支払いリダイレクトを保存するオンラインストアはティア3に入ります。同じ共有ホストですが、コンテナは非rootユーザーとして実行され、余分なカーネル機能はなく、seccompプロファイルを使用し、ポート443のみを公開します。保護された健康情報を保存する医療受付ポータルはティア4に入ります。テナントごとのVMです。侵害のコストは「後で掃除すればいい」ではなく「クライアントに真剣に取り組んでいることを示せない」からです。

秘訣は、クライアントごとにアーキテクチャを再考しないことです。すでに合意した表から行を選んでいるだけです。それが5人のエージェンシーが100のサイトを100の個別のセキュリティ強迫観念なしで運営できる方法です。それはまた、次のクライアントが、電話に出たチームメンバーによって答えが変わることはないことを意味します。これらの選択の背後にあるより深いアーキテクチャの議論については、マルチテナント分離レベルの設計に関するガイドがトレードオフをより詳細に説明しています。

ロックダウンされたコンテナは実際にはどのようなものですか?

「ロックダウン」と言うのをやめて具体的にしましょう。これが典型的なWordPressまたはPHPクライアントにとってのティア3の意味です。

まず、ユーザーを変更します。ほとんどの公式イメージはデフォルトでrootとして実行されます。Dockerfileで非rootユーザーを作成し、そのユーザーとしてアプリを実行します。これにより、コンテナの侵害がホストの侵害になる最も一般的な経路が即座に取り除かれます。次に、不要なケーパビリティを削除します。--cap-drop ALL で実行し、通常は NET_BIND_SERVICE だけを追加して、アプリがポート80でリッスンできるようにします。これだけでも、ほとんどの人が予想するよりも大きな変更です。第三に、--read-only でルートファイルシステムを読み取り専用にし、書き込み可能なディレクトリ(アップロード、データベースデータディレクトリ)をボリュームまたはtmpfsとしてマウントします。第四に、seccompプロファイルを適用し、ホストがサポートしている場合はAppArmorまたはSELinuxを適用します。最後に、コンテナを専用のDockerネットワークに配置し、実際に到達可能にする必要があるポートのみを公開します。

WordPressの例を見てみましょう。ベースイメージはおそらくrootとして実行されるので、useraddステップとUSERディレクティブを追加します。メモリ制限とCPU制限を設定してコンテナを実行し、プラグイントラフィックのバーストが隣人に影響を与えないようにします。/var/www/html/wp-content/uploads を書き込み可能なボリュームとしてマウントします。--read-only を設定します。--privileged フラグがどこにもないネットワークに接続します。結果として、以前は「WordPressサイト」だったものが、「ほとんどの仮想プライベートサーバーよりもロックダウンされているWordPressサイト」になります。

そのすべてを手作りするのが不安定に感じる場合は、より簡単な中間道があります。Dockerの拡張コンテナ分離です。これはユーザー名前空間の分離とセキュアなコンテナランタイムを使用します。これは正当な近道ですが、非rootやケーパビリティの削除をスキップするための無料パスではありません。テナントは依然として賢明なイメージを必要とします。違いは、あなたが一夜にしてseccompの専門家になることなく、カーネルに面した攻撃面が小さくなることです。単一テナントの正確な手順が必要な場合は、ステップバイステップの分離強化ガイドがこのセクションをコピペコマンドに変換します。

いつレイヤリングをやめて、VMを渡すのですか?

ここが逆説的な部分です。より多くの分離は自動的により良いことではありません。VMはハードウェアレベルの分離、別個のカーネル、そしてゲストカーネルが落下した場合のはるかに小さな攻撃面を提供します。それはまさにヘルスケアや金融のクライアントが「分離されたい」と言うときに期待することです。しかし、すべてのVMはパッチ適用、バックアップ、コンピュートコストを追加し、フリートを最新に保つ作業を増やします。あるクライアントがかつてDockerに怖がったからといって、すべてのクライアントにVMを使うなら、実際のお金で安全シアターを買っていることになります。

VMが正しい答えであるのは、テナントごとのリスクがテナントごとのVMの運用コストよりも高い場合です。つまり、規制対象データ、書面によるコンプライアンス要件、信頼できないサードパーティコード、またはノイジーネイバーを除去する必要があるクライアントです。また、クライアントの契約が文字通り専用環境を約束している場合も正しい答えです。「コンテナ」は彼らが「専用」に署名するときに想像しているものではないからです。

しかし、VMは怠惰なコンテナを許しません。一般的な罠は、クライアントをVMに入れ、「VMが彼らを守っている」という理由で強化をスキップすることです。VMはホストをテナントから保護しますが、テナントを自身の悪いイメージから保護するわけではありません。そのVM内でも、非root、ケーパビリティの削除、seccompが必要です。ハイブリッドアプローチ、つまりVM内のコンテナは、しばしばスイートスポットです。VMはコンプライアンスの会話のための境界を提供し、コンテナは既に知っているデプロイメントワークフローを提供します。その議論のより長いバージョンは、すべてのテナントに独自のVMを用意すべきか?にありますが、短い答えは、VMは恐怖のためではなく、契約のためのものであるということです。

これをすべてのクライアントで再現可能にするには?

ティアシステムを記憶ではなくテンプレートにすることで再現可能にします。Composeファイルのディレクトリを1ティアごとに用意します:tier2-baselinetier3-lockedtier4-vm-hybrid。新しいクライアントが現れたら、テンプレートをコピーし、環境変数を変更します。新しいインフラを1行も書く前に、分離の形状はすでにわかっています。

次に、決定を書き留めます。400ページのセキュリティレポートではなく、クライアントのリポジトリに短い段落を書きます:どのデータを保存するか、どのティアにいるか、なぜか、そして何が彼らを1つ上のティアに移動させるか。その段落は100のファイアウォールルールよりも価値があります。なぜなら、それは次の監査人や次の心配しているクライアントに見せられるものだからです。また、最初のセールスコールが薄れた後、なぜパン屋がティア2で、Eコマースストアがティア3なのかを覚えている必要もなくなります。

退屈なチェックを自動化します。CIにすべてのクライアントイメージをスキャンさせ、ルートとして実行される場合、すべてのケーパビリティを持つ場合、またはティアが許可する以外のポートを公開しようとする場合にビルドを失敗させます。そのどれもエキゾチックではありません。善意の開発者によってテンプレートが偶然壊されないようにするだけです。周囲のホスティングワークフローを構築しているなら、本番対応のDockerホスティング戦略がコンテナ定義後の部分をカバーしています。

これのどれも魅力的ではありません。ブログ投稿が「テナント分離」をグリーンフィールドアーキテクチャ図のようにエキサイティングに聞かせることはありません。しかし、これが「私たちはどれだけ分離されていますか?」に指を交差させて「完全に」と答えるエージェンシーと、ティア、設定、理由を示すことができるエージェンシーの違いです。コンテナは魔法の壁ではありません。VMは魔法の弾丸ではありません。ティアシステムは、書き留めて再利用する決定にすぎません。そしてエージェンシーにとって、再現可能であることがすべてです。

Sources (5)