Rủi ro từ những Container chạy quyền Root
Sau hơn 6 tháng vận hành hệ thống Kubernetes (K8s) trên môi trường Production, tôi nhận ra một lỗ hổng phổ biến. Theo báo cáo của RedHat, có đến 53% các sự cố bảo mật K8s bắt nguồn từ cấu hình sai (misconfiguration). Đa số không đến từ các cuộc tấn công phức tạp, mà do chúng ta quá nới lỏng quyền hạn cho Container.
Khi mới triển khai, nhiều kỹ sư thường thiết lập privileged: true để tránh lỗi Permission Denied phiền toái. Tuy nhiên, đây là kẽ hở cho kỹ thuật Container Breakout. Từ một Container bị chiếm quyền, kẻ tấn công có thể leo thang lên Node vật lý và kiểm soát toàn bộ Cluster. Để giải quyết vấn đề này, tôi đã áp dụng kết hợp Pod Security Standards (PSS) và Admission Controllers.
Lựa chọn công cụ bảo mật Pod phù hợp
Kể từ khi Pod Security Policies (PSP) bị loại bỏ hoàn toàn từ phiên bản 1.25, chúng ta có hai phương án thay thế chính. Mỗi cách tiếp cận đều có ưu và nhược điểm riêng tùy vào quy mô hệ thống.
1. Pod Security Admission (PSA) – Giải pháp tích hợp sẵn
PSA là tính năng mặc định trong Kubernetes từ bản 1.23+. Nó hoạt động dựa trên các bộ tiêu chuẩn PSS có sẵn.
- Ưu điểm: Triển khai cực nhanh, không tốn tài nguyên và chỉ cần gắn Label lên Namespace.
- Hạn chế: Chỉ có 3 mức độ cố định (Privileged, Baseline, Restricted). Bạn không thể tùy chỉnh các quy tắc riêng biệt theo nhu cầu đặc thù.
2. Admission Controllers (Kyverno hoặc OPA Gatekeeper)
Đây là các Webhook can thiệp trực tiếp vào quá trình tiếp nhận Request của API Server.
- Ưu điểm: Độ linh hoạt tuyệt đối. Bạn có thể ép buộc mọi Image phải đến từ Registry nội bộ hoặc kiểm tra tài nguyên (Resource Limit) trước khi khởi tạo.
- Hạn chế: Tăng độ trễ cho API Server (khoảng 10-20ms mỗi request). Bạn cũng cần quản lý thêm một thành phần trung gian trong Cluster.
Lời khuyên thực tế: Hãy dùng PSA làm lớp bảo vệ nền tảng (baseline), sau đó bổ sung Kyverno để xử lý các logic nghiệp vụ phức tạp.
Triển khai Pod Security Standards (PSS) thực tế
PSS chia bảo mật thành 3 cấp độ (Profiles). Trong các dự án thực tế, tôi thường áp dụng Baseline cho ứng dụng thông thường và Restricted cho các dịch vụ xử lý dữ liệu nhạy cảm.
Kích hoạt PSA cho Namespace
Giả sử bạn cần bảo vệ namespace production-apps. Thay vì sửa từng file YAML của ứng dụng, hãy gắn label trực tiếp cho namespace để ép thực thi chính sách:
# Áp dụng mức độ Restricted cho namespace
kubectl label --overwrite ns production-apps \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=v1.28
Sau khi lệnh này thực thi, API Server sẽ từ chối mọi yêu cầu tạo Pod vi phạm tiêu chuẩn bảo mật ngay lập tức.
Kiểm chứng: Thử nghiệm chặn Pod không an toàn
Tạo file bad-pod.yaml với cấu hình chạy quyền cao (privileged):
apiVersion: v1
kind: Pod
metadata:
name: root-pod
namespace: production-apps
spec:
containers:
- name: nginx
image: nginx
securityContext:
privileged: true # Vi phạm mức Restricted
Khi chạy kubectl apply, hệ thống sẽ trả về lỗi chi tiết. Cơ chế này buộc các đội phát triển phải chuẩn hóa cấu hình bảo mật ngay từ bước triển khai đầu tiên.
Tối ưu bảo mật với Kyverno
PSA đôi khi quá cứng nhắc. Có những trường hợp ứng dụng cần một vài quyền đặc biệt nhưng vẫn phải chặn các rủi ro khác. Đây là lúc Kyverno phát huy tác dụng.
Tôi chọn Kyverno vì nó sử dụng định dạng YAML quen thuộc. Điều này giúp đội ngũ DevOps dễ dàng quản lý chính sách dưới dạng mã nguồn (Policy as Code) mà không cần học ngôn ngữ Rego phức tạp của OPA.
Chính sách bắt buộc dùng Read-Only Root Filesystem
Việc ép Root Filesystem sang chế độ read-only giúp ngăn chặn hacker ghi đè các file thực thi. Dưới đây là Policy thực tế tôi thường áp dụng:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: enforce-read-only-root-fs
spec:
validationFailureAction: Enforce
background: true
rules:
- name: check-read-only-root-fs
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Yêu cầu set readOnlyRootFilesystem: true để đảm bảo an toàn!"
pattern:
spec:
containers:
- securityContext:
readOnlyRootFilesystem: true
Chiến lược triển khai: Tránh gây gián đoạn hệ thống
Sai lầm lớn nhất là bật chế độ Enforce ngay lập tức trên Cluster đang hoạt động. Điều này có thể khiến hàng loạt Pod bị xóa và không thể khởi động lại, dẫn đến downtime.
Quy trình 4 bước an toàn:
- Chế độ Audit/Warn: Sử dụng label
warn=restrictedđể ghi nhận vi phạm mà không chặn Pod. - Phân tích Log: Theo dõi log từ Kyverno hoặc PSA để xác định các ứng dụng chưa đạt chuẩn.
- Chuẩn hóa cấu hình: Cập nhật
securityContexttrong Helm Chart hoặc Deployment của các team. - Thực thi (Enforce): Chỉ chuyển sang mode chặn hoàn toàn khi mọi ứng dụng đã tuân thủ.
Mẫu SecurityContext chuẩn cho Pod an toàn
Dưới đây là cấu hình Pod tối ưu mà tôi thường sử dụng cho các dự án thực tế:
spec:
securityContext:
runAsNonRoot: true # Chặn user root (UID 0)
runAsUser: 1000 # Chạy với user ID cụ thể
fsGroup: 2000
containers:
- name: my-app
image: my-app:v1.0.0
securityContext:
allowPrivilegeEscalation: false # Chặn leo thang quyền
capabilities:
drop: ["ALL"] # Loại bỏ mọi quyền Linux không cần thiết
readOnlyRootFilesystem: true # Hệ thống file chỉ đọc
Kết luận
Bảo mật Kubernetes là một quá trình liên tục. Việc kết hợp Pod Security Standards để xây dựng nền tảng và Admission Controllers để tinh chỉnh chi tiết sẽ tạo nên lớp giáp vững chắc.
Hãy kiểm tra lại các Namespace của bạn ngay hôm nay. Nếu mọi thứ vẫn đang chạy với quyền Privileged, đó là một quả bom hẹn giờ. Chúc các bạn xây dựng được hệ thống K8s an toàn và tin cậy!

