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