Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 41 — RBAC & IAM trong Kubernetes

Đã đọc 0/15 mục · còn khoảng 11 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn vừa nhận việc DevOps tại một công ty fintech ở Sài Gòn. Cluster Kubernetes production đang chạy 40 microservice, có 25 kỹ sư truy cập, thêm 3 hệ thống CI/CD tự động deploy. Một buổi sáng, một bạn intern chạy nhầm lệnh kubectl delete namespace payment và toàn bộ dịch vụ thanh toán biến mất trong 30 giây. Điều tra ra thì… mọi người trong công ty đều dùng chung một tài khoản cluster-admin. Không ai biết ai đã làm gì, và ai cũng có quyền xóa mọi thứ.

Đây không phải chuyện giả tưởng — đây là kịch bản kinh điển khi một team chưa hiểu về RBAC (Role-Based Access Control) và IAM (Identity and Access Management) trong Kubernetes. Kubernetes mặc định rất "mở": nếu bạn không thiết lập phân quyền cẩn thận, một token bị lộ hoặc một pod bị hack có thể trở thành cửa ngõ chiếm toàn bộ cluster.

Bài học này sẽ giúp bạn trả lời ba câu hỏi cốt lõi mà mọi DevOps Engineer đều phải nắm: Ai (identity) được phép làm gì (permission) trên tài nguyên nào (resource). Nắm vững nó, bạn không chỉ tránh được thảm họa như trên mà còn xây được nền tảng bảo mật đúng chuẩn "least privilege" — nguyên tắc tối thiểu đặc quyền — mà bất kỳ audit bảo mật nào (SOC2, PCI DSS) cũng yêu cầu.

Khái niệm cốt lõi

RBAC trong Kubernetes được xây trên bốn khối lego. Hiểu rõ bốn khối này, bạn ghép được mọi chính sách phân quyền.

Subject — Ai đang yêu cầu?

Subject là "chủ thể" thực hiện hành động. Kubernetes phân biệt ba loại:

  • User — con người, ví dụ bạn Khang, chị Lan. Điều thú vị là Kubernetes không tự quản lý user; nó không có bảng "users" trong database. Danh tính user đến từ bên ngoài: chứng chỉ TLS (client certificate), OIDC token (Google, Azure AD), hoặc do cloud provider cấp (AWS IAM, GCP IAM). Kubernetes chỉ tin vào những gì được xác thực từ các nguồn đó.
  • Group — nhóm user, ví dụ nhóm dev-team, sre. Group giúp bạn gán quyền cho cả tập thể thay vì từng người.
  • ServiceAccount — danh tính cho máy móc, tức là các pod, CI/CD pipeline, controller. Đây là loại subject duy nhất Kubernetes tự quản lý (là một object thật trong cluster, nằm trong một namespace).
Điểm mấu chốt cần nhớ: User/Group là identity của con người (do hệ thống ngoài quản lý), còn ServiceAccount là identity của phần mềm (do Kubernetes quản lý). Nhầm lẫn hai loại này là lỗi rất phổ biến của người mới.

Verb — Được làm gì?

Verb là hành động được phép thực hiện. Các verb thông dụng:

  • Đọc: get (lấy 1 object), list (liệt kê nhiều), watch (theo dõi thay đổi real-time).
  • Ghi: create, update, patch (sửa một phần), delete, deletecollection (xóa hàng loạt).
Một mẹo bảo mật: nhiều người chỉ nghĩ delete là nguy hiểm, nhưng list và watch trên Secret cũng cực kỳ nhạy cảm — vì nó cho phép đọc toàn bộ mật khẩu, token trong namespace.

Resource — Trên tài nguyên nào?

Resource là loại object bạn thao tác: pods, services, deployments, secrets, configmaps, nodes... Ngoài ra còn có subresource như pods/log (xem log), pods/exec (chui vào shell của pod). Bạn có thể cấp quyền xem log mà không cho quyền exec — rất hữu ích để giới hạn quyền của team support.

Role, ClusterRole, RoleBinding, ClusterRoleBinding

