こんにちは!インフラやセキュリティの勉強を始めたばかりの皆さん、日々の開発や運用お疲れ様です。
「コンテナ技術」や「Kubernetes(K8s)」って、なんだか名前からして難しそうですよね。「Dockerコンテナを使えばどこでも同じ環境が動く!」と聞いて便利に使っていたものの、ふと「セキュリティって本当に大丈夫なのかな?」と不安になることはありませんか?
今回は、Kubernetes環境で時々やってしまいがちな「うっかり設定ミス」をきっかけに、悪い奴ら(攻撃者)がどのようにシステムを乗っ取ってしまうのか、そしてそれをどうやって防げばいいのかを、身近な防犯の例えを交えながら優しく紐解いていきたいと思います。
一歩ずつ、一緒に学んでいきましょう!
—
1. 身近な防犯で考えてみよう!「Dockerソケット」の危険性
まずは、今回の主役である Dockerソケット (/var/run/docker.sock)というものについて、おうちの防犯に例えて考えてみましょう。
皆さんの家(=KubernetesのホストOS)には、頑丈な玄関の鍵がついていますよね。そして、家の中に「ペットロボット(=コンテナ)」を飼っているとします。
普通、このロボットは家の中を掃除したりお散歩したりするだけで、家の外の鍵を開けたり、別の家の秘密を覗き見たりすることはできません。
ところが、もし「家のマスターキー(すべての鍵を開けられるリモコン)」を、うっかりロボットの首から下げてしまったらどうなるでしょうか?
ロボットが悪意あるハッカーに乗っ取られた瞬間、そのリモコンを使って家中の鍵を開け、家全体を自由自在に操られてしまいますよね。
Kubernetesの世界における /var/run/docker.sock のマウントとは、まさにこの「マスターキーをロボットに持たせてしまう行為」そのものなのです。
—
2. 攻撃者はどうやって侵入し、特権昇格するのか?
では、具体的にどんな攻撃が行われるのか、そのメカニズムを覗いてみましょう。
開発の便利さや、コンテナの中から別のコンテナを管理したい(いわゆるDind: Docker-in-Dockerなど)という理由で、Pod(Kubernetesでコンテナを動かす単位)の設定ファイルに、ホストの docker.sock をマウントしてしまうことがあります。
攻撃者は、まず何らかの脆弱性(例えば、古いWebアプリケーションの脆弱性など)を突いて、そのPodの中に侵入します。ここまでは「おうちの玄関の窓ガラスが割られた状態」です。
しかし、ここからが本当の恐怖です。攻撃者がコンテナの内部でターミナルを開き、次のようなコマンドを実行したとします。
# コンテナの中から、ホスト側にあるDockerのエンジンに命令を送るテスト
docker ps
もし、このコマンドがエラーを出さずに動いてしまったら……? 攻撃者はガッツポーズをします。なぜなら、そのコンテナは「自分がいる小さな箱の外側(=ホストOS)」を完全に支配する権利を持っているからです。
攻撃者の次のステップ:新しい「超・特権コンテナ」の作成
攻撃者は、マウントされた docker.sock を経由して、ホスト上のDockerエンジンに直接こう命令します。
「ねえ、ホストのハードディスクのすべてを丸ごと読み書きできて、セキュリティ制限が一切ない、最強の特権コンテナを新しく作ってよ!」
YAMLファイル(Kubernetesの設定の元になる設計図のようなもの)で表現すると、以下のような危険すぎる設定のコンテナを、ホスト上で勝手に起動させてしまうのです。
apiVersion: v1
kind: Pod
metadata:
name: attacker-super-pod
spec:
# ホストのOS空間(プロセスやネットワーク)を完全に共有してしまう設定
hostNetwork: true
hostPid: true
hostIPC: true
containers:
- name: evil-container
image: ubuntu:latest
securityContext:
privileged: true # すべてのセキュリティ保護を無効化する「特権モード」
volumeMounts:
- mountPath: /host
name: host-root-volume
volumes:
- name: host-root-volume
hostPath:
path: / # ホストのルートディレクトリ(まるごと全部)をマウント
このコンテナが起動した瞬間、攻撃者はKubernetesクラスター全体の管理者、あるいはホストマシンの「root(最高権限者)」になってしまいます。これが、マウント攻撃による特権昇格の恐ろしい手口です。
—
3. どうやって防ぐ?防御の仕組みを学ぼう
「うわぁ、恐ろしい話だな……。じゃあ、どうやって防げばいいの?」と不安になりますよね。安心してください。現代のKubernetesには、こうした「うっかりミス」をガッチリ防ぐ仕組みがちゃんと用意されています。
防犯に例えるなら、「ロボットが勝手にマスターキーを持ち出そうとしたら、センサーが感知して即座にブザーを鳴らし、ドアをロックする仕組み」です。
対策①:Pod Security Standards(PSS)による制限
Kubernetesには、Podがどれくらい安全な設定で作られているかをチェックする「Pod Security Standards」という基準があります。
これには3つのレベルがあります。
1. Privileged(特権): すべての制限を解除(危険!)
2. Baseline(基準): 一般的なコンテナの安全性を保つ(推奨)
3. Restricted(制限): 最も安全で、コンテナがやりたい放題するのを厳しく防ぐ
これらをネームスペース(Kubernetes内の部屋のようなもの)ごとに適用することで、危険な設定(privileged: true や hostPath のマウントなど)が含まれているPodは、作成する段階でエラーになり、デプロイすらできないように拒否することができます。
ネームスペースに制限をかける設定例
例えば、特定のネームスペースで「Baseline」レベル以上の安全性を強制したい場合は、以下のようなラベルをネームスペースに付与します。
apiVersion: v1
kind: Namespace
metadata:
name: secure-development-ns
labels:
# Baselineレベルのセキュリティを強制する
pod-security.kubernetes.io/enforce: baseline
# 違反したときに警告(Warning)を出す設定
pod-security.kubernetes.io/warn: baseline
# 違反したときに監査ログ(Audit)を残す設定
pod-security.kubernetes.io/audit: baseline
このように設定しておけば、万が一開発者が間違えて危険なマウント設定を書いたPodを作ろうとしても、Kubernetesが「おいおい、その設定はルール違反だよ!」と自動で弾いてくれるようになります。
—
4. まとめ:今日からできる一歩
今回は、Kubernetesにおける docker.sock マウントを通じた特権昇格の仕組みと、その防御策について解説しました。
- 教訓: コンテナにホストの
docker.sockを渡すのは、家全体のマスターキーをロボットに渡すようなもの。原則として絶対に避けましょう! - 対策: Pod Security Standards(PSS)などを活用し、インフラの仕組みとして「危険な設定が入り込めないガード」を固めておきましょう。
セキュリティの対策と聞くと、「覚えることが多くて難しそう……」と感じてしまうかもしれませんが、一つひとつの仕組みは「なぜそれが必要なのか」という理由(リスク)を知ることで、ぐっと理解しやすくなります。
焦らず、一歩ずつ安全なインフラ作りを学んでいきましょうね。それでは、次回の記事もお楽しみに!
コメント