【実務・中級編】 Kubernetes APIサーバーに対するDoS攻撃とリソース制限 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

Kubernetesの心臓を止めるな:APIサーバーへのDoS攻撃を防ぐための「防壁」構築術

現場でインシデント対応をしていると、意外なほど見落とされているのが「APIサーバーそのものへの攻撃」だ。多くのエンジニアはPod内のアプリケーションの脆弱性には神経を尖らせるが、そのオーケストレーターであるKubernetes(K8s)のAPIサーバーが、たった数行のコードで機能不全に陥るリスクを考慮できていない。

今日は、攻撃者の視点から「なぜK8sのAPIサーバーが狙われるのか」、そして「現場でどう防ぐべきか」という現実的な話をしよう。

—

なぜAPIサーバーは「狙い目」なのか?

K8sのAPIサーバーは、クラスター内のすべての通信のハブだ。kubectlの操作はもちろん、各コンポーネントのステータス更新もここを通る。もし、このAPIサーバーに無制限のリクエストを叩き込んだらどうなるか?

攻撃者は、認証情報(ServiceAccountトークン)を奪取した後に、単なるリソースの浪費ではなく、「APIサーバーへの負荷集中によるクラスターの自滅」を狙う。これを食らうと、オートスケーリングが機能せず、ノードの追加もできず、最終的にはクラスター全体がコマンドを受け付けない「操縦不能な巨艦」と化す。

攻撃のPoC(概念実証)の裏側

極めて単純なPythonスクリプトでも、適切に保護されていないクラスターなら悲鳴を上げる。

import requests
import threading

# 奪取したServiceAccountトークン
TOKEN = "your-service-account-token"
API_SERVER = "https://<api-server-ip>:6443"

def send_request():
    headers = {"Authorization": f"Bearer {TOKEN}"}
    # クラスター内のすべてのPod情報を連続で取得し続ける
    while True:
        try:
            requests.get(f"{API_SERVER}/api/v1/pods", headers=headers, verify=False)
        except:
            pass

# スレッドを大量に生成して負荷をかける
for _ in range(50):
    threading.Thread(target=send_request).start()

このスクリプトがやっていることは単純だが、これが何百ものPodから同時に実行されたらどうなるか。APIサーバーのCPUとメモリは枯渇し、制御プレーンはダウンする。これが、我々が「APIレート制限」を叫ぶ理由だ。

—

実践的防衛策:ResourceQuotaとLimitRangeの鉄則

「APIサーバーに過度な負荷をかけさせない」ための第一歩は、各Namespaceにリソースの境界線を引くことだ。これを設定していないクラスターは、例えるなら「鍵のかかっていない金庫」だ。

1. ResourceQuotaで「総量」を制限する

Namespaceごとのリソース消費量に上限を設ける。これにより、特定のNamespaceが暴走しても、クラスター全体を道連れにするのを防げる。

# resource-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: limit-namespace-resources
  namespace: development # 制限をかけたい名前空間
spec:
  hard:
    # このNamespace全体で消費できるCPUとメモリの合計値
    requests.cpu: "2"
    requests.memory: 1Gi
    limits.cpu: "4"
    limits.memory: 2Gi
    # 作成できるPod数も制限し、過剰な負荷発生源を作らせない
    pods: "10"

2. LimitRangeで「個々のコンテナ」を縛る

開発者がリソース要求を明記しなかった場合、K8sはデフォルトで無制限に近いリソースを割り当ててしまうことがある。それを防ぐのがLimitRangeだ。

# limit-range.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: development
spec:
  limits:
  - default:
      cpu: 500m
      memory: 256Mi
    defaultRequest:
      cpu: 100m
      memory: 128Mi
    type: Container

—

現場で差がつく「運用Tips」

コードを書くとき、インフラを構築するとき、以下の3点を意識するだけで、防御力は格段に上がる。

1. ServiceAccountの権限を最小化せよ:
ClusterRoleを無暗に与えるな。RoleとRoleBindingを使い、そのPodが本当に必要な名前空間の、必要なリソースしか触れないように制限する。これが「トークンを盗まれたとき」の被害を最小限にする唯一の防波堤だ。
2. API Rate Limitingの設定を確認せよ:
マネージドK8s(EKS, GKE, AKS)を使っている場合でも、APIサーバーのレート制限パラメータが適切か確認すべきだ。必要に応じて、コントロールプレーンのログを監視し、異常なリクエストパターンを検知したら即座に遮断できる体制を組んでおこう。
3. WAFによる保護:
もしAPIサーバーを公開せざるを得ない場合(基本は推奨しないが)、グローバルな通信に対しては、IPフィルタリングや、レート制限機能を持つWAF越しにアクセスさせること。

最後に:セキュリティは「性悪説」で設計せよ

「自分の書いたコードや構築したインフラが、悪意ある第三者にハックされたらどう動くか?」――常にこの視点を持つこと。

Kubernetesは強力なツールだが、その分、誤った設定は致命的な脆弱性に直結する。今日紹介したResourceQuotaとLimitRangeは、いわばクラスターを守るための「最低限の規律」だ。まずは自分の担当するNamespaceから、この設定が入っているか確認してほしい。

セキュリティは一度やって終わりではない。日々の運用の中で、攻撃者の手法を先読みし、泥臭く設定を磨き続ける。それこそが、トップクラスのエンジニアの姿だと私は信じている。

コメント

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