0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kubernetes⑤(全7回)|kind|Namespace / RBAC — マルチテナントと権限設計

0
Last updated at Posted at 2026-02-18

シリーズ記事一覧

📑 目次

  1. この記事について
  2. この記事のゴール
  3. 前提条件
  4. Docker Composeではこうだった(Before)
  5. k8sではこうなる(After)
  6. ハンズオン:Namespaceで分離し、RBACで制御する
  7. つまずきポイント(体験談)
  8. まとめ
  9. 次回予告

1. この記事について

ここまでで、Pod(第2回)、Service(第3回)、ConfigMap/Secret(第4回)と、k8sの主要リソースを一通り触りました。

ところで、これまでのハンズオンでは全てのリソースを default という名前の空間に作っていました。

実務でこれをやるとどうなるか?

🍽️ チェーンレストランの全店舗が「同じ厨房」を共有している状態です。

  • A店のスタッフがB店のレシピ帳(Secret)を勝手に見れる
  • 開発中の新メニュー(dev環境)が営業中のメニュー(prod環境)と混在する
  • 新人アルバイトが本番の食材を廃棄してしまう(権限がない操作をしてしまう)

今回は「空間を分ける」と「権限を制御する」— k8sのセキュリティの基本に取り組んでみました。


2. この記事のゴール

この記事で書いていること:

  • Namespaceで分離する理由
  • Namespace間のリソース分離を実際に試した話
  • RBAC の3要素(Role / RoleBinding / ServiceAccount)の関係の整理
  • 「読み取りのみ」権限を付与してテストしてみた話

3. 前提条件

項目 要件
前回の完了 第4回でConfigMap/Secret/Volumeを理解済み
クラスタ状態 kindクラスタが起動中
# WSL2 Ubuntu で実行

kubectl get nodes

4. Docker Composeではこうだった(Before)

4-1. Docker Composeの「空間」

Docker Composeでは、基本的に全てのコンテナが同じネットワーク・同じ空間で動きます。

# docker-compose.yml

services:
  api:
    image: myapp:latest
  db:
    image: postgres:14
  redis:
    image: redis:7

環境を分けたい場合は、ファイルを分けるくらい。

# 開発環境
docker-compose -f docker-compose.dev.yml up

# 本番環境
docker-compose -f docker-compose.prod.yml up

4-2. でもこの壁がある

Docker Composeでは、チーム開発や本番運用で以下の限界にぶつかります。

# Docker Composeの現実
壁1 環境の分離がファイル単位 dev/staging/prodが混在しがち
壁2 アクセス制御がない docker-compose コマンドを打てる人は全操作可能
壁3 リソース制限がない 1つのコンテナがメモリを食い尽くすことも

🔰 Memo: 個人開発ではこれで十分だと思います。
問題は「チームで使う」「本番環境を運用する」ときに出てきます。


5. k8sではこうなる(After)

5-1. Namespaceで論理分離

🍽️ 比喩:商業ビルのフロア分け

Namespaceは、1つのk8sクラスタ(ビル)の中に「フロア」を作る仕組みです。

フロア Namespace 中身
1F production 本番のPod、Service、Secret
2F staging ステージングのPod、Service、Secret
3F development 開発中のPod、Service、Secret
管理事務所 kube-system k8sの管理用Pod(API Server等)

各フロアのリソースは独立しています。
1Fの app-secret と 3Fの app-secret は別物です。

5-1-1. デフォルトで存在するNamespace

kubectl get namespaces
Namespace 用途
default ユーザーリソースのデフォルト配置先
kube-system k8sの管理コンポーネント
kube-public 全ユーザーに公開される情報
kube-node-lease ノードの死活監視

🔰 Memo: これまでのハンズオンでは全て default に作っていました。
実務では用途ごとにNamespaceを分けるのが基本だそうです。

5-2. RBACで権限制御

Namespaceで環境を分離しただけでは、誰でもどのNamespaceにもアクセスできてしまいます。
そこで必要になるのがRBAC(Role-Based Access Control) ― 役割ベースのアクセス制御です。

🍽️ 比喩:入館証システム

Namespaceでフロアを分けても、誰でも入れたら意味がありません。
RBACは「誰がどのフロアで何ができるか」を制御する入館証システムです。

RBACは3つの要素で構成されます。

要素 比喩 役割
ServiceAccount スタッフID 「誰が」を識別する(Pod用の身分証明書)
Role 権限定義書 「何ができるか」を定義する
RoleBinding 入館証の発行 ServiceAccountにRoleを紐づける

5-3. Role vs ClusterRole

