【テクニカル・上級編】 コンテナランタイムのセキュリティ設定(runc/crun) – インフラ・ネットワーク & クラウドセキュリティ防御ガイド

コンテナの皮を剥ぐ:CVE-2019-5736から学ぶランタイム・ハーデニングの深淵

多くのエンジニアにとって、コンテナは「魔法の箱」だ。docker runやkubectl applyを叩けばアプリケーションが孤立して動く。しかし、セキュリティの深淵を覗く者にとって、コンテナは単なる「名前空間(Namespaces)とコントロールグループ(cgroups)という境界線上の砂上の楼閣」に過ぎない。

今日語るのは、CVE-2019-5736のような「コンテナ脱出(Container Breakout)」の核心と、それを封じ込めるためのランタイムの要塞化についてだ。教科書的な「アップデートせよ」という勧告で終わらせるつもりはない。なぜその脆弱性が起きるのか、そのメモリレイヤの挙動に踏み込む。

1. 脆弱性の本質:ホストを汚染する「ファイル記述子」の罠

CVE-2019-5736の根本原因は、runcがコンテナ内で実行されるプロセスのプロセスID(PID)にアクセスする際、ホスト側の/proc/self/exeを介してバイナリを読み書きできてしまう点にあった。

攻撃者は、コンテナ内で実行されるバイナリをホスト側のruncバイナリへのシンボリックリンクに書き換えることで、ホストのroot権限を奪取する。これは単なるバグではない。Linuxカーネルのprocfsと、コンテナランタイムが「ホストの実行環境を借りている」という設計上の宿命が生んだ悲劇だ。

この攻撃を防ぐには、単なるパッチ適用だけでは不十分だ。ランタイムレベルで「ホストとの共有」を物理的に断つ必要がある。

2. ランタイムの要塞化:gVisorとKata Containersの選択

runcは、あくまでホストのカーネルを共有する「軽量なプロセス隔離」だ。セキュリティのパラダイムを一段引き上げるなら、gVisorやKata Containersへの移行を検討すべきだ。

  • gVisor (Sentry): アプリケーションとホストカーネルの間に、Goで記述された「カーネル・エミュレータ」を挟む。システムコールをインターセプトし、ホストへ渡す前にフィルタリングする。
  • Kata Containers: 軽量VM(MicroVM)をコンテナの単位で起動する。ハードウェアレベルの分離(VT-x)が、攻撃者にとっての最大の壁となる。

もし、依然としてruncを使い続ける必要があるならば、少なくとも以下のseccompプロファイルでシステムコールを厳格に制限すべきだ。

{
  // デフォルトの拒否設定(ホワイトリスト方式)
  "defaultAction": "SCMP_ACT_ERRNO",
  "syscalls": [
    {
      "names": ["read", "write", "exit", "futex"], // 最小限必要なコールのみ許可
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}

3. 書き込み禁止とマウントの最適化

コンテナランタイムの攻撃対象領域(アタックサーフェス)を最小化する最も泥臭く、かつ効果的な手法は、ルートファイルシステムを読み取り専用(ReadOnly)にすることだ。

Kubernetesでこれを実現するには、Podのセキュリティコンテキストを以下のように設定する。これは、攻撃者が悪意のあるバイナリをランタイムディレクトリに配置することを物理的に防ぐための防壁となる。

securityContext:
  readOnlyRootFilesystem: true
  allowPrivilegeEscalation: false
  runAsNonRoot: true
  capabilities:
    drop:
      - ALL # すべての特権を剥奪し、必要なものだけを付与する

4. 生成AI時代のガードレイルとランタイム監査

最近は、LLM(大規模言語モデル)を内包したコンテナが増えている。ここで注意すべきは、プロンプトインジェクションがコンテナ内の環境変数や、マウントされたサービスアカウントトークンを外部へ持ち出すリスクだ。

ランタイムのログを収集するだけでは足りない。eBPFを用いたリアルタイムの監視が必須だ。Tetragonなどのツールを導入し、execveやopenatといったシステムコールをカーネル空間でフックし、不審なプロセス実行を検知した瞬間に当該コンテナをKillする自動応答アーキテクチャを構築せよ。

最後に:セキュリティは「設定」ではなく「疑心」である

最高峰のセキュリティアーキテクトに求められるのは、ベンダーのリリースノートを鵜呑みにすることではない。「このランタイムの設定は、カーネルのどのメモリ領域を保護しているのか?」「このプロトコルのパケット構造は、中間者攻撃に対してどのように防御されているか?」という問いを持ち続けることだ。

コンテナは便利な道具だが、それは「信頼できないコードを隔離する箱」であるべきだ。箱自体が穴だらけでは意味がない。常にカーネルの挙動を意識し、境界線を厳格に引き直すこと。それが、我々エンジニアが守るべき「防衛ライン」の本質である。

次回の考察では、耐量子暗号(PQC)を見据えたコンテナ通信のTLS 1.3実装と、その鍵交換におけるサイドチャネル攻撃対策について掘り下げる予定だ。セキュリティに終わりはない。準備を怠るな。

コメント

タイトルとURLをコピーしました