Sổ tay kỹ thuật

Kubernetes RBAC – ServiceAccount, Role, RoleBinding

how-to#kubernetes#kubectl#security· cập nhật 2026-11-06

Dùng khi cần cấp quyền tối thiểu cho ServiceAccount (CI, operator, app gọi API) hoặc người dùng, và kiểm tra quyền bằng kubectl auth can-i.

Sửa trang này
Mục lục

Tóm tắt: Quyền = ai (User, Group, ServiceAccount) + được làm gì (Role/ClusterRole: apiGroups + resources + verbs) + ở đâu (RoleBinding: một namespace; ClusterRoleBinding: toàn cluster). RBAC chỉ có allow, không có deny. Luôn kiểm tra lại bằng kubectl auth can-i --as=....

Luồng hoạt động

flowchart LR SA["ServiceAccount ci-deploy (ns app)"] --> RB["RoleBinding (ns app)"] RB -->|roleRef| R["Role deployer (ns app)"] RB -->|"roleRef (tái dùng)"| CR["ClusterRole view"] U["User / Group"] --> CRB["ClusterRoleBinding"] CRB --> CR2["ClusterRole (toàn cluster)"]
Kết hợp Phạm vi hiệu lực
Role + RoleBinding Trong namespace của chúng
ClusterRole + RoleBinding Quyền của ClusterRole nhưng chỉ trong namespace của RoleBinding (cách tái dùng phổ biến)
ClusterRole + ClusterRoleBinding Mọi namespace và resource cấp cluster (node, PV, namespace)

ClusterRole có sẵn hay dùng: view (đọc, trừ Secret), edit (đọc/ghi hầu hết, không sửa RBAC), admin (toàn quyền trong namespace, kể cả RBAC), cluster-admin (mọi thứ).

Cấu hình

ServiceAccount cho CI deploy trong một namespace

rbac-ci.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: ci-deploy
  namespace: app
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployer
  namespace: app
rules:
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
  - apiGroups: [""]                 # "" = core group: pods, services, configmaps, secrets
    resources: ["services", "configmaps"]
    verbs: ["get", "list", "create", "update", "patch"]
  - apiGroups: [""]
    resources: ["pods", "pods/log"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ci-deploy-deployer
  namespace: app
subjects:
  - kind: ServiceAccount
    name: ci-deploy
    namespace: app
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: deployer

Cùng mục đích bằng lệnh (thêm --dry-run=client -o yaml để sinh manifest):

kubectl create serviceaccount ci-deploy -n app
kubectl create role deployer -n app --verb=get,list,watch,create,update,patch --resource=deployments.apps
kubectl create rolebinding ci-deploy-deployer -n app --role=deployer --serviceaccount=app:ci-deploy
 
# Cho nhóm người dùng quyền đọc namespace app bằng ClusterRole có sẵn
kubectl create rolebinding netops-view -n app --clusterrole=view --group=netops

Verb và resource cần nhớ

Thao tác Quyền cần có
kubectl get/describe get, list (thêm watch cho -w)
kubectl apply get, create, patch (thêm update nếu dùng replace)
kubectl logs get trên pods/log
kubectl exec create trên pods/exec (client mới dùng WebSocket có thể cần thêm get)
kubectl port-forward create trên pods/portforward
kubectl scale patch/update trên deployments/scale
Đọc Secret get trên secrets (list/watch cũng đọc được nội dung)

resourceNames: ["api"] giới hạn rule vào object cụ thể. Không giới hạn được create (tên chưa tồn tại lúc kiểm tra); list/watch chỉ khớp khi client lọc theo metadata.name.

Token và kubeconfig cho ServiceAccount

# Token ngắn hạn (TokenRequest API), mặc định 1 giờ
TOKEN=$(kubectl create token ci-deploy -n app --duration=1h)
 
# Kubeconfig riêng cho CI
kubectl config set-cluster prod --server=https://k8s.example.com:6443 \
  --certificate-authority=ca.crt --embed-certs=true --kubeconfig=ci.kubeconfig
kubectl config set-credentials ci-deploy --token="$TOKEN" --kubeconfig=ci.kubeconfig
kubectl config set-context ci --cluster=prod --user=ci-deploy --namespace=app --kubeconfig=ci.kubeconfig
kubectl config use-context ci --kubeconfig=ci.kubeconfig

Từ Kubernetes 1.24 ServiceAccount không còn tự có Secret token dài hạn. Nếu bắt buộc cần token không hết hạn (hệ thống ngoài không làm mới được), tạo Secret type: kubernetes.io/service-account-token với annotation kubernetes.io/service-account.name: ci-deploy, và coi nó như mật khẩu.

Pod không cần gọi API thì đặt automountServiceAccountToken: false trong Pod spec hoặc ServiceAccount.

Kiểm tra quyền

kubectl auth can-i create deployments -n app --as=system:serviceaccount:app:ci-deploy   # yes/no
kubectl auth can-i delete secrets -n app --as=system:serviceaccount:app:ci-deploy
kubectl auth can-i --list -n app --as=system:serviceaccount:app:ci-deploy
kubectl auth can-i get pods --as=alice --as-group=netops -n app
kubectl auth whoami                                    # user và group hiện tại
 
# Ai đang được bind vào ClusterRole cluster-admin
kubectl get clusterrolebindings -o json | jq -r '.items[] | select(.roleRef.name=="cluster-admin") | .metadata.name + ": " + ([.subjects[]? | .kind + "/" + .name] | join(", "))'

Lỗi thường gặp

Triệu chứng Nguyên nhân Cách xử lý
Forbidden: User "system:serviceaccount:app:ci-deploy" cannot list resource "deployments" in API group "apps" Thiếu rule hoặc sai apiGroups Đọc kỹ resource và API group trong thông báo, thêm vào Role
Rule có deployments trong apiGroups: [""] mà vẫn Forbidden Deployment thuộc group apps, không phải core kubectl api-resources | grep deployments để xem group
RoleBinding tạo xong nhưng không có tác dụng Subject ServiceAccount sai namespace, hoặc Binding ở namespace khác kubectl describe rolebinding <rb> -n app
Sửa roleRef của binding bị lỗi roleRef là immutable Xoá binding và tạo lại
can-i trả yes nhưng CI vẫn lỗi CI dùng kubeconfig/context khác kubectl auth whoami trong job CI
Không tạo được Role chứa quyền mình chưa có Chống leo thang quyền (escalation prevention) Người tạo phải có đủ quyền đó, hoặc có verb escalate/bind
Token báo Unauthorized sau một thời gian Token từ kubectl create token hết hạn Tạo lại, hoặc dùng projected token trong Pod (tự làm mới)

Tham khảo