Certified Kubernetes Administrator (CKA) #9 RBAC: Role/ClusterRole、RoleBinding、ServiceAccount、kubectl auth can-i

#8 証明書管理 では PKI と kubeconfig を扱い、誰がクラスターに入ってくるか、つまり認証 (authentication) を整理しました。CSR でユーザー証明書を発行すれば、そのユーザーは apiserver に自分が誰かを証明できます。ところが入ってきた人が何でもできるなら、それは運用ではありません。この記事はその次の問い、誰が何をできるか、つまり認可 (authorization) を扱います。

Kubernetes のデフォルト認可モードが RBAC (Role-Based Access Control) です。CKAD でも RBAC を短く触れましたが、CKA は運用者の視点からもう一段深く入ります。ClusterRole を RoleBinding で束ねてネームスペースを限定する組み合わせ、ServiceAccount にアプリ権限を付与するパターン、auth can-i --as で他人の権限を代わりに確認する検証まで手に馴染ませる必要があります。RBAC は #25 Troubleshooting 4 でも「権限がなくて作業が止まる」障害の原因として再び出てくるので、ここで構造をしっかり固めておきます。

認証の次の認可: 誰が何をできるか #

apiserver に届いたすべてのリクエストは、3 つの関門を順番に通過します。まず 認証 で「あなたは誰か」を確認し、次の 認可 で「その作業をしてよいか」を判定し、最後の admission control で「その内容がポリシーに合うか」を検査します。RBAC はこのうち 2 番目の関門を担当します。

RBAC の判定方式はシンプルです。デフォルトは すべて拒否 であり、あるルールがそのリクエストを明示的に許可したときだけ通過します。つまり RBAC には「拒否」ルールがありません。許可ルールを積み上げる方式であり、どこにも許可がなければそのリクエストは拒否されます。この加算 (additive) モデルを頭に刻んでおくと、「なぜ権限がないのか」という問いに「許可ルールがないから」とすぐに答えられます。

RBAC の 4 つのオブジェクト #

RBAC は 4 種類のオブジェクトだけで構成されます。2 つは 権限の束 を定義し、残りの 2 つはその束を 誰に 与えるかを接続します。

オブジェクト役割範囲
Role権限ルールの束1 つのネームスペース内
ClusterRole権限ルールの束クラスター全体 / 全ネームスペース / 非ネームスペースリソース
RoleBinding束を subject に接続1 つのネームスペース内
ClusterRoleBinding束を subject に接続クラスター全体

権限を定義するオブジェクト (Role/ClusterRole) と、それを付与するオブジェクト (RoleBinding/ClusterRoleBinding) が 分離 されている点が核心です。同じ ClusterRole 1 つを複数の RoleBinding がそれぞれ別のネームスペースで再利用できるのは、この分離のおかげです。

rules: apiGroups / resources / verbs #

Role と ClusterRole の中身は rules 配列です。ルール 1 行は 3 つの軸で「どのリソースにどの動作を許可するか」を書きます。

  • apiGroups: リソースが属する API グループ。core グループ (Pod、Service、ConfigMap など) は空文字列 "" で書きます。Deployment・ReplicaSet は apps、Job は batch、Ingress・NetworkPolicy は networking.k8s.io に属します。
  • resources: 対象リソースの複数形の名前。podsdeploymentsservices のようにです。pods/logpods/exec のような サブリソース もここで別に指定します。
  • verbs: 許可する動作。getlistwatchcreateupdatepatchdeletedeletecollection があります。よく読み取り専用は get/list/watch の 3 つを一緒に与えます。

特定のオブジェクトだけに限定するには resourceNames で名前を固定することもできます。ただし listwatchcreate には resourceNames が適用されないので、運用では「この名前の ConfigMap だけ get/update」のような狭い権限に主に使います。

subjects: User / Group / ServiceAccount #

RoleBinding と ClusterRoleBinding の subjects は権限を受け取る主体です。3 種類があります。

  • User: 人間ユーザー。Kubernetes には User オブジェクトがありません。#8 で見たように、証明書の CN のような外部の身元がそのまま User 名になります。
  • Group: ユーザーのグループ。証明書の O フィールドやトークンの group claim で決まります。system:masters のようにクラスターがあらかじめ定義したグループもあります。
  • ServiceAccount: アプリ (Pod) の身元。ネームスペースに属する実際のオブジェクトであり、Pod が apiserver を呼び出すときに使う権限主体です。

