【テクニカル・上級編】 Kubernetes RBACの過剰権限設定とServiceAccountの悪用 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

Kubernetesの「神」を殺す:RBAC過剰権限の深淵と、その先にある監査のパラドックス

多くのKubernetesクラスタは、構築された瞬間に「終わっている」。

セキュリティアーキテクトとして数々の企業をアセスメントしてきたが、結局のところ、脆弱性の根本原因はCVEのゼロデイでもメモリリークでもなく、「人間が権限の粒度を理解していないこと」に尽きる。特にKubernetesにおける ServiceAccount の過剰権限設定は、攻撃者にとっての「ゴール」だ。

一度クラスタの内部に入り込み、特権を持った ServiceAccount のトークンを奪取すれば、そこはもう攻撃者の独壇場となる。今日は、Kubernetes RBACの脆弱性を悪用する攻撃のメカニズムと、それを防ぐための「泥臭い」監査ロジックについて掘り下げていこう。

—

1. 攻撃者が狙う「盲点」:ServiceAccountのトークンという名の鍵

Kubernetesの各Podには、デフォルトで /var/run/secrets/kubernetes.io/serviceaccount/token というJWTがマウントされる。これが攻撃者にとっての「マスターキー」だ。

多くの現場で目にするのが、デフォルトの default ServiceAccountに ClusterRoleBinding で cluster-admin 権限を付与してしまっているケースだ。あるいは、CI/CDパイプライン用のServiceAccountが、なぜかノードのシェル実行権限やシークレットの全読み取り権限を持っている。

攻撃のロジック:特権昇格の連鎖

攻撃者は、アプリケーションの脆弱性(例えば、SSRF や Remote Code Execution)を足掛かりにPod内部へ侵入する。その後、以下の手順でクラスタ全体を掌握する。

1. トークンの取得: cat /var/run/secrets/kubernetes.io/serviceaccount/token でJWTを窃取する。
2. 権限列挙: kubectl auth can-i --list で自分に何ができるかを確認する。
3. 特権の乱用: secrets のダンプ、pods/exec によるバックドアの設置、あるいは PersistentVolume を悪用したホストファイルシステムの破壊を行う。

—

2. 実践:RBACの「過剰権限」を特定するコード

「権限が強すぎる」という抽象的な警告は意味がない。以下のコード例のように、攻撃者が悪用可能な権限セットを Go クライアントを使って洗い出し、異常を検知するスクリプトをCI/CDのパイプラインや監視エージェントに組み込む必要がある。

// 危険な権限を持つServiceAccountを特定するための簡易監査ツール
package main

import (
    "context"
    "fmt"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
)

func main() {
    // インクラスタ設定を読み込み
    config, _ := rest.InClusterConfig()
    clientset, _ := kubernetes.NewForConfig(config)

    // 全てのClusterRoleBindingを走査
    crbs, _ := clientset.RbacV1().ClusterRoleBindings().List(context.TODO(), metav1.ListOptions{})
    for _, crb := range crbs.Items {
        // "cluster-admin" 権限を持つバインディングを特定
        if crb.RoleRef.Name == "cluster-admin" {
            for _, subject := range crb.Subjects {
                if subject.Kind == "ServiceAccount" {
                    // ここでアラートを発火させる、あるいは自動削除するロジックを実装
                    fmt.Printf("警告: 危険な権限設定を検知 -> SA: %s, Namespace: %s\n", subject.Name, subject.Namespace)
                }
            }
        }
    }
}

—

3. 監査ログを用いた異常検知:パケットの向こう側を見る

APIサーバーの監査ログ(Audit Log)は、攻撃の痕跡を追うための「ブラックボックス」だ。しかし、ログを垂れ流しているだけでは意味がない。攻撃者は kubectl を使わず、直接 apiserver のREST APIを叩いて隠密性を高める。

検知すべき異常行動のシグナル:

  • 非定常な get secrets: 特定のPodからシークレットへのアクセスが急増、または深夜帯に発生。
  • impersonate の利用: User や Groups を偽装して権限を奪う手法。これはログ上で必ず impersonatedUser フィールドに記録される。
  • exec コマンドの多用: 開発者が実行するはずのない kubectl exec が自動化されたAgent経由で実行されている。

これらのログを SIEM (Splunk, Datadog, ELK等) に流し込み、以下のロジックでフィルタリングを行うべきだ。

// 監査ログフィルタリング例(Impersonation検知)
{
  "query": "verb: (create) AND objectRef.resource: (pods/exec) AND user.username: (system:serviceaccount:*)",
  "comment": "ServiceAccountによるexecコマンド実行は、基本的に異常と見なす"
}

—

4. 防衛の最前線:ガードレイルの設計

最後に、アーキテクトとして提示したいのは「ゼロトラスト・アーキテクチャ」への移行だ。

1. Kyverno / OPA Gatekeeperの強制: Pod Security Admissionを実装し、特権コンテナの起動をポリシーレベルで拒否する。
2. Ephemeral Containersの活用: exec を許可せず、トラブルシューティングには一時的なコンテナを利用する運用への転換。
3. Workload Identityの活用: クラウドプロバイダー(AWS EKSのIAM Roles for Service Accounts等)と連携し、トークンの有効期限を極限まで短くする。

最後に

セキュリティは「静的な設定」ではない。攻撃者は常にAPIの仕様の隙間、RBACの複雑な継承関係、そして運用者の「めんどくさい」という感情を突いてくる。

君たちが守るべきは、単なる設定ファイルではない。クラスタという「仮想的な国家」のガバナンスそのものだ。今日紹介した監査手法を、単なるチェックリストに留めず、CI/CDのパイプラインに組み込み、開発者の自由を奪わずに「安全な道」を強制させるアーキテクチャを設計してほしい。

それが、現代のホワイトハッカーに求められる真のエンジニアリングだ。

コメント

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