RBAC / NetworkPolicy / ResourceQuota
1つのクラスタに複数のチーム · 環境が一緒に住むマルチテナント運用の隔離を作る3つのポリシーオブジェクトを扱います。RBAC の Role · ClusterRole · ServiceAccount · RoleBinding モデル、NetworkPolicy の default-deny パターンと CNI 依存、ResourceQuota と LimitRange の対の関係までを一連の流れで整理しながら2部を締めくくります。
2部の最後の章です。第8章 StatefulSet / DaemonSet / Job / CronJob から 第13章 オートスケーリング まで、ワークロードを運用するモデルを一層ずつ積み上げてきました。コントローラ4種、永続データ、外部進入点、リソース要求 · 上限、ヘルスチェック、オートスケーリングまで — Pod 1個を安定的に立ち上げ、負荷に合わせて増やし減らす一連の流れが手に入りました。本章ではその上に一層さらに載せるテーマを扱います — 1つのクラスタに複数のチーム · 環境が一緒に住む状況のセキュリティとリソース統制 です。キーワードは3つです。RBAC (誰が何をできるか)、NetworkPolicy (どのトラフィックが通るか)、ResourceQuota (どれだけ作れるか)。3つのオブジェクトすべてがネームスペース単位ポリシーだという共通点があり、第7章 Namespace とラベル で「Namespace 自体はセキュリティ境界ではない」と押さえておいたその空白を、この3つのオブジェクトが埋めます。
本章の終わりには 1つのクラスタの上に複数の環境 · チームが安全に一緒に住める隔離の3次元 が手に入ります。2部の振り返りと次の部 (3部 深さ) の案内も一緒に込めます。
3つのポリシーの共通座標 — ネームスペース単位 #
第7章 で Namespace を扱うとき一行を残しておきました — Namespace 自体はセキュリティ境界ではありません。 オブジェクト名を分ける論理的な区画でしかなく、本当の隔離はその上に載るポリシーオブジェクトたちが作るという話でした。その上に載るポリシーの本体が本章のテーマ3つです。
| 次元 | オブジェクト | 説明 |
|---|---|---|
| 権限 | Role / ClusterRole / RoleBinding / ClusterRoleBinding | 誰がどのオブジェクトにどの動詞を使えるか |
| トラフィック | NetworkPolicy | どの Pod がどの Pod と通信できるか |
| リソース | ResourceQuota / LimitRange | 1つのネームスペースがどれだけ作れるか |
3つのオブジェクトすべてがネームスペース単位で適用されるか (NetworkPolicy、ResourceQuota、LimitRange、Role / RoleBinding)、ネームスペースに連携して適用されます (ClusterRole + RoleBinding の組み合わせ)。1つのクラスタの上に dev / staging / prod、またはチーム A / チーム B が一緒に住むマルチテナント運用の隔離は、この3次元が合わさったとき初めて完成します。
本章の流れは単純です。権限から — RBAC を最も詳しく扱い、その次にトラフィック (NetworkPolicy)、その次にリソース (ResourceQuota / LimitRange) の順で進みます。
RBAC — 誰が何をできるか #
RBAC (Role-Based Access Control) は K8s API 呼び出し単位で権限を表現するモデルです。kubectl get pods、kubectl create deployment、kubectl delete secret のようなすべての動作は結局 K8s API サーバに対する HTTP リクエストです。RBAC はそのリクエスト1件1件に対して「この主体がこの動詞をこのリソースに使えるか」を検査します。
モデルは4つのオブジェクトで表現されます。権限のまとまり (Role / ClusterRole) と、その権限と主体をつなぐオブジェクト (RoleBinding / ClusterRoleBinding) です。
| オブジェクト | 何か | スコープ |
|---|---|---|
Role | 権限のまとまり (verbs + resources) | ネームスペース |
ClusterRole | 権限のまとまり (verbs + resources) | クラスタ (すべてのネームスペース共有) |
RoleBinding | Role または ClusterRole を主体に付与 | ネームスペース |
ClusterRoleBinding | ClusterRole を主体に付与 | クラスタ全域 |
ここで一つ微妙な部分があります。RoleBinding は ClusterRole を参照することもできます。 ClusterRole は権限のまとまりで RoleBinding はそのまとまりをどのネームスペースで誰に与えるか決めるオブジェクトなので、「標準 ClusterRole (例: view、edit) を1つ作っておいてネームスペースごとに RoleBinding で別々の人に付与」するパターンが運用で最もよくあります。
本章は RBAC のマニフェストと運用パターンまでを扱います。Aggregated ClusterRole、impersonation、EKS の IRSA · GKE の Workload Identity のような外部 IAM マッピング、トークンライフサイクルのような深さは 第16章 RBAC / ServiceAccount の深層 で本格的に扱います。
Subject — 権限を受ける側 #
権限が付与される主体 (Subject) は3つです。
- User — 人のユーザです。K8s 自体にはユーザのデータベースがなく、外部認証 (OIDC、x509 クライアント証明書、クラウド IAM マッピングなど) がユーザ名を教えてくれます。
- Group — ユーザのまとまりです。User と同様に外部認証がグループ情報を K8s に伝えます。
- ServiceAccount — Pod が K8s API にアクセスするとき使う ID です。人ではなくワークロードのアイデンティティです。
この3つのうち K8s マニフェストで直接作って管理するのは ServiceAccount がほぼ唯一です。User と Group は外部認証の産物なので K8s の中にオブジェクトとして存在しません。RoleBinding の subjects フィールドに書かれるだけです。
ServiceAccount — Pod の ID #
すべての Pod はある ServiceAccount の ID を持ってクラスタに住んでいます。マニフェストに spec.serviceAccountName を書かないとそのネームスペースの default ServiceAccount が自動で結ばれます。Pod の中で kubectl のようなツールで K8s API にアクセスすると、その呼び出しはその ServiceAccount の権限で行われます。
kubectl get serviceaccounts -n defaultNAME SECRETS AGE
default 0 3d基本の default ServiceAccount はどの権限も付与されていません。RBAC を適用した運用クラスタで Pod の中から kubectl get pods を試みると次のメッセージが出るのが正常です。
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:default" cannot list resource "pods" in API group "" in the namespace "default"このメッセージを見て RoleBinding で権限を結んでやれば同じコマンドが通ります。次の例でその流れを追いかけます。
RBAC マニフェスト1まとまり #
最も単純なシナリオをマニフェスト1枚に整理してみます。dev ネームスペースに pod-reader という ServiceAccount を作り、その SA に「Pod を読める権限」を付与します。そしてその SA を使う Pod の中で kubectl get pods が通るか確認する流れです。
apiVersion: v1
kind: ServiceAccount
metadata:
name: pod-reader
namespace: dev
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: dev
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader
namespace: dev
subjects:
- kind: ServiceAccount
name: pod-reader
namespace: dev
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io3つのオブジェクトの責任を一行ずつ押さえておきます。
- ServiceAccount
pod-reader—devネームスペースの新しい ID です。まだ何の権限もありません。 - Role
pod-reader—podsリソースに対してget、list、watchの動詞を許可する権限のまとまりです。apiGroups: [""]はコア API グループ (Pod、Service、ConfigMap など) を指します。 - RoleBinding
pod-reader— Role と ServiceAccount をつなぐオブジェクトです。subjectsが受ける側、roleRefが与える側です。
この3つのオブジェクトを一度に適用したあと、その ServiceAccount を使う Pod を立ち上げてみます。
apiVersion: v1
kind: Pod
metadata:
name: reader
namespace: dev
spec:
serviceAccountName: pod-reader
containers:
- name: kubectl
image: bitnami/kubectl:1.32
command: ["sleep", "3600"]kubectl apply -f rbac-pod-reader.yaml
kubectl apply -f reader-pod.yaml
kubectl exec -n dev reader -- kubectl get pods -n devNAME READY STATUS RESTARTS AGE
reader 1/1 Running 0 30s同じ Pod の中で権限のない動作を試みると止められることも確認できます。
kubectl exec -n dev reader -- kubectl create deployment nginx --image=nginx -n deverror: failed to create deployment: deployments.apps is forbidden: User "system:serviceaccount:dev:pod-reader" cannot create resource "deployments" in API group "apps" in the namespace "dev"pod-reader Role は Pod の get / list / watch だけを与えて Deployment の create は与えなかったので、正確にその部分で拒否されます。
verbs と resources の核心 #
Role / ClusterRole の rules でよく使われる verbs を表に整理すると次のとおりです。
| verb | 意味 |
|---|---|
get | 単一オブジェクトの照会 |
list | オブジェクト一覧の照会 |
watch | 変更イベントの購読 |
create | オブジェクト生成 |
update | オブジェクト更新 (全体) |
patch | オブジェクト部分更新 |
delete | オブジェクト削除 |
deletecollection | マッチするオブジェクトの一括削除 |
読み取りだけ許可するなら get、list、watch の3つを一緒に与えます。kubectl get のようなコマンドが内部的に list を使い、watch は informer キャッシュの更新に使われるからです。書き込みまで許可するなら create、update、patch、delete を追加します。
resources は pods、services、configmaps のように複数形の名前を書きます。apiGroups はそのリソースが属する API グループです。コアグループ (Pod / Service / ConfigMap / Secret など) は [""] (空文字列)、Deployment / StatefulSet / DaemonSet は ["apps"]、Job / CronJob は ["batch"]、Ingress は ["networking.k8s.io"] です。リソースがどのグループに属するかは kubectl api-resources で一度に確認できます。
kubectl api-resourceskubectl auth can-i — 権限の検証 #
RBAC を触っておくと次の質問がすぐに付いてきます — 「それでこのユーザは本当にこの動作ができるのか?」マニフェストをしばらく見ていても結果が一目で入ってこないことが多いです。K8s がこの質問に直接答えてくれるコマンドが kubectl auth can-i です。
kubectl auth can-i create pods -n dev
kubectl auth can-i delete deployments -n prodyes / no のどちらか一つが出力されます。別のユーザや ServiceAccount の立場で問いたいなら --as オプションで impersonation を使います。
kubectl auth can-i create pods --as=alice -n dev
kubectl auth can-i list secrets --as=system:serviceaccount:dev:pod-reader -n dev--as オプション自体にも権限が必要です (impersonation 権限)。運用クラスタの admin が新しく作った RBAC ポリシーが意図どおり動作するか確認するとき最もよく使われるパターンです。すべての権限を一度に見たいなら --list を付けます。
kubectl auth can-i --list --as=alice -n dev診断の完成された流れと一般的な権限拒否のトラブルシューティング木は 第27章 kubectl デバッグパターン で整理します。
よくある落とし穴 — 広すぎる ClusterRole #
RBAC を最初に適用するとき最もよく犯すミスが 面倒さに負けて ClusterRole cluster-admin を ServiceAccount に結ぶ パターンです。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: app-admin
subjects:
- kind: ServiceAccount
name: app
namespace: dev
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.iocluster-admin は K8s API 全体に対する無制限の権限です。この ClusterRoleBinding が適用された ServiceAccount のトークンが Pod 1個でも外部へ漏れると、そのトークンでクラスタのすべてのネームスペースのすべての Secret を読み、すべてのオブジェクトを消せます。コンテナイメージの中のライブラリに脆弱性が一つあるだけでもその一点がクラスタ全体の事故に広がります。
運用の標準原則は 最小権限 (least privilege) です。ワークロードが本当に必要な verbs と resources だけを正確に絞って Role にまとめ、その Role を RoleBinding で付与します。K8s があらかじめ作っておく標準 ClusterRole があり、これを RoleBinding でネームスペースに限定して使うパターンが一般的な出発点です。
| ClusterRole | 説明 |
|---|---|
view | ネームスペースのオブジェクトを読み取り。Secret は除く |
edit | view + ほとんどのオブジェクトの書き込み。Role / RoleBinding など RBAC オブジェクトは除く |
admin | edit + そのネームスペースの中の RBAC オブジェクト管理 |
cluster-admin | クラスタ全体に無制限 |
view / edit / admin を RoleBinding で特定のネームスペースに限定すると、人 · チーム · サービスに適度な権限のまとまりを速く付与でき、cluster-admin は クラスタ運用者一握り にだけ ClusterRoleBinding で付与する形が標準です。マニフェスト自体を admission の段階で止めるポリシー (例: 「cluster-admin の連携を禁止」) は 第17章 Admission Controller の OPA Gatekeeper · Kyverno が扱う領域です。
automountServiceAccountToken #
ServiceAccount のトークンは基本的に Pod の中の /var/run/secrets/kubernetes.io/serviceaccount/token に自動でマウントされます。K8s API を呼ぶ予定のない Pod には、そのトークンすらマウントしない方が安全です。マニフェストの automountServiceAccountToken: false でオフにできます。
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
automountServiceAccountToken: false
containers:
- name: nginx
image: nginx:1.27この一行を入れておくと、その Pod が万一侵害されても K8s API に直接アクセスするトークンがありません。セキュリティガイドの常連の推奨事項です。トークンを外部の秘密ストア · IRSA と連携して「パスワード0」で運用する本格的なパターンは 第29章 シークレット運用 で扱います。
NetworkPolicy — Pod 間トラフィックの統制 #
RBAC が K8s API に対する権限を扱うとすれば、NetworkPolicy は Pod 間の IP トラフィック を扱います。同じクラスタの2つの Pod が互いの IP を知って通信しようとするとき、そのトラフィックが許可されるか検査するポリシーです。
基本はすべて通過 #
K8s ネットワークモデルの基本は単純です — NetworkPolicy がなければすべての Pod が互いに通信できます。 同じネームスペースであれ別のネームスペースであれ、Pod の IP さえ知れば自由にパケットを送れます。マルチテナントクラスタでこの基本値がそのまま置かれると、1つのネームスペースの Pod が別のネームスペースの DB Pod に自由にアクセスする形になります。
NetworkPolicy の動作ルールは次の2行に整理されます。
- NetworkPolicy が1つでもマッチする Pod のトラフィックは、そのポリシーの
policyTypesに書かれた方向に対して default-deny が適用されます。 - そしてそのポリシーの
ingress/egressルールに明示的に許可されたトラフィックだけが通過します。
マッチするポリシーが1枚もない Pod は上のルールが発動しないのですべてのトラフィックが通ります。マッチするポリシーが1枚でもあると、そのポリシーの方向に対してはホワイトリストモデルへ転換されます。
CNI が NetworkPolicy を支援しなければならない #
NetworkPolicy は K8s マニフェスト次元では標準ですが、実際にトラフィックを止める作業は CNI (Container Network Interface) プラグインがします。 だから CNI が NetworkPolicy を支援しないとマニフェストを適用しても何も起こりません。トラフィックはそのまま通ります。
| CNI | NetworkPolicy 支援 |
|---|---|
| Calico | 支援 |
| Cilium | 支援 (eBPF ベース) |
| Antrea | 支援 |
| flannel | 未支援 |
| EKS の amazon-vpc-cni | 別途オプションの有効化が必要 (Calico を一緒にインストールするか vpc-cni の NetworkPolicy オプションをオンにしなければならない) |
運用クラスタで NetworkPolicy を使う計画なら、クラスタを作るときから CNI を選んでおかなければなりません。基本の EKS クラスタで NetworkPolicy マニフェストを適用して「なぜトラフィックが止まらないのか?」がよくある落とし穴です — CNI が支援しなければマニフェストはただ etcd に入っているオブジェクトでしかありません。CNI データプレーンの本格的なモデル (iptables ベース vs eBPF ベース、Calico vs Cilium) は 第15章 CNI の深層 で扱います。
default-deny → allow パターン #
運用の標準パターンは ネームスペースに default-deny ポリシーを1枚かけて、必要な通信だけを明示的に許可 することです。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: prod
spec:
podSelector: {}
policyTypes:
- Ingress
- EgresspodSelector: {} は空のセレクタで「このネームスペースのすべての Pod」を指します。policyTypes に Ingress と Egress がどちらも書かれていて ingress / egress のルールが1行もないので、このネームスペースのすべての Pod は入ってくるトラフィックも出ていくトラフィックもすべて遮断されます。
この状態のままにしておくと Pod が DNS の照会すらできなくなるので、最低限 DNS トラフィックは解放しなければなりません。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: prod
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53その次にワークロードごとに必要な通信を1枚ずつ追加します — frontend が backend へ行く 80/TCP、backend が DB へ行く 5432/TCP のような具合です。
NetworkPolicy マニフェスト — frontend → backend #
最もよくある1コマを1枚に書いておくと次のとおりです。backend Pod が frontend Pod から入ってくる 8080/TCP トラフィックだけを受けるようにする ingress ポリシーです。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-allow-frontend
namespace: prod
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080読み方は次のとおりです。
spec.podSelector— このポリシーが適用される Pod です。app=backendのラベルが付いた Pod にだけ適用されます。policyTypes: [Ingress]— 入ってくる方向に対するポリシーであることを明示します。egress はこのポリシーでは制御しません。ingress[0].from— どこから来るトラフィックを許可するか。app=frontendのラベルが付いた Pod から来ます。ingress[0].ports— どのポートに対して。8080 / TCP だけを許可します。
from のセレクタは3つの中から選べます — この3つは別々にまたは一緒に使えます。
| セレクタ | 意味 |
|---|---|
podSelector | 同じネームスペースの Pod ラベルマッチ |
namespaceSelector | 別のネームスペースのすべての Pod (またはそのネームスペース + podSelector の組み合わせ) |
ipBlock | CIDR 表現で IP 範囲 (外部 IP またはノード IP) |
namespaceSelector と podSelector を同じ from の項目に一緒に書くと「特定のネームスペースの特定のラベルの Pod」になります。2つを別々に書くと「そのネームスペースのすべての Pod または同じネームスペースのそのラベルの Pod」の意味になってしまうので、意図した形が何かを正確に見て書かなければなりません。
ingress:
- from:
- namespaceSelector:
matchLabels:
env: prod
podSelector:
matchLabels:
app: frontendingress:
- from:
- namespaceSelector:
matchLabels:
env: prod
- podSelector:
matchLabels:
app: frontendこの2つのマニフェストの意味が異なるという点が NetworkPolicy の常連の落とし穴です。上のマニフェストは「env=prod ネームスペースの frontend Pod だけ」で、下のマニフェストは「env=prod ネームスペースのすべての Pod または同じネームスペースの frontend Pod」です。
egress ルール — 出ていく方向 #
ingress の鏡が egress です。backend Pod が DB へ 5432 ポートで出ていく通信だけを許可するポリシーは次の形です。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-egress-to-db
namespace: prod
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432このポリシー1枚が適用されると backend Pod は postgres Pod の 5432 / TCP 以外にはどこへも出ていけません。上で作った default-deny + allow-dns の組み合わせと合わせると、backend Pod の出ていく通信は「DNS + DB」の2つに限定されます。外部インターネットへ行く通信をワークロードごとに正確にホワイトリストで狭めておくのが運用セキュリティの標準の形です。
NetworkPolicy の限界 #
NetworkPolicy は L3 / L4 ポリシー です。IP、ポート、プロトコルだけを見ます。HTTP メソッドやパスのような L7 ポリシーは NetworkPolicy の範囲を外れます — Cilium の L7 ポリシーや Istio / Linkerd のようなサービスメッシュがその次元を扱います (後続の K8s 深掘り本の領域です)。そして NetworkPolicy はクラスタの中のトラフィックポリシーで、外部インバウンドは 第10章 Ingress の Ingress · LoadBalancer の次元 で、外部アウトバウンドは NAT ゲートウェイのセキュリティグループ で別途統制されます。1つのクラスタのセキュリティの形は複数の層のポリシーが一緒に作っていきます。
ResourceQuota — ネームスペースのリソース合計上限 #
第11章 resources.requests / limits でコンテナ単位のリソースモデル — requests と limits — を扱いました。コンテナ1個の保証と上限を決めるオブジェクトでした。その上に一層さらに載せるのが ネームスペース単位の合計上限 である ResourceQuota です。
運用シナリオは明確です。1つのクラスタに dev / staging / prod、または複数のチームが一緒に住むとき、dev ネームスペースがすべてのノードの CPU を使い尽くして prod ワークロードのリソースが足りなくなる事故を防がなければなりません。ResourceQuota がその空白を埋めます。
ResourceQuota マニフェスト #
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: dev
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "50"
services: "20"
configmaps: "30"
secrets: "30"
persistentvolumeclaims: "10"
requests.storage: 100Giこの ResourceQuota が dev ネームスペースに適用されると次の合計が限度を超えられません。
- そのネームスペースの中のすべての Pod の
requests.cpuの合計 ≤ 4コア requests.memoryの合計 ≤ 8Gilimits.cpuの合計 ≤ 8コアlimits.memoryの合計 ≤ 16Gi- オブジェクトの個数 — Pod 50個、Service 20個、ConfigMap · Secret 各30個、PVC 10個
- PVC の
requests.storageの合計 ≤ 100Gi
上限を超えるオブジェクトの生成は K8s API サーバで拒否されます。dev ネームスペースにすでに4コアが割り当てられた状態で追加 Pod の requests.cpu: 1 を作ろうとすると、その Pod の生成リクエストは admission の段階で拒否され次のメッセージが出ます。
Error from server (Forbidden): error when creating "...": pods "..." is forbidden: exceeded quota: dev-quota, requested: requests.cpu=1, used: requests.cpu=4, limited: requests.cpu=4ResourceQuota 動作の確認 #
kubectl get resourcequota -n dev
kubectl describe resourcequota dev-quota -n devName: dev-quota
Namespace: dev
Resource Used Hard
-------- ---- ----
configmaps 12 30
limits.cpu 6 8
limits.memory 12Gi 16Gi
pods 18 50
persistentvolumeclaims 3 10
requests.cpu 3 4
requests.memory 6Gi 8Gi
requests.storage 30Gi 100Gi
secrets 15 30
services 8 20Used / Hard の表が1ページに出る形です。運用クラスタで1つのネームスペースがどこまで埋まっているか確認するとき describe が最も速いツールです。
LimitRange と対 — コンテナ単位の基本値 · 上限 #
ResourceQuota の微妙な落とし穴の一つが — ResourceQuota が有効化されたネームスペースに Pod を作るとき、コンテナに requests / limits を書かないと拒否されます。 ResourceQuota が合計を計算するにはすべてのコンテナのリソース値が必要なのに、マニフェストに書かれていないコンテナは合計の計算ができないからです。
この部分の運用の安全網が LimitRange です。LimitRange はコンテナ単位で基本値と最大値 · 最小値を決めるオブジェクトです。第11章 で一度押さえたオブジェクトで、本章では ResourceQuota と対でもう一度整理します。
apiVersion: v1
kind: LimitRange
metadata:
name: dev-limits
namespace: dev
spec:
limits:
- type: Container
default:
cpu: 200m
memory: 256Mi
defaultRequest:
cpu: 100m
memory: 128Mi
max:
cpu: "2"
memory: 2Gi
min:
cpu: 50m
memory: 64Miこの LimitRange が適用されたネームスペースに Pod マニフェストが入ってくると次のことが起こります。
- コンテナに
requestsがなければdefaultRequest(100m / 128Mi) が自動で埋められます。 - コンテナに
limitsがなければdefault(200m / 256Mi) が自動で埋められます。 - コンテナの
requestsやlimitsがmax(2 / 2Gi) を超えると拒否されます。 min(50m / 64Mi) 未満なら拒否されます。
ResourceQuota と LimitRange の責任を分けておくと一行ずつ整理されます。
| オブジェクト | 単位 | 何を決めるか |
|---|---|---|
LimitRange | コンテナ | 基本値 · 最大 · 最小 |
ResourceQuota | ネームスペース | 合計上限、オブジェクト個数の上限 |
運用の形は2つを一緒に置くことです。LimitRange が壊れたマニフェストの空白を埋めてくれて、ResourceQuota がその埋められた値たちの合計が限度を超えないように止めます。2つが一緒にあって初めてマルチテナント運用のリソースポリシーが安定的に回ります。
scopes / scopeSelector — 一部の Pod にだけ #
ResourceQuota は基本的にネームスペースのすべての Pod に適用されますが、scope を狭められます。よく使われるパターンは PriorityClass 別の分離です — 例えば high-priority ワークロードのリソース合計だけを別に制限したり、BestEffort QoS の Pod だけを別途制限する具合です。
apiVersion: v1
kind: ResourceQuota
metadata:
name: high-priority-quota
namespace: dev
spec:
hard:
requests.cpu: "2"
requests.memory: 4Gi
scopeSelector:
matchExpressions:
- operator: In
scopeName: PriorityClass
values: ["high"]運用の基本の形では scope なしで全体に適用する1枚から始め、必要なとき scope を持つポリシーを追加する方式が無難です。
3つのポリシーの協業 — マルチテナントクラスタの隔離 #
3つのオブジェクトが作る隔離の形を1つの図に整理しておくと次のとおりです。
[ RBAC ] 誰がオブジェクトを作れるか
│ (verbs × resources × namespace)
│
[ NetworkPolicy ] 作られた Pod が誰と通信するか
│ (podSelector × from/to × ports)
│
[ ResourceQuota ] そのネームスペースがどれだけ作れるか
│ (cpu/memory 合計 + オブジェクト個数)
│
[ LimitRange ] コンテナ単位の基本値 · 上限
(default / max / min)3つのオブジェクトが別々に回っているように見えますが、実際には1つのネームスペースの隔離を一緒に作ります。dev ネームスペースに RBAC を適用して dev チームだけがその中のオブジェクトを触れるようにし、NetworkPolicy で dev の Pod が prod の DB へ行くトラフィックを止め、ResourceQuota で dev が使い尽くせる CPU · メモリ · オブジェクト個数を限定します。この3つがすべて適用されているとき、dev で発生した事故が staging と prod へ漏れない隔離が成立します。
この隔離がきれいに回るにはもう一つの前提が必要です — ネームスペース自体をよく分けておくこと です。環境別 (dev / staging / prod)、チーム別 (team-a / team-b)、またはサービス単位でネームスペースをどう分けるかのポリシーは、クラスタを最初にセットアップするときに決めておかなければならない決定です。この決定を曖昧にしたまま RBAC / NetworkPolicy / ResourceQuota を適用しようとすると、ポリシーの目をどこに合わせるべきか毎回揺れます。
2部の振り返り — 7章で手に入ったもの #
2部の最後の章なので一度整理します。1部がマニフェスト1枚を読み書きする段階まで連れていってくれたとすれば、2部はその上に運用の目を一層ずつ加えました。
- 第8章 — StatefulSet / DaemonSet / Job / CronJob です。Deployment ではないコントローラ4種で、アイデンティティとディスクが必要なワークロード、ノードごとに1つずつ立ち上がらなければならないワークロード、一度きりの作業、周期実行の作業の4つのパターンを扱います。
- 第9章 — PV / PVC / StorageClass です。永続データモデルとして、静的 · 動的プロビジョニング、accessModes、reclaimPolicy、volumeBindingMode、allowVolumeExpansion を整理し、StatefulSet の volumeClaimTemplates が何を作るかを説明します。
- 第10章 — Ingress と Ingress Controller です。外部進入点を集約するオブジェクトと、そのマニフェストを実際のトラフィックルーティングへ解いてくれるコントローラを扱い、HTTP / HTTPS、TLS 終端、仮想ホスト、パスベースのルーティングまで整理します。
- 第11章 — resources.requests / limits です。コンテナ単位のリソース要求と上限を説明し、requests がスケジューリングの基準、limits が OOM · CPU スロットリングの基準だという点と、QoS の3等級が evict 優先順位を決める流れを扱います。
- 第12章 — Health check です。liveness / readiness / startup probe の3つで、コンテナの生きていること · サービスの準備ができたこと · 初期化段階を K8s がどう判定するかを見ます。
- 第13章 — HPA / VPA / Cluster Autoscaler です。Pod 数、Pod リソース、ノード数が負荷に合わせて自動で変わる3次元を説明し、metrics-server · custom metrics · HPA + VPA の衝突の落とし穴も押さえます。
- 第14章 (本章) — RBAC / NetworkPolicy / ResourceQuota です。セキュリティとリソースポリシーを通じて、誰が、どのトラフィックが、どれだけ許可されるかのマルチテナントクラスタの隔離の3次元を扱います。
この7章をすべて追ってきた時点なら、会社のクラスタのマニフェストディレクトリでどんな種類のオブジェクトに出会っても、その意図と運用上の落とし穴を一行で読める段階です。kind: StatefulSet を見ると volumeClaimTemplates と headless Service を自然に思い浮かべ、kind: Ingress を見るとその後ろの Ingress Controller が何かを問い、resources の下の空の limits を見ると OOM の危険と LimitRange の不在を同時に疑うようになります。マニフェスト1枚がクラスタの中でどう回るかのモデルが頭の中に定着した段階です。
練習問題 #
- 上の本文の
rbac-pod-reader.yamlとreader-pod.yamlを順に適用したあと、kubectl exec -n dev reader -- kubectl get pods -n devとkubectl exec -n dev reader -- kubectl create deployment nginx --image=nginx -n devの2つのコマンドの結果を記録します。その次に同じ SA にdeploymentsのcreate権限をさらに付与するには Role のrulesをどう追加すべきかをマニフェスト一行で書き、kubectl auth can-i create deployments --as=system:serviceaccount:dev:pod-reader -n devで検証します。 prodネームスペースに §「default-deny → allow パターン」のdefault-deny-allとallow-dnsの2つのポリシーを適用したあと、frontend → backend 8080 / TCP だけを許可するポリシー1枚を追加します。その次に backend Pod の中から別のネームスペースの任意の Service へcurlを試みて遮断されるか、許可された frontend からは通るかを時間順に記録します。CNI が NetworkPolicy を支援しないクラスタ (例: 基本の flannel) では同じポリシーがトラフィックを止められないという §「CNI が NetworkPolicy を支援しなければならない」のモデルとどうつながるかを一段落でメモします。devネームスペースにdev-quotaとdev-limitsの2つのオブジェクトを一緒に適用します。requests/limitsを抜かした Deployment マニフェストを apply したとき LimitRange が自動で埋めてくれる値、maxを超えるマニフェストが拒否されるメッセージ、ResourceQuota の合計が限度に達したとき新しい Pod の生成が拒否されるメッセージをそれぞれ記録します。3つのメッセージがどの段階 (admission、validation) で出るかを §「3つのポリシーの協業」の図と合わせて一段落に整理します。
一行まとめ: マルチテナントクラスタの隔離は、RBAC (K8s API 権限)、NetworkPolicy (Pod 間の IP トラフィック)、ResourceQuota + LimitRange (ネームスペースのリソース合計 + コンテナ単位の基本値) の3次元が合わさったとき成立する。運用の標準原則は RBAC の最小権限、NetworkPolicy の default-deny + allow、ResourceQuota と LimitRange の対の運用だ。Namespace 自体はセキュリティ境界ではなく、この3つのポリシーが載って初めて本当の隔離が作られる。
次の章 #
2部が終わりました。3部 深さの最初の章である 第15章 CNI の深層 からは視点を一段さらに移します — マニフェストの動作を支える データプレーン · ポリシーエンジン · API 拡張 の深さへ入っていきます。本章の NetworkPolicy が実際にどう止められるかの答えが第15章の Calico / Cilium / eBPF です。
3部全体の筋書きは次のとおりです。
| 章 | テーマ |
|---|---|
| 第15章 | CNI の深層 — Calico · Cilium · eBPF |
| 第16章 | RBAC · ServiceAccount の深層 — Aggregated ClusterRole · Impersonation · IRSA · Workload Identity |
| 第17章 | Admission Controller — OPA Gatekeeper · Kyverno |
| 第18章 | CRD と Operator パターン — controller-runtime |
| 第19章 | 可観測性 — Prometheus · Grafana · Loki · OpenTelemetry |
| 第20章 | GitOps — ArgoCD · Flux |
3部を終えるとクラスタをセットアップする人の視野で K8s を見られる段階に到達します。その次の 4部 EKS 実戦 では、AWS EKS の上に実際のサービスを最初から載せて運用する一連の流れを追いかけます。