Đây là bốn object kết nối ba khái niệm trên lại với nhau:

  • Role: tập hợp quyền (verb + resource) trong phạm vi một namespace. Ví dụ: "được get/list pods trong namespace payment".
  • ClusterRole: tập hợp quyền ở phạm vi toàn cluster, hoặc dùng cho tài nguyên không thuộc namespace nào (như nodes, persistentvolumes).
  • RoleBinding: "dây nối" gán một Role (hoặc ClusterRole) cho subject trong một namespace cụ thể.
  • ClusterRoleBinding: gán một ClusterRole cho subject trên toàn bộ cluster.
Công thức dễ nhớ: Role/ClusterRole = định nghĩa quyền (làm được gì). Binding = trao quyền đó cho ai. Bản thân Role không có tác dụng gì nếu chưa có Binding — giống như bạn in một tấm thẻ ra vào nhưng chưa phát cho ai.

Một cặp đôi hay gây bối rối: bạn có thể dùng ClusterRole + RoleBinding. Nghĩa là định nghĩa quyền một lần ở cấp cluster (tái sử dụng), nhưng chỉ áp dụng trong phạm vi một namespace khi bind. Đây là pattern rất thực dụng để không phải copy-paste cùng một Role vào 20 namespace.

RBAC và IAM của cloud gặp nhau ở đâu?

Khi chạy trên EKS (AWS), GKE (Google), hay AKS (Azure), có hai lớp phân quyền chồng lên nhau:

  • Cloud IAM — kiểm soát ai được truy cập API của cloud (tạo cluster, thay đổi node group, đọc S3...).
  • Kubernetes RBAC — kiểm soát ai làm gì bên trong cluster.
Ví dụ trên EKS, một AWS IAM user/role phải được ánh xạ (map) sang Kubernetes user/group thông qua aws-auth ConfigMap (hoặc EKS Access Entries mới hơn), rồi RBAC mới quyết định quyền cụ thể bên trong. Hiểu ranh giới này giúp bạn debug lỗi "403 Forbidden" đúng chỗ: là lỗi IAM (chưa vào được cửa) hay RBAC (vào được nhưng không có quyền)?

Tình huống thực tế

Tình huống 1 — Startup e-commerce Việt Nam siết quyền sau sự cố

Một startup thương mại điện tử tại TP.HCM (khoảng 30 kỹ sư) ban đầu cho cả team quyền cluster-admin để "cho nhanh". Sau khi một kỹ sư vô tình scale nhầm deployment về 0 replica giữa giờ cao điểm sale 12/12 khiến website sập 18 phút, ban lãnh đạo yêu cầu chấn chỉnh.

Team DevOps thiết kế lại theo mô hình phân tầng: nhóm developers chỉ được get/list/watch pods, logs, deployments trong namespace của team mình, cộng quyền create/patch deployment (để deploy) nhưng không được đụng vào Secret và không được delete namespace. Nhóm sre có quyền rộng hơn trên toàn cluster nhưng vẫn không phải cluster-admin. Chỉ 2 người có quyền admin thật sự, và mọi thao tác admin đều phải qua một tài khoản riêng có ghi log.

Bài học: "cho nhanh" bằng cluster-admin là món nợ kỹ thuật đắt đỏ. Least privilege không làm chậm team nếu bạn thiết kế Role đúng theo nhu cầu thật (developer cần deploy, không cần đọc mật khẩu production).

Tình huống 2 — Pod bị hack và bài toán ServiceAccount mặc định

Một công ty SaaS ở Singapore chạy ứng dụng Node.js trên GKE. Một lỗ hổng trong thư viện npm cho phép kẻ tấn công chạy lệnh tùy ý bên trong pod. Điều khiến sự cố trở nên nghiêm trọng: pod đó dùng ServiceAccount default của namespace, và ai đó trước kia đã lỡ tay bind ServiceAccount default với ClusterRole edit. Kết quả: kẻ tấn công dùng token của pod (nằm sẵn ở /var/run/secrets/kubernetes.io/serviceaccount/token) để liệt kê Secret của các namespace khác.