User と Group はクラスターが管理しない外部の身元であり、ServiceAccount だけがクラスター内のオブジェクトだという違いを覚えておくと、バインディングを書くときに迷いません。

Role vs ClusterRole、RoleBinding vs ClusterRoleBinding #

CKA で最もよく問われるのが、この 4 つのオブジェクトの 組み合わせ規則 です。権限の束 (Role/ClusterRole) とバインディング (RoleBinding/ClusterRoleBinding) をどう組み合わせるかによって、権限の及ぶ範囲が変わります。

権限の束バインディング結果の権限範囲
RoleRoleBindingその RoleBinding がある 1 つのネームスペース 内のリソース
ClusterRoleClusterRoleBinding全ネームスペース + 非ネームスペースリソース (クラスター全体)
ClusterRoleRoleBindingClusterRole に定義された権限を、その RoleBinding がある 1 つのネームスペースに限定 して付与
RoleClusterRoleBinding不可能。Role はネームスペースに紐づくので、クラスター範囲では付与できない

3 行目、ClusterRole を RoleBinding で束ねる組み合わせ が運用で特に有用です。「Pod を読む権限」のような ClusterRole を 1 度だけ定義しておき、チームごとに自分のネームスペースで RoleBinding でその ClusterRole を指せば、各チームは 自分のネームスペースの Pod だけ を読めます。権限の束は 1 揃いだけ維持しながら、適用範囲はネームスペースに狭めるわけです。

非ネームスペースリソースは ClusterRole でのみ #

ノード (Node)、PersistentVolume、Namespace 自体、CertificateSigningRequest のようなリソースは、どのネームスペースにも属しません。こうした クラスター範囲リソース に対する権限は Role では表現できず、必ず ClusterRole で定義する必要があります。「ノードを list する権限を作れ」という問題で Role を使うと答えがずれるのは、これが理由です。

generator で素早く作る #

試験で RBAC を YAML で手編集すると時間を失います。kubectl create generator で骨組みを作り、必要なときだけ $do (=--dry-run=client -o yaml) で抜き出して直す流れが速いです。

Role と ClusterRole #

# ネームスペース Role: pods を読み取り専用で
k create role pod-reader \
  --verb=get,list,watch \
  --resource=pods \
  -n dev

# サブリソースを含む (pods/log まで)
k create role log-reader \
  --verb=get,list \
  --resource=pods,pods/log \
  -n dev

# ClusterRole: クラスター範囲 (全 ns / Node など)
k create clusterrole deploy-manager \
  --verb=get,list,watch,create,update,patch,delete \
  --resource=deployments.apps

# ノードを読む ClusterRole
k create clusterrole node-viewer \
  --verb=get,list,watch \
  --resource=nodes

--resource=deployments.apps のように リソース.グループ 形式を使うと apiGroup を正確に指定できます。core グループのリソースは pods のようにグループなしで書きます。

RoleBinding と ClusterRoleBinding #

# Role をユーザーに (その ns 内だけで)
k create rolebinding pod-reader-bind \
  --role=pod-reader \
  --user=jane \
  -n dev

# ClusterRole を RoleBinding で: dev ns 内だけで deploy 管理
k create rolebinding deploy-mgr-bind \
  --clusterrole=deploy-manager \
  --user=jane \
  -n dev

# ClusterRole を ServiceAccount に (クラスター全体)
k create clusterrolebinding node-viewer-bind \
  --clusterrole=node-viewer \
  --serviceaccount=monitoring:metrics-sa

# ClusterRole をグループ全体に (クラスター全体)
k create clusterrolebinding dev-admins \
  --clusterrole=admin \
  --group=dev-team

--role は同じネームスペースの Role を、--clusterrole は ClusterRole を指します。subject は --user--group--serviceaccount=<ns>:<name> の中から選びます。ServiceAccount は必ず ネームスペース:名前 形式で書く必要がある点に注意します。