種類 スコープ 比喩 用途
Role 特定のNamespace内 「1Fだけで使える入館証」 特定環境の権限管理
ClusterRole クラスタ全体 「全フロア使えるマスターキー」 管理者やクラスタ全体の権限

同様に RoleBindingClusterRoleBinding があります。

まず、1つのNamespace内でどう動くかを見てみましょう:

基本パターン(1つのNamespace内):

これが複数のNamespaceに展開されると、以下のような全体像になります:

全体像(複数Namespace + ClusterRole):

🍽️ productionフロアの viewer は「メニュー(Pod)を見る」だけ。
developmentフロアの developer は「新メニューを作る」もOK。
admin はマスターキーで全フロアに入れる。

5-4. 権限チェックの流れ


6. ハンズオン:Namespaceで分離し、RBACで制御する

6-1. 作業ディレクトリ

# WSL2 Ubuntu で実行

mkdir -p ~/k8s-handson/namespace-rbac
cd ~/k8s-handson/namespace-rbac

6-2. Step1:Namespaceを作ってリソースを分離

6-2-1. 2つのNamespaceを作成

# ~/k8s-handson/namespace-rbac/ で実行

# production 用のNamespace
kubectl create namespace production

# development 用のNamespace
kubectl create namespace development

# 確認
kubectl get namespaces

期待される出力:

NAME              STATUS   AGE
default           Active   ...
development       Active   5s
kube-node-lease   Active   ...
kube-public       Active   ...
kube-system       Active   ...
production        Active   5s

6-2-2. 各Namespaceにリソースを配置

📂 namespace-rbac/
├── prod-deployment.yaml           ← Step 1 🆕
└── dev-deployment.yaml            ← Step 1 🆕
# prod-deployment.yaml
# production 用のDeployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: production         # ← Namespace を指定
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.25     # 本番は安定バージョン
          ports:
            - containerPort: 80
# dev-deployment.yaml
# development 用のDeployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  namespace: development        # ← Namespace を指定
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:latest   # 開発は最新バージョン
          ports:
            - containerPort: 80
項目 prod-deployment dev-deployment 違いの理由
namespace production development 環境ごとにリソースを分離
replicas 2 1 本番は冗長化、開発は1つで十分
image nginx:1.25(固定) nginx:latest(最新) 本番は安定版、開発は最新機能を試す
name web-app web-app 同じ名前でOK(Namespaceが異なるため衝突しない)

Namespace = 「フロアの仕切り」
同じビル(クラスタ)内でも、フロア(Namespace)が違えば同じ部屋番号(リソース名)を使えます。
namespace: フィールドを指定しないと default Namespace に作成されます。

🔰 Note: 両方とも name: web-app にしています。
Docker Composeなら名前が衝突しますが、k8sではNamespaceが違えば同じ名前のリソースを作れるんですね。

# ~/k8s-handson/namespace-rbac/ で実行

# 両方を適用
kubectl apply -f prod-deployment.yaml
kubectl apply -f dev-deployment.yaml

6-3. Step2:Namespace間の分離を確認

# production のPodを確認
kubectl get pods -n production

期待される出力:

NAME                       READY   STATUS    RESTARTS   AGE
web-app-xxxxxxxxx-xxxxx   1/1     Running   0          10s
web-app-xxxxxxxxx-yyyyy   1/1     Running   0          10s
# development のPodを確認
kubectl get pods -n development

期待される出力:

NAME                       READY   STATUS    RESTARTS   AGE
web-app-xxxxxxxxx-zzzzz   1/1     Running   0          10s
# default のPodを確認(何もないはず)
kubectl get pods -n default

期待される出力:

No resources found in default namespace.

同じ名前のDeploymentが、別々のNamespaceで独立して動いています。

🍽️ 1F(production)には2人のスタッフ、2F(development)には1人。
お互いのフロアには干渉しません。

6-3-1. 全Namespaceを横断して見る

# 全NamespaceのPodを一覧
kubectl get pods --all-namespaces

管理者は --all-namespaces(または -A)で全フロアを俯瞰できます。
ビルの警備室のモニターのようなものです。


6-4. Step3:RBAC — 読み取り専用ユーザーを作成

Step1〜2でNamespaceの分離を体験しました。
ここからはRBACで**「見るだけで変更はできない」権限**を作ります。実務で最もよく使うパターンです。

6-4-1. 3つのファイルを作成

📂 namespace-rbac/
├── prod-deployment.yaml           ✅ Step 1
├── dev-deployment.yaml            ✅ Step 1
├── serviceaccount.yaml            ← Step 3 🆕
├── role-readonly.yaml             ← Step 3 🆕
└── rolebinding-readonly.yaml      ← Step 3 🆕

