Run as Non-Root: Cách chạy pod/container với quyền người dùng non-root

Đã kiểm duyệt nội dung
Đánh giá
Run as Non-Root là một nguyên tắc bảo mật quan trọng trong môi trường container, hướng đến việc cấu hình để container hoặc Pod không chạy với quyền root mà sử dụng một user có đặc quyền hạn chế hơn. Bài viết này được mình đúc kết từ kinh nghiệm hơn 10 năm triển khai Docker và Kubernetes production cho nhiều hệ thống khác nhau, tập trung vào cách áp dụng non-root user trong Dockerfile, cấu hình securityContext chuẩn xác cùng các bước kiểm tra để đảm bảo tính ổn định của ứng dụng.
Những điểm chính
- Quan điểm của mình: Việc chuyển đổi hệ thống sang trạng thái Non-Root ban đầu có thể khiến bạn gặp phải một số lỗi “Permission denied” khó chịu. Tuy nhiên, đây là sự đánh đổi hoàn toàn bắt buộc và xứng đáng để bảo vệ hệ thống của doanh nghiệp khỏi các rủi ro leo thang đặc quyền nghiêm trọng.
- Lý do bảo mật: Hiểu rõ lợi ích của việc chạy Non-Root giúp bạn ngăn chặn nguy cơ leo thang đặc quyền và bảo vệ an toàn cho hệ thống máy chủ trước các rủi ro xâm nhập.
- Nguyên tắc vận hành: Nắm vững các quy tắc về đặc quyền tối thiểu và chỉ định ID cụ thể giúp người đọc cấu hình quyền truy cập chính xác, đảm bảo tính ổn định cho container và Pod.
- Chuẩn bị Image: Biết cách tạo user phi root và phân quyền thư mục ngay từ bước build image giúp ứng dụng khởi động mượt mà mà không cần đến đặc quyền quản trị cao nhất.
- Cách thức triển khai: Nắm được các phương pháp cấu hình SecurityContext trong Kubernetes và tham số User trong Docker Compose để ép hệ thống vận hành dưới quyền hạn chế một cách chuyên nghiệp.
- Kiểm tra xác minh: Biết cách sử dụng các lệnh thực thi để xác thực tiến trình đang chạy đúng user không phải root, giúp đảm bảo các chính sách an toàn thông tin đã được áp dụng thành công.
- Giới thiệu Vietnix: Biết đến Vietnix là nhà cung cấp Cloud Server mạnh mẽ, giúp bạn có một nền tảng hạ tầng đáng tin cậy để triển khai các giải pháp Kubernetes an toàn.
- Câu hỏi thường gặp: Giải đáp các thắc mắc liên quan đến Run as Non-Root.

Tại sao nên Run as Non-Root?
Run as Non-Root là cách cấu hình để container hoặc Pod không chạy với quyền root mà sử dụng một user thông thường có đặc quyền hạn chế hơn. Theo mặc định, nhiều container engine như Docker sẽ chạy các tiến trình bên trong container bằng quyền root. Tuy nhiên, việc duy trì trạng thái này trong môi trường thực tế tiềm ẩn nhiều rủi ro nghiêm trọng.
Bạn nên thiết lập run as non-root vì những lý do sau đây:
- Ngăn chặn leo thang đặc quyền: Nếu một tin tặc xâm nhập thành công vào ứng dụng đang chạy quyền root, chúng có thể dễ dàng khai thác các công cụ hệ thống để nâng quyền và thoát ra khỏi vùng cách ly của container. Việc chạy bằng user thông thường sẽ chặt đứt khả năng này.
- Bảo vệ hệ thống máy chủ: Container thực chất dùng chung nhân hệ điều hành với máy chủ vật lý. Do đó, nếu một tiến trình root trong container vô tình xóa hoặc ghi đè lên các tệp tin quan trọng được mount từ host vào, hệ thống máy chủ gốc sẽ bị hỏng hoàn toàn.
- Tuân thủ các tiêu chuẩn bảo mật: Hầu hết các chính sách bảo mật doanh nghiệp và tiêu chuẩn quốc tế (như CIS Benchmarks cho Docker/Kubernetes) đều bắt buộc ứng dụng không được phép chạy với quyền root để đạt chuẩn an toàn thông tin.
- Tương thích môi trường: Nhiều nền tảng như OpenShift mặc định chặn chạy root, do đó cấu hình non-root giúp app chạy ổn định mọi nơi.