auth can-i: 権限を検証する #

RBAC を作った後、実際にその権限が通るか を確認せずに進むと、試験で点数を失います。kubectl auth can-i がこの検証ツールです。

# 自分の権限を確認
k auth can-i create deployments -n dev
# yes または no で答える

# 特定のユーザーになりすまして確認 (--as)
k auth can-i get pods --as jane -n dev

# グループまで真似る
k auth can-i delete nodes --as jane --as-group dev-team

# ServiceAccount の権限を確認
k auth can-i list pods \
  --as=system:serviceaccount:monitoring:metrics-sa -n dev

# その subject が何をできるかを一目で
k auth can-i --list --as jane -n dev

--asimpersonation (なりすまし) 機能です。管理者権限で、まるでそのユーザーがリクエストしたかのように apiserver に問い合わせ、RBAC の判定結果だけを受け取ります。実際に kubeconfig を変えずに「jane がこの作業をできるか」を即座に確認できるので、RBAC 作業の正解確認に最も速いです。

ServiceAccount を真似るときは --as=system:serviceaccount:<ネームスペース>:<名前> 形式を使います。この system:serviceaccount:... 文字列が、そのまま ServiceAccount の内部 User 名でもあります。

ServiceAccount: アプリに権限を与える #

ここまでの User/Group は人のためのものでした。ところがクラスター内で回るアプリが apiserver を呼び出さなければならないときにも権限が必要です。たとえばコントローラーが Pod を watch したり、モニタリングアプリがノード指標を読んだりする場合です。このとき使う身元が ServiceAccount です。

# ServiceAccount を作成
k create serviceaccount metrics-sa -n monitoring

# Pod に接続 (deployment の場合 spec.template.spec)
k set serviceaccount deployment/metrics metrics-sa -n monitoring

Pod の spec.serviceAccountName に ServiceAccount 名を書くと、その Pod 内には ServiceAccount トークンが自動でマウントされます。Pod 内のアプリはこのトークンで apiserver に認証し、その ServiceAccount にバインドされた Role/ClusterRole が許可する範囲でのみ動作できます。

運用の原則は 最小権限 です。アプリごとに専用の ServiceAccount を置き、そのアプリが実際に必要な動作だけを許可する Role をバインドします。すべてのネームスペースには default ServiceAccount がありますが、そこに権限を寄せると、そのネームスペースのすべての Pod が同じ権限を持つことになるので、専用の ServiceAccount を使う方が安全です。

#8 で作ったユーザーを接続する #

#8 で CSR でユーザー証明書を発行すると、その証明書の CN が User 名になります。このユーザーは認証はされますが、まだ何の権限もありません。RBAC で権限を付けて初めて作業できます。

# #8 で CN=jane で発行したユーザーに dev ns 権限を付与
k create role developer \
  --verb=get,list,watch,create,update,patch,delete \
  --resource=pods,deployments.apps,services \
  -n dev

k create rolebinding jane-dev \
  --role=developer \
  --user=jane \
  -n dev

# 検証
k auth can-i create deployments --as jane -n dev   # yes
k auth can-i create deployments --as jane -n prod   # no

