【実務・中級編】 Kubernetes API Serverのアクセス制限と認証・認可 – 暗号理論・認証基盤 & エンドポイントセキュリティ防御ガイド

Kubernetesの心臓部を守れ:API Serverを「公開」するなという警鐘

現場でインシデント対応をしていると、笑えない現実に直面することがある。「KubernetesのAPI Serverがインターネットに全開放されていた」というケースだ。これは、家の玄関の鍵を開けたまま、リビングに金庫を置いて放置しているようなものだ。

今日は、Kubernetesのコントロールプレーンをどう鉄壁にするか、その「現場の勘所」を共有する。教科書的な設定だけでは、百戦錬磨の攻撃者は防げない。

1. なぜAPI Serverが狙われるのか?(攻撃者の視点)

攻撃者が最初に狙うのは、kube-apiserverの公開ポート(通常は6443)だ。ここさえ突破すれば、クラスター内の全リソースを操作し、コンテナを乗っ取り、そこを足掛かりにクラウドのIAM権限を奪取できる。

彼らが使う手法は単純だ。

  • 匿名認証の悪用: 設定ミスで system:anonymous がクラスタ管理者権限を持っている場合、認証なしで kubectl が叩けてしまう。
  • RBACの不備: 「とりあえず cluster-admin を付与しておく」という怠惰な権限管理が、特権昇格の踏み台になる。
  • トークンの漏洩: CI/CDパイプラインのログや、誤ってコミットされた kubeconfig から静的トークンを盗み出す。

2. 防御の要:ネットワーク層での封鎖

まず大前提として、kube-apiserverをインターネットに公開してはならない。

クラウド環境(AWS/GCP/Azure)での鉄則

必ず「プライベートエンドポイント」を使用すること。パブリックIPを付与せず、VPN(OpenVPN, WireGuard)や、AWSなら AWS Systems Manager Session Manager を経由した踏み台サーバーからのみアクセスできるようにする。

Nginxでのアクセス制限(WAF/リバースプロキシを挟む場合)

もし何らかの事情でAPIサーバーの前にプロキシを置くなら、ngx_http_auth_request_module を使い、認証を通ったクライアントのみを通す構成にせよ。

# Nginxの設定例:API Serverへのアクセス制御
location /api/ {
    # 特定のIP範囲のみ許可(ただしIP制限は偽装可能なので過信しない)
    allow 10.0.0.0/24;
    deny all;

    # 証明書ベースの相互認証(mTLS)を強制する
    ssl_verify_client on;
    ssl_client_certificate /etc/nginx/certs/ca.crt;
    
    proxy_pass https://kubernetes-internal-ip:6443;
}

3. RBACの「最小権限」を徹底する(IAMとの連携)

Kubernetesの認証において、RSAやECDSAを用いた公開鍵暗号は「証明書の正当性」を保証するために使われる。しかし、認証(Who are you?)が通っても、認可(What can you do?)が甘ければ意味がない。

悪い例:開発者に cluster-admin を渡す

これをやると、開発者が誤ってクラスター全体を削除したり、機密情報にアクセスしたりするリスクがある。

良い例:Namespace単位の制限

特定のNamespace(例:web-app-production)のみ操作可能な Role と RoleBinding を作成する。

# RoleBindingの定義(特定のユーザーに権限を付与)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-read-only-binding
  namespace: web-app-production
subjects:
- kind: User
  name: "engineer@company.com" # OIDC等と連携したユーザーID
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader # 読み取り専用の権限
  apiGroup: rbac.authorization.k8s.io

4. プログラムからのAPI利用:サービスアカウントのセキュアな運用

アプリケーションからAPIを叩く際、ServiceAccount のトークンをコードに埋め込むのは最悪のプラクティスだ。必ず「OIDC連携」を使うこと。

以下は、PythonでKubernetesクライアントを使う際のセキュアな実装パターンだ。

from kubernetes import client, config

def get_k8s_client():
    # 実行環境がPod内の場合、自動的にServiceAccountトークンが読み込まれる
    # ローカル開発時は kubeconfig をロードするが、本番では環境変数で制御する
    try:
        config.load_incluster_config() 
    except config.ConfigException:
        config.load_kube_config()

    # 最小権限で実行される ServiceAccount に紐付いたクライアントのみを利用する
    v1 = client.CoreV1Api()
    return v1

# 安全にPod一覧を取得する例
def list_pods():
    api = get_k8s_client()
    pods = api.list_namespaced_pod(namespace="web-app-production")
    for pod in pods.items:
        print(f"Found pod: {pod.metadata.name}")

結論:セキュリティは「設定」ではなく「哲学」

Kubernetesのセキュリティは、一度設定して終わりではない。

  • mTLSによる暗号化: 通信経路は必ずTLSで保護し、証明書は短命に保つ。
  • ログの監査: audit-log を有効にし、誰がいつ何をしたかを必ず外部ストレージに転送する。
  • 防御的姿勢: 「API Serverは常に攻撃されている」という前提で、異常なAPIコールを検知するアラートを仕込むこと。

君たちが書くコードの一行、設定するYAMLの一つが、会社のインフラを守る砦になる。面倒な作業こそ、自動化し、堅牢に積み上げていこう。それが、プロのエンジニアの流儀だ。

コメント

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