Với Enterprise Cloud của Vietnix, doanh nghiệp không chỉ được trang bị một hạ tầng mạnh mẽ với CPU AMD EPYC và ổ cứng NVMe Enterprise, mà còn có toàn quyền quản trị và tự động hóa. Bạn có thể dễ dàng khởi tạo và quản lý hàng loạt Cloud Server, tích hợp liền mạch với các công cụ CI/CD và DevOps, đồng thời áp dụng các chính sách bảo mật như “run as non-root” một cách hiệu quả.
Nguyên tắc chạy container/pod với non-root user
Để việc thiết lập non-root diễn ra trơn tru và không gây lỗi cho ứng dụng, bạn cần tuân thủ nghiêm ngặt các nguyên tắc sau:
- Nguyên tắc đặc quyền tối thiểu: Bạn chỉ cấp phát quyền vừa đủ để ứng dụng có thể đọc, ghi và thực thi các tệp tin cần thiết, tuyệt đối không cấp quyền dư thừa.
- Sử dụng ID cụ thể: Hệ thống máy chủ thường nhận diện quyền thông qua các con số (UID/GID) thay vì tên người dùng. Do đó, bạn nên chỉ định rõ UID (ví dụ: 1000) thay vì chỉ dùng tên (như “appuser”) để tránh sự cố lệch quyền giữa container và máy chủ.
- Không sử dụng các cổng dưới 1024: Các hệ điều hành Linux yêu cầu quyền root để mở các cổng mạng từ 1 đến 1023 (như port 80 cho HTTP). Khi chạy bằng quyền non-root, bạn phải cấu hình ứng dụng lắng nghe ở các cổng cao hơn (ví dụ: 8080, 8443).
- Thiết lập quyền truy cập thư mục: Khi gắn ổ đĩa từ máy chủ vào container, bạn phải đảm bảo user non-root bên trong container có đủ quyền (read/write) đối với thư mục trên máy chủ gốc.

Hiểu sâu về User Namespace:
Thực chất, khi bạn áp dụng Run as Non-Root, bạn đang tận dụng cơ chế User Namespaces của Linux. Cơ chế này cho phép một tiến trình có thể là “root” bên trong một namespace cô lập nhưng lại chỉ là một user bình thường trên hệ thống Host. Bằng cách gán cứng một UID (ví dụ 10001) vào Container, ngay cả khi hacker thực thi được mã độc thì hệ điều hành Host vẫn chỉ nhìn nhận mã độc đó như một user cấp thấp vô hại, từ đó vô hiệu hóa hoàn toàn các lệnh phá hoại hệ thống.
Chuẩn bị container image để hỗ trợ non-root
Cấu hình user và phân quyền bên trong image
Để container có thể chạy với non-root user, image cần được tạo sẵn một user không phải root và gán UID/GID cụ thể cho user đó trong Dockerfile. Dockerfile thường bao gồm các bước tạo user/group, thiết lập thư mục làm việc và sử dụng lệnh USER <uid hoặc tên user> để chỉ định tiến trình chính trong container chạy dưới user này thay vì UID 0. Nếu image không được cấu hình như vậy, việc bật chính sách non-root từ Kubernetes bằng securityContext có thể khiến container khởi động thất bại do không tìm thấy user hoặc không đủ quyền thực thi.
# Tạo group và user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# Phân quyền thư mục cần thiết
RUN chown -R appuser:appgroup /app
# Chuyển sang user non-root
USER appuserLỗi thường gặp: Rất nhiều bạn đặt lệnh USER appuser lên trước lệnh RUN chown. Điều này sẽ gây lỗi ngay lập tức vì lúc này user non-root chưa có quyền thực thi lệnh chown (lệnh này đòi hỏi quyền root). Luôn nhớ: Phân quyền xong mới đổi User.
Điều chỉnh quyền thư mục, file cần ghi/đọc cho non-root user
Bên cạnh việc tạo non-root user, các thư mục và file mà tiến trình bên trong container cần đọc/ghi (ví dụ thư mục log, cache, dữ liệu tạm) phải được gán quyền sở hữu (owner/group) hoặc permission phù hợp với UID/GID của non-root user.
Với các image web server như Nginx, bạn cần đảm bảo các đường dẫn như /var/log/nginx, /var/cache/nginx hoặc các thư mục cấu hình tùy chỉnh được chown hoặc chmod đúng cho user phi root, để tiến trình có thể tạo file, ghi log và truy cập tài nguyên mà không bị lỗi Permission denied. Việc chuẩn hóa quyền ngay từ bước build image giúp khi áp dụng runAsUser hoặc runAsNonRoot trong Kubernetes/Docker, container hoạt động ổn định dưới user không phải root mà không yêu cầu đặc quyền bổ sung.

