Kubernetesクラスタは安定稼働していても本当に安全ですか?
Kubernetesクラスタを構築し、Podが順調に動き、Ingressがドメインに正しくルーティングされているのを確認すると、ひとまずホッとするエンジニアも多いのではないでしょうか。私も以前はそうでした。しかし、あるテストサーバーが無警戒に開放されたポートを経由して深夜2時にSSHブルートフォース攻撃を受けたとき、「動いていること」と「安全であること」は決して同義ではないと痛感しました。
Kubernetesはデフォルトでセットアップの容易さを優先する傾向があります。そのため、kube-apiserver、kubelet、etcdなどの設定ファイルの権限が緩く設定されている(644や777など)ことがよくあります。仮にWeb PodにRCE(リモートコード実行)の脆弱性があった場合、攻撃者にServiceAccountのトークンを読み取られ、不十分なAPIポート設定を突かれてクラスタ全体の制御権を奪われる危険性があります。こうした設定ミスを解消するには、信頼性の高い自動監査ツールが必要です。
CIS Kubernetes BenchmarkとKube-benchとは?
効果的な監査を行うために、まずは以下の2つの基本ツール・指標を理解しておきましょう。
- CIS Kubernetes Benchmark: Center for Internet Securityが発行する200ページ超のドキュメント。Control Plane、etcd、Worker Node、認証メカニズムなどの安全な構成標準を幅広く定義しています。
- Kube-bench: Aqua Security社が開発したGo言語製のオープンソースツール。ノード構成、ファイルパーミッション、プロセスパラメータなどをCIS標準と照合し、わずか10〜15秒で詳細なレポートを出力します。
Kube-benchによるK8sセキュリティ監査の実践
クラスタの構成形態(kubeadmによるセルフホストか、EKSやGKEなどのマネージドサービスか)に応じて、以下のいずれかの方法を選択できます。
方法1:Kubernetes JobとしてKube-benchを実行する(推奨)
この方法を使えば、各ノードに個別にSSH接続することなく、kubectl経由でクラスタ全体を迅速にスキャンできます。
マニフェストファイル job-kube-bench.yaml を作成します:
cat <<EOF > job-kube-bench.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: kube-bench
spec:
template:
spec:
hostPID: true
nodeSelector:
node-role.kubernetes.io/control-plane: ""
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
containers:
- name: kube-bench
image: aquasec/kube-bench:latest
command: ["kube-bench"]
volumeMounts:
- name: var-lib-etcd
mountPath: /var/lib/etcd
readOnly: true
- name: var-lib-kubelet
mountPath: /var/lib/kubelet
readOnly: true
- name: etc-systemd
mountPath: /etc/systemd
readOnly: true
- name: etc-kubernetes
mountPath: /etc/kubernetes
readOnly: true
- name: usr-bin
mountPath: /usr/local/mount-from-host/bin
readOnly: true
restartPolicy: Never
volumes:
- name: var-lib-etcd
hostPath:
path: /var/lib/etcd
- name: var-lib-kubelet
hostPath:
path: /var/lib/kubelet
- name: etc-systemd
hostPath:
path: /etc/systemd
- name: etc-kubernetes
hostPath:
path: /etc/kubernetes
- name: usr-bin
hostPath:
path: /usr/bin
EOF
Jobをデプロイしてログ結果を取得します:
# スキャンJobの作成
kubectl apply -f job-kube-bench.yaml
# Podの実行完了を待機
kubectl wait --for=condition=complete job/kube-bench --timeout=60s
# レポートの出力
kubectl logs job/kube-bench
方法2:Master / Worker Node上でバイナリを直接実行する
ベアメタルサーバーや自己管理型のVM環境では、スタンドアロンバイナリを実行するのが各ノードを監査する最も直感的な方法です。
# 最新リリースのダウンロード
curl -L https://github.com/aquasecurity/kube-bench/releases/download/v0.8.0/kube-bench_0.8.0_linux_amd64.tar.gz -o kube-bench.tar.gz
tar -xvf kube-bench.tar.gz
# Control Planeノードの監査
sudo ./kube-bench run --targets master
# Workerノードの監査
sudo ./kube-bench run --targets node
結果の確認とFAIL警告への対処
Kube-benchは結果を次の4つのステータスに分類します:
[PASS]: CIS標準に準拠した設定。[FAIL]: 重大なセキュリティ問題。早急な対応が必要。[WARN]: 実際の要件に応じた再評価が必要な警告。[INFO]: 参考情報。
FAIL項目の下には、具体的な修正手順を示す == Remediation == ブロックが必ず記載されます。以下は、構築直後のK8sクラスタで特によく見られる代表的な2つのエラーです:
1. API Server設定ファイルの不適切なパーミッション(項目 1.1.1)
デフォルトでは、初期シークレットやトークンを含むマニフェストファイルがOS上の一般ユーザーから読み取れる状態になっている場合があります。パーミッションを 600 に絞り込んで制限します:
sudo chown root:root /etc/kubernetes/manifests/kube-apiserver.yaml
sudo chmod 600 /etc/kubernetes/manifests/kube-apiserver.yaml
2. Kubeletの匿名認証の有効化(項目 4.2.1)
anonymous-auth が有効になっていると、ノードの内部ネットワークに侵入した攻撃者がKubeletのポート10250へ直接リクエストを送信できるようになります。/var/lib/kubelet/config.yaml を修正します:
authentication:
anonymous:
enabled: false
webhook:
enabled: true
変更を反映するためにプロセスを再起動します:
sudo systemctl restart kubelet
K8sクラスタ監査の実践ノウハウ
ステージング環境や本番環境で長期にわたりKube-benchを運用してきた経験から、押さえておくべき重要なポイントをまとめました:
- 盲目的に100% PASSを目指さないこと: 匿名リクエストの無効化やhostPathの制限を推奨するルールの中には、CNI(CalicoやCiliumなど)やストレージCSIの動作に影響を与えるものがあります。本番環境に適用する前に、必ずステージング環境で十分に検証してください。
- CronJobによる定期スキャンと通知の統合: 毎週日曜日の深夜3時に実行されるCronJobを設定します。誰かが誤ってファイル権限を変更した際にも即座に検知できるよう、エラーログをDevOpsチームのSlackやTelegramチャンネルに直接通知しましょう。
- 適切なベンチマークバージョンの選択: 実行中のK8sバージョンを確認し、適切なフラグ(例:
--benchmark cis-1.8)を指定してください。バージョンが一致していないと、正確な監査結果が得られません。
インフラのセキュリティ対策は継続的なプロセスです。定期的な監査パイプラインにKube-benchを組み込むことで、思わぬセキュリティホールに怯えることなく安心して運用できるようになります。