このように 証明書で身元を作り (#8)、RBAC で権限を付ける (この記事) という 2 段階が合わさって、「特定のユーザーに特定のネームスペース権限を付与」という試験問題が完成します。

aggregated ClusterRole を一言 #

ClusterRole には、複数の ClusterRole をラベルで束ねて自動的に合成する aggregated ClusterRole 機能があります。aggregationRule にラベルセレクターを書いた ClusterRole は、そのラベルを持つ他の ClusterRole の rules を自動で吸収するので、admineditview のようなデフォルト ClusterRole に新しいリソースの権限をラベルだけ付けて拡張できます。

YAML 例 #

generator で十分ですが、構造を目で確認して直せる必要があります。2 つの代表的な組み合わせを YAML で見ます。

Role + RoleBinding (ネームスペース限定) #

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: dev
  name: pod-reader
rules:
  - apiGroups: [""]            # core グループ
    resources: ["pods", "pods/log"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: dev
  name: pod-reader-bind
subjects:
  - kind: User
    name: jane              # 証明書 CN などの外部の身元
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

roleRef は一度作ると 変更できません。バインディングの対象 Role を変えるには、RoleBinding を削除して作り直す必要があります。subject の apiGroup は User/Group のとき rbac.authorization.k8s.io で、ServiceAccount のときは空文字列 ("") だという違いも、試験でよく引っかかります。

ClusterRole を RoleBinding で (再利用 + 範囲限定) #

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole         # 一度定義して複数 ns で再利用
metadata:
  name: deployment-reader
rules:
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding         # ClusterRole を dev ns だけに限定して付与
metadata:
  namespace: dev
  name: deploy-reader-bind
subjects:
  - kind: ServiceAccount
    name: ci-bot
    namespace: dev
roleRef:
  kind: ClusterRole       # roleRef.kind が ClusterRole
  name: deployment-reader
  apiGroup: rbac.authorization.k8s.io

roleRef.kindClusterRole でも、RoleBinding で束ねたため、ci-bot ServiceAccount は dev ネームスペースの Deployment だけ を読めます。同じ ClusterRole を prod ネームスペースの RoleBinding でも指せば、そちらの subject は prod の Deployment だけを読みます。権限の束は 1 つ、適用範囲はネームスペース別に分離されるパターンです。

試験ポイント #

  • 加算モデル。RBAC には拒否ルールがありません。許可が 1 つもなければ拒否であり、許可ルールは積み上がります。
  • 4 つのオブジェクトの組み合わせ表を覚える。特に ClusterRole + RoleBinding (再利用 + ns 限定) と Role + ClusterRoleBinding は不可能 を区別します。
  • 非ネームスペースリソース (Node、PV、Namespace など) は ClusterRole でのみ 権限を与えられます。Role で作ると間違いです。
  • apiGroups。core リソースは ""、Deployment は apps、Job は batch、Ingress・NetworkPolicy は networking.k8s.io です。
  • generator を手に馴染ませるk create role/clusterrole--verb--resourcek create rolebinding/clusterrolebinding--role/--clusterrole--user/--group/--serviceaccount
  • --serviceaccount=ns:name 形式と、impersonation の --as=system:serviceaccount:ns:sa 形式を区別します。
  • 検証は auth can-i--as--as-group--list で作業直後に正解を確認します。
  • roleRef は不変。対象を変えるにはバインディングを作り直します。
  • subject の apiGroup。User/Group は rbac.authorization.k8s.io、ServiceAccount は ""

まとめ #

この記事で押さえたこと:

  • RBAC は認証の次の認可。apiserver は認証 → 認可 → admission の順でリクエストを検査し、RBAC が 2 番目の関門を担います。
  • 4 つのオブジェクト。Role/ClusterRole が権限の束を、RoleBinding/ClusterRoleBinding がその束を subject に接続します。
  • rules は apiGroups/resources/verbssubjects は User/Group/ServiceAccount の 3 種類です。
  • 組み合わせ規則。ClusterRole を RoleBinding で束ねると権限を再利用しながらネームスペースに限定でき、非ネームスペースリソースは ClusterRole でのみ扱います。
  • ServiceAccount でアプリに最小権限 を与え、#8 の証明書ユーザーには RBAC で権限を付けて作業を完成させます。
  • auth can-i --as で検証する 習慣が、試験で点数を守ります。

RBAC の基礎は K8s 中級トラックの #7 RBAC / NetworkPolicy / ResourceQuota で NetworkPolicy・ResourceQuota とともにマルチテナントの視点でも整理してあるので、権限・トラフィック・リソースの 3 つのポリシーを一つに束ねて見たいなら、合わせて読んでおくとよいです。

次へ — Workloads 1 #

#2 からここまで Cluster Architecture ドメインを締めくくりました。control plane の構造、構築、HA、アップグレード、etcd バックアップ、証明書、そして今回の RBAC まで、クラスター自体を立てて守る仕事を扱いました。

#10 Workloads 1 からは、クラスターの上で回るワークロードに入ります。Deployment の動作原理を ReplicaSet とともに深く見て、rolling update がどう進むのか、問題が起きたときどう rollback するのかを運用者の視点から整理します。

X