Sau sự cố, team áp dụng ba biện pháp: (1) tạo ServiceAccount riêng cho mỗi ứng dụng với quyền tối thiểu, (2) đặt automountServiceAccountToken: false cho các pod không cần gọi API Kubernetes, (3) không bao giờ bind quyền cho ServiceAccount default.

Bài học: ServiceAccount là identity của phần mềm — nếu pod bị chiếm, quyền của ServiceAccount chính là quyền của kẻ tấn công. Một pod hiển thị website tĩnh thì không có lý do gì cần token truy cập Kubernetes API.

Tình huống 3 — CI/CD được cấp quyền quá rộng

Một team fintech dùng GitLab CI để deploy lên EKS. Pipeline dùng một ServiceAccount được gán ClusterRoleBinding tới cluster-admin cho tiện. Khi audit PCI DSS diễn ra, auditor đánh dấu đây là rủi ro nghiêm trọng: bất kỳ ai sửa được file .gitlab-ci.yml (kể cả qua merge request độc hại) đều có thể chạy lệnh với quyền admin toàn cluster.

Team thu hẹp lại: tạo ServiceAccount deployer chỉ có quyền create/update/patch trên deployments, services, configmaps trong đúng các namespace ứng dụng, dùng ClusterRole tái sử dụng bind bằng RoleBinding vào từng namespace. Pipeline production còn thêm bước phê duyệt thủ công.

Bài học: identity của tự động hóa (CI/CD) cần bị giới hạn còn chặt hơn con người, vì nó chạy không có người giám sát trực tiếp và là mục tiêu tấn công hấp dẫn.

Hướng dẫn từng bước

Hãy tạo một ServiceAccount cho ứng dụng chỉ được đọc pods và logs trong namespace payment.

Bước 1 — Tạo ServiceAccount:

kubectl create serviceaccount log-reader -n payment

Bước 2 — Định nghĩa Role (quyền đọc pods và logs):

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: payment
  name: pod-log-reader
rules:
- apiGroups: [""]            # "" là core API group
  resources: ["pods", "pods/log"]
  verbs: ["get", "list", "watch"]

Áp dụng: kubectl apply -f role.yaml

Bước 3 — Tạo RoleBinding gán Role cho ServiceAccount:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: bind-log-reader
  namespace: payment
subjects:
- kind: ServiceAccount
  name: log-reader
  namespace: payment
roleRef:
  kind: Role
  name: pod-log-reader
  apiGroup: rbac.authorization.k8s.io

Bước 4 — Kiểm tra quyền bằng kubectl auth can-i:

Đây là công cụ vàng để test RBAC mà không cần thử-và-lỗi:

# Kiểm tra quyền của chính bạn
kubectl auth can-i delete pods -n payment

# Kiểm tra quyền của ServiceAccount (giả lập identity)
kubectl auth can-i get pods -n payment \
  --as=system:serviceaccount:payment:log-reader
# → kết quả: yes

kubectl auth can-i delete pods -n payment \
  --as=system:serviceaccount:payment:log-reader
# → kết quả: no

Bước 5 — Gán ServiceAccount cho pod trong Deployment:

spec:
  template:
    spec:
      serviceAccountName: log-reader
      automountServiceAccountToken: true  # để false nếu pod không gọi K8s API

Với con người trên EKS, thay vì tạo Role cho ServiceAccount, bạn ánh xạ AWS IAM role vào Kubernetes group qua EKS Access Entries hoặc aws-auth ConfigMap, rồi bind group đó với Role/ClusterRole tương ứng.

