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
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: deployerCù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=netopsVerb 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.kubeconfigTừ 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) |