Cách run Pod/Container as non-root chi tiết
Sử dụng SecurityContext trong Kubernetes
Cấu hình ở cấp độ Pod
Trong môi trường Kubernetes, bạn không cần phải sửa đổi lại Dockerfile nếu muốn ép một container chạy non-root. Thay vào đó, bạn sẽ sử dụng trường securityContext trong tệp cấu hình YAML của pod. Trong manifest, cấu hình được khai báo tại spec.securityContext, với các trường như runAsUser:<UID> để buộc mọi container dùng cùng một UID không phải 0 hoặc runAsNonRoot: true để yêu cầu Kubernetes chỉ cho phép Pod start nếu user bên trong container không phải root.
Cấu hình file pod-security-context.yaml:
apiVersion: v1
kind: Pod
metadata:
name: non-root-pod-demo
spec:
securityContext:
runAsUser: 1001
runAsNonRoot: true
fsGroup: 1001 # Phân quyền cho volume
containers:
- name: my-app
image: your-app-image:latest
ports:
- containerPort: 8080Mẹo từ chuyên gia: Ở bước cấu hình Pod này, theo kinh nghiệm của mình, bạn nên bổ sung thêm trường fsGroup: <ID>. Trường này cực kỳ hữu ích vì nó sẽ tự động thay đổi quyền sở hữu của bất kỳ Volume nào được mount vào Pod sang Group ID mà bạn chỉ định, giúp ứng dụng không bao giờ bị lỗi mất quyền ghi file.
Cấu hình ở cấp độ Container
Nếu bạn cần các container khác nhau trong cùng một Pod chạy với các user khác nhau, bạn có thể định nghĩa securityContext riêng cho từng container. Cấu hình ở cấp độ container sẽ ghi đè lên cấu hình ở cấp độ pod.
Cấu hình file container-security-context.yaml:
apiVersion: v1
kind: Pod
metadata:
name: non-root-container-demo
spec:
containers:
- name: app-container-1
image: your-app-image-1:latest
securityContext:
runAsUser: 1001
runAsNonRoot: true
- name: app-container-2
image: your-app-image-2:latest
securityContext:
runAsUser: 1002
runAsNonRoot: trueChỉ định người dùng trong Dockerfile
Cách đơn giản nhất để run as non-root là sử dụng chỉ thị USER ngay bên trong tệp tin cấu hình Dockerfile. Đầu tiên, bạn cần viết lệnh tạo ra một nhóm (group) và một người dùng (user) mới với UID/GID cụ thể (ví dụ: 1001). Sau đó, bạn cấp quyền sở hữu thư mục làm việc cho người dùng này bằng lệnh chown. Cuối cùng, bạn thêm dòng USER 1001 ở cuối Dockerfile để đảm bảo mọi lệnh thực thi khi khởi chạy container đều dùng quyền của user số 1001 thay vì root.
Cấu hình Dockerfile như sau:
# Ví dụ cho ứng dụng Node.js
FROM node:18-slim
# Tạo user hệ thống để tăng tính bảo mật
RUN groupadd -r appgroup && useradd -r -g appgroup -u 1001 appuser
WORKDIR /app
COPY . .
# Chuyển quyền sở hữu thư mục cho user mới
RUN chown -R appuser:appgroup /app
# Chuyển sang dùng user non-root
USER 1001
CMD ["node", "server.js"]Sử dụng Docker Compose với tham số User
Khi sử dụng Docker Compose để phát triển hoặc triển khai nhỏ, bạn có thể ghi đè người dùng mặc định của image bằng thuộc tính user. Cách tiếp cận này rất linh hoạt vì nó cho phép bạn chỉ định UID/GID trùng với user trên máy Host, giúp giải quyết triệt để các vấn đề về quyền truy cập khi mount volume giữa máy thật và container. Việc này đảm bảo các file log hoặc dữ liệu sinh ra bởi container vẫn thuộc quyền sở hữu của bạn thay vì root.
Cấu hình file YAML tham khảo như sau:
version: '3.8'
services:
web-app:
image: nginx:latest
# Chạy container với UID 1000 và GID 1000 của User máy host
user: "1000:1000"
ports:
- "8080:8080"
volumes:
- ./data:/var/lib/app/dataKiểm tra và xác minh container/pod đang chạy non-root
Để xác thực cấu hình đã hoạt động, bạn hãy thực hiện các lệnh sau:
Kiểm tra ID người dùng
- Docker:
docker exec id - K8s:
kubectl exec -- id
Nếu lệnh id trả về UID khác 0 (ví dụ uid=1001), container đang chạy dưới user không phải root theo cấu hình runAsUser hoặc runAsNonRoot trong securityContext.
Kiểm tra tiến trình thực tế
Bạn chạy lệnh:
kubectl exec -- ps auxNếu kết quả trả về cột USER hiển thị UID (1001) thì bạn đang chạy user non-root.
Kiểm tra biến môi trường
Bạn chạy lệnh:
kubectl exec <pod_name> -- whoami
docker exec <container_id> whoamiKết quả trả về tên user bạn đã tạo (hoặc báo lỗi nếu user không có trong /etc/passwd – điều này bình thường nếu bạn chỉ dùng UID).
Lỗi thường gặp: Lệnh whoami có thể báo lỗi “whoami: cannot find name for user ID 1001” nếu bạn chỉ khai báo số UID trong Kubernetes mà chưa tạo user thực tế trong /etc/passwd của Image. Đừng lo lắng, về mặt bảo mật, miễn là hệ thống nhận UID khác 0, container của bạn đã an toàn.
Vietnix – Nhà cung cấp nền tảng Enterprise Cloud cho mọi giải pháp Kubernetes an toàn
Để triển khai hiệu quả các thực hành bảo mật nâng cao như Run as Non-Root trong Kubernetes, đòi hỏi một hạ tầng đám mây với khả năng tùy biến linh hoạt và hiệu suất cao. Vietnix cung cấp dịch vụ Enterprise Cloud Server hiệu suất vượt trội, lý tưởng để bạn xây dựng và vận hành các cụm Kubernetes an toàn. Với các tùy chọn cấu hình mạnh mẽ, bộ vi xử lý hiệu suất cao, ổ cứng NVMe siêu tốc và kết nối mạng ổn định, Vietnix đảm bảo bạn có một nền tảng vững chắc để triển khai các Pod, cấu hình securityContext và quản lý các container non-root một cách mượt mà.
Thông tin liên hệ:
- Website: https://vietnix.vn/
- Hotline: 1800 1093
- Email: sales@vietnix.com.vn
- Địa chỉ: 265 Hồng Lạc, Phường Bảy Hiền, Thành Phố Hồ Chí Minh
Câu hỏi thường gặp
Tại sao việc chạy container với quyền root lại được coi là một rủi ro bảo mật?
Chạy container với quyền root là rủi ro vì nếu một kẻ tấn công khai thác được một lỗ hổng trong ứng dụng, họ sẽ có quyền root bên trong container. Từ đó, họ có thể cố gắng leo thang đặc quyền để tấn công máy chủ host hoặc các container khác, gây ra thiệt hại nghiêm trọng.
Lệnh USER trong Dockerfile có vai trò gì trong việc chuẩn bị một image non-root?
Lệnh USER trong Dockerfile chỉ định người dùng (và tùy chọn là nhóm) mà container sẽ chạy các lệnh RUN, CMD và ENTRYPOINT tiếp theo. Bằng cách đặt USER thành một người dùng non-root đã được tạo trước đó, bạn đảm bảo rằng tiến trình chính của container sẽ khởi động với đặc quyền hạn chế.
Tại sao việc thêm người dùng vào nhóm docker trên máy chủ host lại có thể gây ra một rủi ro bảo mật?
Việc thêm người dùng vào nhóm docker thực chất là cấp cho người dùng đó các đặc quyền tương đương với quyền root trên máy chủ host. Người dùng đó có thể sử dụng các lệnh Docker để mount các thư mục hệ thống nhạy cảm vào container, từ đó có thể truy cập và sửa đổi toàn bộ hệ thống của host. Do đó, đây là một quyết định cần được cân nhắc kỹ lưỡng.
Run as Non-Root là một nguyên tắc bảo mật cơ bản và cực kỳ quan trọng trong hệ sinh thái container, giúp giảm thiểu đáng kể bề mặt tấn công và hạn chế tác động của các lỗ hổng bảo mật. Việc hiểu rõ các nguyên tắc và cách triển khai Run as Non-Root là một bước đi thiết yếu để làm chủ Kubernetes Security và bảo vệ các ứng dụng Cloud Native một cách hiệu quả.
THEO DÕI VÀ CẬP NHẬT CHỦ ĐỀ BẠN QUAN TÂM
Đăng ký ngay để nhận những thông tin mới nhất từ blog của chúng tôi. Đừng bỏ lỡ cơ hội truy cập kiến thức và tin tức hàng ngày