Lỗi thường gặp & mẹo

  • Lạm dụng cluster-admin. Đây là lỗi số một. cluster-admin cấp toàn quyền, kể cả sửa chính RBAC. Chỉ dành cho vài người và tài khoản break-glass khẩn cấp.
  • Bind quyền cho ServiceAccount default. Mọi pod không chỉ định ServiceAccount đều dùng default. Gán quyền cho nó nghĩa là gán cho tất cả pod. Hãy luôn tạo ServiceAccount riêng.
  • Nhầm namespace của Role và Binding. Role trong namespace A không thể được bind để có tác dụng ở namespace B. Nếu thấy "yes/no" không như mong đợi, kiểm tra namespace trước tiên.
  • Wildcard trong resources/verbs. verbs: [""] hoặc resources: ["*"] tiện lúc viết nhưng phá vỡ least privilege. Liệt kê tường minh những gì thực sự cần.
  • Quên pods/log và pods/exec là subresource riêng. Cấp get pods không đồng nghĩa cho xem log. Phải khai báo pods/log riêng.
  • Không phân biệt lỗi IAM và lỗi RBAC trên cloud. Lỗi "Unauthorized" thường là IAM (chưa xác thực được), còn "Forbidden" là RBAC (đã xác thực nhưng thiếu quyền). Đọc kỹ thông báo lỗi tiết kiệm hàng giờ debug.
Mẹo hữu ích:

  • Dùng kubectl auth can-i --list --as=... để xem toàn bộ quyền của một identity.
  • Bắt đầu với quyền tối thiểu rồi mở rộng dần khi có lỗi Forbidden thực tế — dễ hơn nhiều so với cấp rộng rồi siết lại.
  • Ưu tiên ClusterRole tái sử dụng + RoleBinding theo namespace thay vì copy Role nhiều lần.
  • Định kỳ audit bằng các công cụ như kubectl-who-can, rbac-lookup hoặc rakkess để phát hiện quyền dư thừa.

Bài tập thực hành

  • Cơ bản: Tạo namespace staging, một ServiceAccount viewer, và một Role cho phép get/list/watch trên pods, services, deployments. Dùng kubectl auth can-i --as=... để chứng minh viewer không thể delete deployment.
  • Trung cấp: Tạo một ClusterRole namespace-deployer (quyền quản lý deployments, services, configmaps) và bind nó bằng RoleBinding vào hai namespace app-a và app-b cho cùng một group dev-team. Xác nhận group này không có quyền trong namespace payment.
  • Nâng cao: Mô phỏng tình huống 2 — tạo một pod dùng ServiceAccount riêng với automountServiceAccountToken: false. Exec vào pod và chứng minh rằng không còn file token tại /var/run/secrets/kubernetes.io/serviceaccount/. Sau đó bật lại token, bind ServiceAccount với quyền chỉ đọc ConfigMap, và thử kubectl get secrets từ bên trong pod để thấy nó bị từ chối.
  • Tư duy: Viết ra danh sách các Role bạn sẽ thiết kế cho một team 20 người gồm developer, SRE, và data analyst (chỉ cần xem log). Với mỗi nhóm, ghi rõ verb + resource + namespace được phép.

Tóm tắt

RBAC trong Kubernetes trả lời câu hỏi cốt lõi: ai (Subject) được làm gì (Verb) trên tài nguyên nào (Resource). Bốn object nền tảng là Role/ClusterRole (định nghĩa quyền) và RoleBinding/ClusterRoleBinding (trao quyền cho subject), với ranh giới quan trọng là phạm vi namespace hay toàn cluster.

Ba loại subject cần phân biệt rạch ròi: User và Group là identity của con người (do hệ thống ngoài quản lý), còn ServiceAccount là identity của phần mềm (do Kubernetes quản lý) — và chính ServiceAccount thường là điểm yếu bị bỏ quên. Trên cloud, RBAC còn chồng lên một lớp IAM riêng: IAM canh cửa vào cluster, RBAC canh quyền bên trong.

Nguyên tắc xuyên suốt là least privilege: cấp đúng những gì cần, không hơn. Tránh cluster-admin bừa bãi, không bind quyền cho ServiceAccount default, giới hạn CI/CD chặt hơn cả con người, và dùng kubectl auth can-i để kiểm chứng thay vì đoán. Làm chủ những nguyên tắc này, bạn biến cluster từ một quả bom hẹn giờ thành một hệ thống an toàn, có thể audit, và sẵn sàng cho mọi tiêu chuẩn compliance.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi