KubernetesのRBAC要塞化:その「とりあえず cluster-admin」が会社を滅ぼす理由
現場でコードを叩いていると、開発スピードを優先するあまり「とりあえず動くように」と、ServiceAccountに cluster-admin 権限を付与したくなる衝動に駆られることは誰にでもある。だが、断言しよう。その「とりあえず」が、君のクラスタを最も脆い標的に変える。
攻撃者は、アプリケーションの些細な脆弱性(例えば、最近流行った公開プロキシのSSRFや、依存パッケージのRCE)を足がかりにポッド内へ侵入し、そこからマウントされている ServiceAccount のトークンを盗む。もしそのトークンが広範な権限を持っていたら? 攻撃者はクラスタ全体のシークレットを抜き取り、全ノードを乗っ取り、バックドアを仕込むのに1分もかからない。
今日は、そんな悪夢を未然に防ぐための「実戦的なRBAC設計」について、泥臭い知見を共有する。
—
1. 攻撃者が狙う「盲点」:トークンの悪用
攻撃者の視点に立てば、Kubernetesクラスタ内部で最も美味しいターゲットは default 名前空間の default ServiceAccountが持っている権限、あるいは設定ミスで肥大化した権限だ。
もし、あるポッドに list や get 権限が許されている場合、攻撃者は kubectl get secrets を叩き、DBのパスワードや外部APIのトークンを平文で回収する。さらに create 権限があれば、特権コンテナを起動してホストOSのルート権限を奪取する。これが「権限昇格」の典型的なルートだ。
—
2. 最小権限の鉄則:RoleとRoleBindingの使い分け
ClusterRole を多用してはいけない。特に特定の名前空間で動くアプリには、必ず Role と RoleBinding を使え。
以下に、特定の名前空間内で「自分のポッドのステータスを確認するだけ」に絞った、セキュアな設計例を示す。
実装サンプル:必要最小限のRBAC定義
# 1. 権限(Role)を定義:必要な操作以外は一切拒否する
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production-app
name: pod-reader-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"] # 編集や削除権限は与えないのが鉄則
---
# 2. サービスアカウントの作成
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-runner-sa
namespace: production-app
---
# 3. 紐付け(RoleBinding):特定のSAだけに権限を付与
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods-binding
namespace: production-app
subjects:
- kind: ServiceAccount
name: app-runner-sa
namespace: production-app
roleRef:
kind: Role
name: pod-reader-role
apiGroup: rbac.authorization.k8s.io
この定義により、この ServiceAccount は他の名前空間には一切干渉できず、かつポッドの読み取り以外は何もできない。これが堅牢な設計の第一歩だ。
—
3. 定期監査の自動化:穴を見つける「眼」を持つ
設計は一度作れば終わりではない。運用中に「とりあえず」で権限が追加されるのがK8sの常だ。これを防ぐには、定期的なスキャンが不可欠だ。
現場でお勧めするのは kubectl-who-can や rbac-lookup といったツールをCI/CDパイプラインに組み込むことだ。
特に、以下のようなコマンドで「誰が secret を読み取れるのか」を定期的に洗い出す運用をチームに徹底させよう。
# 特定リソースに対する権限の洗い出し
kubectl rbac-lookup get secrets
もし、未知のサービスアカウントや、本来権限を持つべきではないユーザーが表示されたら、即座に修正の対象とする。セキュリティは「性善説」ではなく「常に疑うこと」から始まる。
—
4. 最後に:エンジニアとしての矜持
結局のところ、RBACの設定は面倒だ。開発者は機能実装に集中したいし、インフラ担当は障害対応で手一杯だろう。しかし、インシデントが発生した後の対応コストは、設計時の手間の1000倍に膨れ上がる。
automountServiceAccountToken: falseを活用せよ:権限が不要なポッドには、そもそもトークンをマウントさせないのが最強の防御だ。- 名前空間を分けろ:環境ごと、アプリごとに名前空間を隔離し、影響範囲を最小化する。
「動けばいい」という考え方は卒業しよう。君たちが書くそのYAML一行が、会社の資産を守る最後の砦になる。何か不明点があれば、またいつでも聞いてくれ。現場からは以上だ。
コメント