Hướng dẫn cấu hình sudo và sudoers file trên Linux: Phân quyền an toàn cho từng người dùng

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Mình từng gặp tình huống này: một đồng nghiệp cần restart service Nginx trên server production, nhưng không có quyền root. Cách đơn giản nhất là cho họ mật khẩu root — nhưng đó là cách tệ nhất về mặt bảo mật. Đúng lúc đó mình mới thấy sudo quan trọng đến mức nào.

Trên con server CentOS 7 cũ của công ty, mình từng phải tối ưu khá nhiều thứ. Một trong những việc đầu tiên là cấu hình lại toàn bộ sudo policy — vì trước đó, gần như ai cũng được thêm vào group wheel mà không có giới hạn gì.

Vấn đề thực tế khi cấp quyền trên server

Khi làm việc với server Linux trong môi trường team, bạn sẽ gặp ngay bài toán: ai được làm gì? Developer cần deploy code, DevOps cần quản lý service, junior sysadmin cần xem log — nhưng không ai trong số này nên có toàn quyền root không giới hạn.

Linux giải quyết vấn đề này qua sudo (superuser do) và file cấu hình /etc/sudoers. Thay vì chia sẻ mật khẩu root, bạn kiểm soát chính xác: user nào, được chạy lệnh gì, với tư cách của user nào, trên máy nào.

Ba cách tiếp cận để cấp quyền sudo

Cách 1: Thêm user vào group sudo hoặc wheel

Nhanh nhất, quen thuộc nhất — một lệnh là xong. Nhưng lưu ý: cách này cấp toàn quyền sudo, không giới hạn lệnh nào cả.

# Ubuntu/Debian — dùng group "sudo"
sudo usermod -aG sudo username

# CentOS/RHEL/Fedora — dùng group "wheel"
sudo usermod -aG wheel username

# Kiểm tra user đã thuộc group chưa
id username
# groups: uid=1001(username) gid=1001(username) groups=1001(username),10(wheel)

Sau khi thêm vào group, user cần logout/login lại để group mới có hiệu lực.

Cách 2: Thêm rule trực tiếp vào /etc/sudoers

Muốn kiểm soát chi tiết hơn — ví dụ chỉ cho phép restart Nginx chứ không phải toàn bộ hệ thống — thì đây là hướng đi.

# LUÔN dùng visudo để chỉnh sudoers — KHÔNG bao giờ mở file trực tiếp
sudo visudo

# Cú pháp cơ bản trong sudoers:
# user  host=(runas_user) command
username ALL=(ALL) ALL

# Giới hạn chỉ được restart nginx
username ALL=(ALL) /usr/bin/systemctl restart nginx

# Nhiều lệnh, cách nhau bằng dấu phẩy
username ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx

Cách 3: Tạo file riêng trong /etc/sudoers.d/

Thay vì nhồi tất cả vào một file /etc/sudoers ngày càng dài, bạn tạo file riêng cho từng team trong /etc/sudoers.d/. Muốn thu quyền ai? Xóa file của họ là xong — không cần mò trong đống config khổng lồ.

# Tạo file cấu hình riêng cho user/team
sudo visudo -f /etc/sudoers.d/devteam

# Nội dung file:
# Cấp quyền deploy cho cả group devteam
%devteam ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl restart php-fpm

# Lưu ý: phân quyền file phải là 0440
sudo chmod 0440 /etc/sudoers.d/devteam

So sánh ưu nhược điểm của từng cách

Tiêu chí Group (sudo/wheel) Sửa /etc/sudoers /etc/sudoers.d/
Dễ dùng Rất dễ Trung bình Trung bình
Kiểm soát chi tiết Không (full quyền)
Dễ quản lý nhiều user Khó Khó (1 file lớn) Dễ (file riêng)
An toàn khi lỡ tay Thấp Thấp nếu không dùng visudo Cao hơn
Phù hợp môi trường Dev cá nhân Server nhỏ, ít user Production, team

Cách 1 cấp full sudo — user làm được mọi thứ như root. Cách 2 và 3 cho phép bạn giới hạn đúng lệnh cần thiết. Nguyên tắc bảo mật là least privilege — chỉ cấp đúng quyền cần thiết, không hơn.

Nên chọn cách nào?

  • Máy cá nhân / dev machine: Cách 1 hoàn toàn ổn — thêm user vào group sudo là đủ.
  • Server nhỏ, chỉ bạn hoặc 1-2 người admin: Cách 2, sửa trực tiếp sudoers với visudo.
  • Server production, có nhiều team: Cách 3 — mỗi team/role có file riêng trong /etc/sudoers.d/, dễ audit và dễ thu hồi quyền.

Mình thường dùng cách 3 cho production. Khi cần thu quyền của ai đó, chỉ cần xóa hoặc đổi tên file của họ thay vì mò vào một file sudoers khổng lồ.

Hướng dẫn triển khai thực tế

Bước 1: Tạo user và group (nếu chưa có)

# Tạo user mới
sudo useradd -m -s /bin/bash deployer
sudo passwd deployer

