【入門編】 コンテナ隔離のためのネットワークポリシーと名前空間の分離 – インシデントレスポンス & フォレンジック(DFIR)防御ガイド

みなさん、こんにちは!日々進化するサイバー攻撃の裏側で、システムの安全を守るために奮闘しているSOC(Security Operations Center)アナリストの筆者です。

最近は「コンテナ」や「Kubernetes(クバネティス)」を使ってシステムを開発することが当たり前になってきましたよね。開発スピードが上がってとても便利な反面、セキュリティ担当としては「もし、このコンテナの1つが泥棒(ハッカー)に乗っ取られたらどうしよう…」と、いつもハラハラしながら監視をしています。

実は、コンテナの世界はデフォルト(初期設定)のままだと、「鍵のかかっていないシェアハウス」のような状態なのです。どこか1つの部屋(コンテナ)に泥棒が入ると、廊下を伝って他の全員の部屋に簡単に侵入できてしまいます。

そこで今回は、新人のIT担当者の方や、セキュリティを学び始めたばかりの開発者のみなさんに向けて、万が一コンテナが乗っ取られたときに「泥棒をその部屋に閉じ込め(隔離)、警察(フォレンジック調査官)が現場検証できるように証拠を保全する」ための具体的なテクニックを、身の回りの防犯に例えながら一歩ずつ優しく解説していきます!

—

1. 泥棒の動きを知る:なぜ「隔離」が必要なのか?

まずは、攻撃者がコンテナに侵入したときに何を企んでいるのか、そのメカニズムを泥棒に例えて見てみましょう。

コンテナ環境における攻撃のステップは、一般的に以下のような流れで進みます。

[インターネット]
       │ (泥棒が侵入!)
       ▼
 ┌───────────┐
 │ WEBコンテナ │  <─── ここが最初に乗っ取られる!
 └─────┬─────┘
       │ (他の部屋を物色:ラテラルムーブメント)
       ├──────────────────────┐
       ▼                      ▼
 ┌───────────┐          ┌───────────┐
 │ DBコンテナ  │          │ 管理コンテナ│
 │ (顧客データ) │          │ (システム)  │
 └───────────┘          └───────────┘

1. 足がかりの作成(侵入):
脆弱性(防犯の隙間)を突いて、一般公開されているWEBコンテナなどに侵入します。
2. 周囲の探索(スキャン):
侵入したコンテナから、同じネットワーク内にある他のコンテナ(データベースなど)がないか偵察します。
3. 横展開(ラテラルムーブメント):
防御が薄い内部のコンテナへ次々に侵入を広げ、最終的に大切な個人情報や機密データを盗み出します。

もし、あなたが「WEBコンテナが何者かにハッキングされた!」と気づいたら、どうしますか?
焦って「すぐにこのコンテナを消去(デリート)して、新しく作り直そう!」と思ってしまうかもしれません。

しかし、セキュリティの現場ではこれはNGアクションになります。
なぜなら、コンテナを消してしまうと、泥棒が残した足跡(ログやメモリ上の証拠、犯行ツール)がすべて綺麗さっぱり消え去ってしまうからです。これでは、どこから侵入されたのか、何を盗まれたのかが永久に分からなくなってしまいます。

そこで必要になるのが、「コンテナを生かしたまま、ネットワークの通信だけを完全に遮断して閉じ込める(隔離)」という高度な防犯テクニックなのです。

—

2. 対策その1:防犯シャッターで閉じ込める「NetworkPolicy」

コンテナを隔離するための最初の強力な武器が、NetworkPolicy(ネットワークポリシー)です。

これは、アパートの部屋の前に「自動で閉まる頑丈な防火シャッター」を設置するようなものです。通常時はみんなが自由に行き来できるように開けておきますが、非常事態が発生した瞬間にシャッターをガシャーン!と閉めて、その部屋からの出入りを一切禁止します。

Kubernetesでは、このシャッターの役割をYAML(ヤムル)という設定ファイルで定義します。

実践:コンテナを完全隔離する「隔離専用ポリシー」

以下は、異常が検知された特定のコンテナ(ここでは app: compromised-pod というラベルがついたPod)のすべての通信(入る波も、出る波も)をシャッターのように完全に遮断する設定例です。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: isolate-compromised-pod
  namespace: default # 対象のコンテナがあるネットワークの区画を指定します
spec:
  # 「app: compromised-pod」というラベルが貼られたコンテナをターゲットにします
  podSelector:
    matchLabels:
      app: compromised-pod
  # 適用するルールの種類(Ingress=入る通信、Egress=出る通信)を指定します
  policyTypes:
  - Ingress
  - Egress
  # ingress: と egress: の中身を「空っぽ」にすることで、
  # 「いかなる通信も一切許可しない(=完全な通信遮断)」という意味になります。
  ingress: []
  egress: []

この設定のポイント

通常、Kubernetesは「設定がないものはすべて許可」という太っ腹なルール(デフォルトオープン)で動いています。しかし、この NetworkPolicy を適用すると、「ここに書かれたルール以外の通信はすべて拒否する」という厳しいルール(デフォルトデニアル)に切り替わります。

上記のコードでは、許可するルールを [](空っぽ)にしているため、「すべての通信を拒否する=完全な隔離」が実現するわけですね。これで、泥棒は外の指示役(C2サーバー)と連絡を取ることも、隣のデータベースを覗き見することもできなくなりました!

—

3. 対策その2:現場検証のための「ネットワーク名前空間」の分離

さて、通信を遮断して泥棒を部屋に閉じ込めることには成功しました。次に行うのは「現場検証(フォレンジック調査)」です。

しかし、ここで一つ問題があります。
「泥棒がどのIPアドレスと通信しようとしていたのか」「どんな怪しいデータを送ろうとしていたのか」を調べるために、コンテナの中でパケットキャプチャ(通信の記録)を行いたいのですが、乗っ取られたコンテナの内部はすでにウイルスや改ざんツールで汚染されている可能性があります。

汚染されたコンテナの中で直接調査コマンドを実行するのは、「犯人がまだ潜んでいるかもしれない暗闇の部屋に、素手で入っていく」ようなもので、非常に危険ですし、証拠を書き換えられてしまうリスクもあります。

そこで、Linuxの「ネットワーク名前空間(Network Namespace)」という仕組みを使います。

ネットワーク名前空間とは?

コンテナ技術の実態は、1つの大きなOS(ホスト)の中に、仕切りを作って「あたかも独立したパソコンが動いているように見せる」技術です。この「ネットワーク部分の仕切り」のことを「ネットワーク名前空間」と呼びます。

イメージとしては、ホストOSという「大きなマンション」の中に、それぞれのコンテナ専用の「専用郵便ポストや電話回線(名前空間)」が割り当てられている状態です。

[ホストOS (マンション全体)]
 │
 ├─ [コンテナAの部屋] ─── (独自のネットワーク名前空間 A)
 │                                │
 └─ [コンテナBの部屋] ─── (独自のネットワーク名前空間 B)
                                  │
      ★ 調査官はホスト側から、コンテナBの「名前空間」だけに
         虫眼鏡(調査ツール)を差し込んで、安全に通信を覗き見することができます!

私たちは、乗っ取られたコンテナの中に入る必要はありません。安全な「ホストOS(マンションの管理人室)」から、ターゲットのコンテナの「ネットワーク名前空間」にだけアクセスし、外側から安全に虫眼鏡で観察すれば良いのです。

—

4. SOCアナリスト直伝!現場での「泥臭い」フォレンジック手順

ここからは、実際にインシデントが発生したと仮定して、SOCアナリストが現場で行っている具体的なコマンド操作を追体験してみましょう。一歩ずつ進めていきますので、怖がらなくて大丈夫ですよ!

ステップ1:乗っ取られたコンテナの「プロセスID(PID)」を特定する

まずは、ホストOS側から、ターゲットのコンテナが「OS上のどのプロセスで動いているか」を特定します。

# 1. 隔離したいPodが動いているノード(サーバー)にログインします。
# 2. 以下のコマンドで、対象コンテナのコンテナIDを調べます。
kubectl get pod compromised-pod -o jsonpath='{.status.containerStatuses[0].containerID}'

# 例として、コンテナIDが「docker://abcdef123456...」だと分かりました。
# 3. ノード上で、そのコンテナのプロセスID(PID)を特定します。
docker inspect --format '{{.State.Pid}}' abcdef123456

*※ここではDockerの例ですが、containerdを使用している場合は crictl inspect などを使用します。*

仮に、ここでプロセスIDが 12345 だと判明したとします。

ステップ2:nsenter コマンドで安全にネットワーク空間に潜入する

ここで、魔法のコマンド nsenter(エヌエス・エンター)を使います。このコマンドは、指定したプロセスの「仕切られた空間(名前空間)」に、外側から入り込むことができるツールです。

# プロセスID「12345」のネットワーク(-n)名前空間に入り込んで、
# その中で「ip addr」コマンドを実行し、ネットワークカードの状態を確認します。
sudo nsenter -t 12345 -n ip addr

このコマンドを実行すると、乗っ取られたコンテナのシステムを一切汚染することなく、そのコンテナが見ているネットワーク機器の一覧を安全に取得することができます。

ステップ3:証拠の保全!パケットキャプチャを開始する

泥棒がどのような悪事を働こうとしていたのか、通信の証拠(パケット)をファイルに保存しましょう。ホストOS側にインストールされている信頼できる tcpdump コマンドを使用します。

# ターゲットコンテナのネットワーク空間に入り、通信を監視してファイルに書き出します。
# -w オプションで、後から解析できるように「evidence.pcap」というファイルに保存します。
sudo nsenter -t 12345 -n tcpdump -i any -w /tmp/evidence.pcap

これで、隔離されたコンテナが「外に出ようとして、NetworkPolicyにブロックされている虚しい足掻き」や「内部で動いている不審なプログラムの通信」を、安全かつ確実に記録することができます。

この保存された evidence.pcap ファイルを、後から「Wireshark(ワイヤーシャーク)」などの解析ソフトで読み込めば、「あ、この泥棒は外部の怪しいサーバーから追加のウイルスをダウンロードしようとしていたんだな」といった事実が丸裸になります!

—

5. まとめ:一歩ずつ対策を学んでいきましょう!

今回の内容を簡単におさらいしてみましょう。

  • 焦ってPodを消さない: 犯行の証拠(ログやメモリ)が消えてしまうため、まずは「生かしたまま隔離」が鉄則です。
  • NetworkPolicyで閉じ込める: 許可ルールを空っぽにしたポリシーを適用し、通信の防犯シャッターを下ろします。
  • 名前空間(Namespace)の分離を利用する: ホスト側から nsenter コマンドなどを使って、安全な場所からコンテナのネットワークを覗き見(フォレンジック)します。

コンテナやKubernetesのセキュリティと聞くと、最初は「なんだか難しそう…」と身構えてしまうかもしれません。でも、こうして「アパートの防犯」や「現場検証のブルーシート」に例えて考えてみると、意外とシンプルな原則で動いていることが分かりますよね。

セキュリティ対策に「これで完璧!」という終わりはありません。しかし、こうして仕組みを一つずつ紐解き、理解を深めていくことが、システムを、そしてユーザーを守るための最も確実な第一歩になります。

これからも、安全で楽しい開発ライフを一緒に送っていきましょう。一歩ずつ、一緒に学んでいきましょうね!

コメント

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