6-4-2. ① ServiceAccount(スタッフID)

# serviceaccount.yaml
# ServiceAccount = Podの身分証明書

apiVersion: v1
kind: ServiceAccount
metadata:
  name: prod-viewer              # この名前がスタッフID
  namespace: production          # production に所属

6-4-3. ② Role(権限定義書)

# role-readonly.yaml
# Role = 「何ができるか」の定義

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader               # ロール名
  namespace: production          # このNamespace内でのみ有効
rules:
  # Pod に対する権限
  - apiGroups: [""]              # コアAPI(Pod, Service等)
    resources: ["pods"]          # 対象リソース
    verbs: ["get", "list", "watch"]   # 許可する操作(読み取りのみ)

  # Service に対する権限
  - apiGroups: [""]
    resources: ["services"]
    verbs: ["get", "list"]

6-4-4. Role の読み方

YAMLの項目 比喩 意味
apiGroups: [""] 「基本メニュー(Pod等)について」 コアAPIグループ
resources: ["pods"] 「Podという料理について」 対象リソースの種類
verbs: ["get", "list", "watch"] 「見る・一覧する・監視する、はOK」 許可する操作

🍽️ この権限定義書は「1Fのメニュー(Pod)とレジ表(Service)は見ていいけど、新メニュー作成(create)や廃棄(delete)はダメ」という内容です。

6-4-5. 主なverbs一覧

verb 意味 比喩
get 1つ取得 特定の料理を確認する
list 一覧取得 メニュー一覧を見る
watch 変更を監視 オーダー状況をリアルタイムで見る
create 作成 新メニューを追加する
update 更新 メニューの内容を変更する
delete 削除 メニューから外す

6-4-6. ③ RoleBinding(入館証の発行)

# rolebinding-readonly.yaml
# RoleBinding = ServiceAccountにRoleを紐づける

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: prod-viewer-binding      # バインディング名
  namespace: production
subjects:
  # 誰に(ServiceAccount)
  - kind: ServiceAccount
    name: prod-viewer            # ← serviceaccount.yaml の name と一致
    namespace: production
roleRef:
  # 何の権限を(Role)
  kind: Role
  name: pod-reader               # ← role-readonly.yaml の name と一致
  apiGroup: rbac.authorization.k8s.io

🍽️ 「prod-viewer さん(ServiceAccount)に、pod-reader という入館証(Role)を発行します」という申請書(RoleBinding)です。

6-4-7. 適用

# ~/k8s-handson/namespace-rbac/ で実行

kubectl apply -f serviceaccount.yaml
kubectl apply -f role-readonly.yaml
kubectl apply -f rolebinding-readonly.yaml

# 確認
kubectl get serviceaccount -n production
kubectl get role -n production
kubectl get rolebinding -n production

期待される出力(serviceaccount):

NAME          SECRETS   AGE
default       0         ...
prod-viewer   0         5s

6-5. Step4:権限テスト — できること・できないこと

6-5-1. kubectl auth can-i で権限を確認

# prod-viewer は production で pods を get できる?
kubectl auth can-i get pods \
  --namespace production \
  --as system:serviceaccount:production:prod-viewer

期待される出力:

yes
# prod-viewer は production で pods を delete できる?
kubectl auth can-i delete pods \
  --namespace production \
  --as system:serviceaccount:production:prod-viewer

期待される出力:

no
# prod-viewer は development で pods を get できる?
kubectl auth can-i get pods \
  --namespace development \
  --as system:serviceaccount:production:prod-viewer

期待される出力:

no

RBAC が効いています。

6-5-2. 結果まとめ

操作 Namespace 結果 理由
get pods production ✅ yes Role で get を許可
list pods production ✅ yes Role で list を許可
delete pods production ❌ no Role に delete がない
get secrets production ❌ no Role に secrets がない
get pods development ❌ no Role は production 限定

🍽️ 1F(production)の入館証で、1Fのメニュー(Pod)は見られる。
でも、レシピ帳(Secret)は見られないし、2F(development)には入れない。
削除(廃棄)もできない。

6-5-3. 実際にPodとして使ってみる

# prod-viewer の ServiceAccount でPodを起動し、内部からAPIを叩く
kubectl run rbac-test \
  --image=bitnami/kubectl \
  --namespace production \
  --serviceaccount=prod-viewer \
  --rm -it --restart=Never \
  -- kubectl get pods -n production

期待される出力:

NAME                       READY   STATUS    RESTARTS   AGE
web-app-xxxxxxxxx-xxxxx   1/1     Running   0          5m
web-app-xxxxxxxxx-yyyyy   1/1     Running   0          5m
# 同じSAで delete を試みる
kubectl run rbac-test2 \
  --image=bitnami/kubectl \
  --namespace production \
  --serviceaccount=prod-viewer \
  --rm -it --restart=Never \
  -- kubectl delete pod web-app-xxxxxxxxx-xxxxx -n production

期待される出力:

Error from server (Forbidden): pods "web-app-xxxxxxxxx-xxxxx" is forbidden: User "system:serviceaccount:production:prod-viewer" cannot delete resource "pods" in API group "" in the namespace "production"

Forbidden(禁止)が返されました。
RBACによるアクセス制御がちゃんと機能しているのを確認できました。


6-6. 後片付け

# リソースの削除
kubectl delete namespace production
kubectl delete namespace development

# Namespaceを削除すると、中のリソースも全て削除される
kubectl get namespaces

🔰 Note: Namespaceを削除すると、そのNamespace内のDeployment、Pod、Service、ConfigMap、Secret、Role、RoleBinding... 全てが消えます
本番では絶対に慎重にやらないといけないですね。


7. つまずきポイント(体験談)

7-1. -n フラグの付け忘れ

症状: kubectl get pods で何も出ない → default Namespace を見ていた。

対策: 常に -n <namespace> を付ける習慣をつける。

# よく使うNamespaceをデフォルトに変更
kubectl config set-context \
  --current \
  --namespace=production

# 確認
kubectl config view --minify | grep namespace

これで -n production を省略できます。

7-2. RoleBinding の subjects.name の不一致

症状:

Error from server (Forbidden): ...

権限を設定したはずなのに拒否される。

対策: 3つのリソースの名前の紐づきを確認。

# ServiceAccount名を確認
kubectl get sa -n production

# Roleの内容を確認
kubectl describe role pod-reader -n production

# RoleBindingの紐づきを確認
kubectl describe rolebinding prod-viewer-binding -n production

🍽️ 入館証(RoleBinding)に書かれた名前と、実際のスタッフID(ServiceAccount名)が違ったら、ゲートを通れません。

7-3. Role と ClusterRole の混同

間違い 結果
RoleBinding で ClusterRole を参照 動く(そのNamespace内でClusterRoleの権限が適用される)
ClusterRoleBinding で Role を参照 エラー(ClusterRoleBindingはClusterRoleしか参照できない)

🔰 Memo: 迷ったら「まずNamespace内のRoleから始める」のが安全だと感じました。
ClusterRoleは管理者向けの上級機能です。


8. まとめ

8-1. この記事でやったこと

# 内容 状態
1 Namespaceで論理的にリソースを分離した
2 同名リソースが別Namespaceで共存できることを確認した
3 RBAC(ServiceAccount + Role + RoleBinding)を構築した
4 権限テスト(できること/できないこと)を確認した

8-2. RBAC の3要素(まとめ表)

要素 比喩 定義する内容 スコープ
ServiceAccount スタッフID 「誰が」 Namespace
Role 権限定義書 「何ができるか」 Namespace
RoleBinding 入館証の発行 「誰に何の権限を」 Namespace
ClusterRole 全フロア共通権限 「何ができるか」 クラスタ全体
ClusterRoleBinding マスターキー発行 「誰に何の権限を」 クラスタ全体

8-3. Docker Compose → k8s 対応表

Docker Compose Kubernetes 備考
ファイルで環境を分離 Namespace k8sは1クラスタ内で論理分離
(該当なし) RBAC Docker Composeには権限管理がない
(該当なし) ServiceAccount Pod単位の身分証明
全員がdocker-compose操作可能 Role + RoleBinding 操作ごとに許可/拒否を制御

8-4. 第4回との繋がり:Secretの安全性

前回「base64は暗号化ではない」と書きました。
Secretの安全性はRBACで担保するのが正解です。

# Secretを読めないRole
rules:
  - apiGroups: [""]
    resources: ["pods"]       # Podだけ許可
    verbs: ["get", "list"]
    # ← secrets は含めない = Secretにアクセスできない

🍽️ レシピ帳(Secret)は金庫に入れるだけでは不十分。
「金庫の鍵を持てるのは誰か」(RBAC)まで設定して初めて安全。


9. 次回予告

第6回:運用 — ログ・監視・トラブルシュート

環境分離も権限制御もできました。
でも、実務で最も時間を使うのは運用です。

🍽️ レストランを開店するより、毎日の営業(トラブル対応・品質管理)の方がずっと大変。

次回は:

  • kubectl logs / kubectl describe / kubectl exec の使い分け
  • 「Podが起動しない!」のトラブルシュート手順
  • リソース使用量の確認方法
  • 実務でよく使う kubectl コマンド集

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?