# Tạo group cho team
sudo groupadd devteam

# Thêm user vào group
sudo usermod -aG devteam deployer

Bước 2: Tạo sudoers rule với quyền giới hạn

sudo visudo -f /etc/sudoers.d/deployer

# Nội dung — chỉ cho phép restart/reload service liên quan đến deploy:
deployer ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx, \
                              /usr/bin/systemctl reload nginx, \
                              /usr/bin/systemctl restart php8.1-fpm, \
                              /usr/bin/systemctl status nginx

NOPASSWD nghĩa là user không cần nhập mật khẩu khi chạy lệnh đó — hữu ích cho automation/CI-CD script.

Bước 3: Cấu hình nâng cao với Aliases

Khi số lệnh tăng lên (5–10 lệnh là chuyện thường trong môi trường production), dùng Command Alias cho gọn:

sudo visudo -f /etc/sudoers.d/webteam

# Định nghĩa alias
Cmnd_Alias WEB_SERVICES = /usr/bin/systemctl restart nginx, \
                          /usr/bin/systemctl reload nginx, \
                          /usr/bin/systemctl restart php8.1-fpm

Cmnd_Alias VIEW_LOGS = /usr/bin/tail -f /var/log/nginx/error.log, \
                       /usr/bin/tail -f /var/log/nginx/access.log

# Cấp quyền cho group
%webteam ALL=(ALL) NOPASSWD: WEB_SERVICES
%webteam ALL=(ALL) NOPASSWD: VIEW_LOGS

Bước 4: Kiểm tra cấu hình

# Kiểm tra syntax toàn bộ sudoers (không thực thi)
sudo visudo -c
# Output mong muốn: /etc/sudoers: parsed OK
# /etc/sudoers.d/deployer: parsed OK

# Xem quyền hiện tại của user đang đăng nhập
sudo -l

# Xem quyền của một user cụ thể (cần quyền root)
sudo -lU deployer

# Test thử lệnh với -l flag (list, không thực thi)
sudo -l -U deployer

Cấu hình bổ sung hữu ích

# Tăng thời gian timeout sudo (mặc định 15 phút, đây đổi thành 5 phút)
# Thêm vào /etc/sudoers:
Defaults timestamp_timeout=5

# Yêu cầu nhập mật khẩu mỗi lần (timeout = 0)
Defaults timestamp_timeout=0

# Ghi log tất cả lệnh sudo vào file riêng
Defaults logfile=/var/log/sudo.log

# Bật lecture (cảnh báo khi lần đầu dùng sudo)
Defaults lecture=always

Những lỗi hay gặp và cách tránh

Lỗi 1: Sửa sudoers bằng editor thường (không dùng visudo)

Nếu bạn mở /etc/sudoers bằng nano hay vim trực tiếp và lỡ lưu với cú pháp sai, sudo sẽ hỏng hoàn toàn — không ai dùng được nữa. visudo kiểm tra syntax trước khi lưu. Đó là lý do nó tồn tại.

Lỗi 2: Quên đường dẫn tuyệt đối trong sudoers

# Sai — sudoers LUÔN cần đường dẫn tuyệt đối
deployer ALL=(ALL) systemctl restart nginx

# Đúng
deployer ALL=(ALL) /usr/bin/systemctl restart nginx

# Tìm đường dẫn đúng của lệnh
which systemctl
# /usr/bin/systemctl

Lỗi 3: Wildcard trong sudoers bị bypass

# NGUY HIỂM — user có thể dùng: sudo vim /etc/sudoers
deployer ALL=(ALL) /usr/bin/vim *

# An toàn hơn — chỉ cho phép chỉnh file cụ thể
deployer ALL=(ALL) /usr/bin/vim /var/www/html/config.php

Mình đã gặp trường hợp wildcard trong sudoers bị dùng để leo thang đặc quyền — user được phép vim * và họ mở luôn /etc/passwd để sửa. Cẩn thận với wildcard trong sudoers.

Audit và monitoring

Cấu hình xong rồi thì đừng để yên — bật logging để biết ai đang dùng sudo làm gì:

# Xem log sudo trên Ubuntu/Debian
grep sudo /var/log/auth.log

# Xem log sudo trên CentOS/RHEL
grep sudo /var/log/secure

# Ví dụ output:
# Mar 15 10:23:45 server sudo: deployer : TTY=pts/1 ; PWD=/home/deployer ;
# USER=root ; COMMAND=/usr/bin/systemctl restart nginx

Nếu server của bạn dùng journald (systemd-based), dùng thêm:

journalctl -u sudo --since "today"
# Hoặc lọc theo user cụ thể:
journalctl SYSLOG_IDENTIFIER=sudo _UID=$(id -u deployer)

Cấu hình sudo đúng không chỉ là chuyện bảo mật — nó còn giúp cả team làm việc trơn tru mà không cần ping admin mỗi khi muốn restart service. Nhớ ba điều: cấp đúng quyền cần thiết, ghi log mọi hành động, và dùng visudo — không có ngoại lệ.

Share: