❤️ AZDIGI chính thức cập nhật hệ thống blog mới hoàn chỉnh. Tuy nhiên có thể một số bài viết bị sai lệch hình ảnh, hãy ấn nút Báo cáo bài viết ở cuối bài để AZDIGI cập nhật trong thời gian nhanh nhất. Chân thành cám ơn.
Trên một VPS Linux, mỗi user account là một “cánh cửa” vào hệ thống. Càng nhiều cửa mở, càng nhiều rủi ro. Bài này mình sẽ đi sâu vào việc quản lý user và permission theo nguyên tắc Least Privilege, giúp bạn kiểm soát chặt chẽ ai được làm gì trên server.

Nguyên tắc Least Privilege là gì?
Least Privilege (quyền tối thiểu) nghĩa là: mỗi user, mỗi process chỉ được cấp đúng quyền cần thiết để hoàn thành công việc của nó. Không hơn, không kém.
Nghe thì hiển nhiên, nhưng thực tế rất nhiều VPS đang chạy ngược lại hoàn toàn:
- Mọi người đều SSH bằng root
- App chạy dưới quyền root
- User deploy có full sudo không giới hạn
- Account cũ không ai dùng vẫn còn active
Chỉ cần một account bị compromise, attacker có toàn quyền server. Least Privilege giúp giới hạn thiệt hại: dù một account bị chiếm, kẻ tấn công cũng chỉ làm được rất ít.
Audit user hiện tại trên server
Bước đầu tiên là xem server đang có những ai. Không phải tất cả user trong /etc/passwd đều đáng lo, nhưng những user có shell access thì cần kiểm tra kỹ.
Lọc ra những user có thể login (có shell thật, không phải nologin hay false):
cat /etc/passwd | grep -v nologin | grep -v false
Output sẽ kiểu như:
root:x:0:0:root:/root:/bin/bash
thach:x:1000:1000::/home/thach:/bin/bash
deploy:x:1001:1001::/home/deploy:/bin/bash
olduser:x:1002:1002::/home/olduser:/bin/bash
Câu hỏi cần đặt ra với mỗi user trong danh sách:
- User này là ai? Còn cần dùng không?
- Tại sao user này có shell access?
- User này có sudo không? Nếu có thì sudo được những gì?
Nếu bạn thấy user lạ mà không nhớ đã tạo bao giờ, đó là dấu hiệu cần điều tra ngay. Kiểm tra last olduser để xem user đó có login gần đây không.
Audit quyền sudo
Biết ai có shell chưa đủ. Bạn cần biết ai đang có quyền sudo, vì sudo gần như tương đương root.
Xem file sudoers chính (bỏ qua comment):
grep -v '^#' /etc/sudoers | grep -v '^$'
Kiểm tra thêm thư mục sudoers.d, nơi thường chứa các rule bổ sung:
ls -la /etc/sudoers.d/
cat /etc/sudoers.d/*
Một cách nhanh hơn là xem những user thuộc group sudo (Debian/Ubuntu) hoặc wheel (CentOS/AlmaLinux):
# Ubuntu/Debian
getent group sudo
# CentOS/AlmaLinux
getent group wheel
Nếu output hiện ra một đống user đều có full sudo, đó chính là vấn đề cần xử lý.
Cấp sudo chi tiết thay vì full access
Đây là phần quan trọng nhất khi áp dụng Least Privilege cho sudo. Thay vì cho user quyền ALL=(ALL) ALL, bạn chỉ cho phép đúng command cần thiết.
Ví dụ: user deploy chỉ cần restart nginx và php-fpm, không cần làm gì khác với quyền root.
Tạo file rule riêng cho user deploy:
visudo -f /etc/sudoers.d/deploy
Nội dung:
# User deploy — chỉ được restart nginx và php-fpm
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart php*-fpm
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl reload nginx
Giải thích từng phần:
deploy, user được áp dụng ruleALL=(ALL), từ bất kỳ host nào, chạy với quyền bất kỳ user nàoNOPASSWD:, không hỏi password (cần thiết cho automation/CI-CD)- Phần cuối là đường dẫn tuyệt đối đến command được phép
Luôn dùng đường dẫn tuyệt đối (full path) trong sudoers. Nếu chỉ ghi systemctl mà không có /usr/bin/systemctl, kẻ tấn công có thể tạo một file systemctl giả trong thư mục khác và chạy với quyền root.
Kiểm tra lại user deploy có thể làm gì:
sudo -l -U deploy
Output sẽ liệt kê chính xác những command mà user deploy được phép chạy với sudo.
Audit file SUID/SGID
SUID (Set User ID) là một permission đặc biệt: khi file có SUID, bất kỳ ai chạy nó đều chạy với quyền của owner file đó (thường là root). SGID tương tự nhưng cho group.
Một số file SUID là cần thiết (passwd, ping, su). Nhưng nếu attacker cài thêm file SUID hoặc có file SUID bị lỗi bảo mật, đó là đường leo thang đặc quyền (privilege escalation) rất phổ biến.
Tìm tất cả file SUID trên server:
find / -perm -4000 -ls 2>/dev/null
Tìm file SGID:
find / -perm -2000 -ls 2>/dev/null
Output sẽ liệt kê tất cả file có SUID/SGID. Bạn cần review từng file:
- File này có phải của hệ thống không? (
/usr/bin/passwd,/usr/bin/sudolà bình thường) - File này có cần SUID không? Nhiều file SUID cũ không còn cần thiết
- File lạ nằm ở thư mục không thuộc hệ thống? Đó là dấu hiệu đáng ngờ
Xóa SUID khỏi file không cần thiết:
# Xóa SUID
chmod u-s /path/to/file
# Xóa SGID
chmod g-s /path/to/file
Nên lưu lại danh sách SUID files hiện tại làm baseline. Chạy lại lệnh find định kỳ và so sánh với baseline để phát hiện file SUID mới xuất hiện.
# Tạo baseline
find / -perm -4000 -type f 2>/dev/null | sort > /root/suid-baseline.txt
# So sánh sau này
find / -perm -4000 -type f 2>/dev/null | sort | diff /root/suid-baseline.txt -
Service accounts: mỗi app một user riêng
Một trong những lỗi phổ biến nhất: chạy mọi thứ bằng root. Web server, database, Node.js app, cron job… tất cả đều root. Nếu bất kỳ service nào bị khai thác, attacker có ngay quyền root.
Cách đúng là tạo user riêng cho mỗi service, và user đó chỉ có quyền trên những gì service cần:
# Tạo user cho Node.js app — không có home dir, không có login shell
useradd --system --no-create-home --shell /sbin/nologin nodeapp
# Tạo user cho một service Python
useradd --system --no-create-home --shell /sbin/nologin pyworker
Flag --system tạo system account (UID thấp, không hiện ở login screen). Flag --shell /sbin/nologin ngăn user này SSH vào server.
Trong file systemd service, chỉ định user:
[Service]
User=nodeapp
Group=nodeapp
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/node /var/www/myapp/server.js
Phân quyền thư mục cho đúng user:
# Thư mục app thuộc về user nodeapp
chown -R nodeapp:nodeapp /var/www/myapp
# Chỉ owner đọc/ghi, group đọc, others không có quyền gì
chmod -R 750 /var/www/myapp
Với cách này, nếu app Node.js bị hack, attacker chỉ truy cập được thư mục /var/www/myapp dưới quyền user nodeapp. Không đọc được file của service khác, không sửa được config hệ thống.
Giới hạn quyền dùng su
Lệnh su cho phép chuyển sang user khác (thường là root). Mặc định, bất kỳ user nào biết password root đều dùng được su. Bạn nên giới hạn chỉ một nhóm user cụ thể mới được phép.
Trên CentOS/AlmaLinux, group wheel thường đã được cấu hình sẵn. Trên Ubuntu/Debian, bạn cần setup thủ công.
Chỉnh file PAM cho lệnh su:
nano /etc/pam.d/su
Tìm dòng sau và bỏ comment (xóa dấu # đầu dòng):
# CentOS/AlmaLinux — dùng group wheel
auth required pam_wheel.so use_uid
# Ubuntu/Debian — dùng group sudo (hoặc tạo group wheel)
auth required pam_wheel.so use_uid group=sudo
Sau khi bật dòng này, chỉ user thuộc group wheel (hoặc sudo) mới chạy được lệnh su. Các user khác sẽ bị từ chối ngay cả khi biết password root.
Đảm bảo user chính của bạn nằm trong group cho phép:
# CentOS/AlmaLinux
usermod -aG wheel thach
# Ubuntu/Debian
usermod -aG sudo thach
Password policy
Nếu server có user dùng password để login (thay vì chỉ SSH key), bạn cần đặt policy cho password: thời hạn, độ dài tối thiểu, độ phức tạp.
Xem thông tin password của một user:
chage -l thach
Output sẽ hiện ngày đổi password gần nhất, ngày hết hạn, số ngày tối thiểu/tối đa giữa các lần đổi, v.v.
Đặt password hết hạn sau 90 ngày và cảnh báo trước 14 ngày:
# Password hết hạn sau 90 ngày
chage -M 90 thach
# Cảnh báo 14 ngày trước khi hết hạn
chage -W 14 thach
# Tối thiểu 7 ngày giữa các lần đổi password
chage -m 7 thach
Để yêu cầu password phức tạp (độ dài, phải có chữ hoa, số, ký tự đặc biệt), cài module PAM:
# Ubuntu/Debian
apt install libpam-pwquality -y
# CentOS/AlmaLinux (thường đã có sẵn)
dnf install pam_pwquality -y
Cấu hình trong file:
nano /etc/security/pwquality.conf
Các setting hay dùng:
# Độ dài tối thiểu
minlen = 12
# Tối thiểu 1 chữ hoa
ucredit = -1
# Tối thiểu 1 chữ số
dcredit = -1
# Tối thiểu 1 ký tự đặc biệt
ocredit = -1
# Không cho dùng lại 5 password gần nhất
remember = 5
Nếu server chỉ dùng SSH key và đã disable password login hoàn toàn (như bài trước đã hướng dẫn), phần password policy này ít quan trọng hơn. Nhưng vẫn nên set, vì một số service khác (su, sudo khi không có NOPASSWD) vẫn dùng password.
Khóa và vô hiệu hóa account không dùng
Account cũ không ai dùng là rủi ro lớn. Có thể password đã bị lộ mà không ai biết. Cách xử lý:
Khóa password (user không login bằng password được):
# Khóa account
usermod -L olduser
# Mở khóa nếu cần
usermod -U olduser
Đổi shell thành nologin (chặn cả SSH key login):
usermod -s /sbin/nologin olduser
Kết hợp cả hai cho chắc:
# Khóa password + đổi shell
usermod -L -s /sbin/nologin olduser
Set ngày hết hạn cho account:
# Account hết hạn ngày 2025-12-31
chage -E 2025-12-31 contractor
Cách này hữu ích cho account tạm thời (contractor, thực tập sinh). Đến ngày hết hạn, account tự động bị disable.
Trước khi xóa hẳn một user (userdel), nên khóa trước và quan sát một thời gian. Nếu không có vấn đề gì thì mới xóa. Tránh xóa xong mới phát hiện có service đang chạy dưới user đó.
Theo dõi hoạt động user
Bạn cần biết ai đang login, ai đã login gần đây, và có ai cố login thất bại không. Linux có sẵn các công cụ cho việc này:
Xem ai đang online:
# Ai đang login
who
# Chi tiết hơn: đang chạy gì, idle bao lâu
w
Lịch sử login:
# Login thành công gần đây
last
# Chỉ xem user cụ thể
last thach
# Login thất bại (brute force detection)
lastb
Xem log authentication chi tiết:
# Ubuntu/Debian
tail -100 /var/log/auth.log
# CentOS/AlmaLinux
tail -100 /var/log/secure
Nếu bạn thấy hàng trăm dòng “Failed password” từ các IP lạ trong lastb hoặc auth log, đó là dò mật khẩu. Bài sau mình sẽ nói về Fail2ban để tự động block các IP này.
Ví dụ thực tế: setup user deploy cho web app
Mình sẽ đi qua một ví dụ hoàn chỉnh: tạo user deploy cho CI/CD pipeline, user này chỉ được phép:
- Ghi file vào
/var/www/myapp - Restart nginx và php-fpm
- Không có quyền gì khác
Bước 1: Tạo user
# Tạo user deploy với home directory
useradd -m -s /bin/bash deploy
# Set password (hoặc chỉ dùng SSH key thì bỏ qua)
passwd deploy
Bước 2: Tạo thư mục app và phân quyền
# Tạo thư mục
mkdir -p /var/www/myapp
# Ownership cho deploy
chown -R deploy:deploy /var/www/myapp
# Permission: owner full, group đọc+chạy, others không gì
chmod -R 750 /var/www/myapp
Nếu nginx cần đọc file trong thư mục này, thêm user www-data (hoặc nginx) vào group deploy:
# Ubuntu/Debian — web server chạy dưới user www-data
usermod -aG deploy www-data
# CentOS/AlmaLinux — web server chạy dưới user nginx
usermod -aG deploy nginx
Bước 3: Cấp sudo giới hạn
visudo -f /etc/sudoers.d/deploy
Nội dung:
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl reload nginx
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart php*-fpm
Bước 4: Setup SSH key cho deploy
# Tạo thư mục .ssh cho user deploy
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
# Thêm public key của CI/CD
echo "ssh-ed25519 AAAA... ci-cd-pipeline" >> /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
Bước 5: Kiểm tra
# Kiểm tra quyền sudo
sudo -l -U deploy
# Thử SSH vào bằng user deploy
ssh deploy@your-server-ip
# Thử restart nginx (phải thành công)
sudo systemctl restart nginx
# Thử đọc file root (phải thất bại)
cat /etc/shadow
User deploy giờ chỉ làm được đúng những gì cần cho việc deploy. Không hơn.
Checkpoint
Bạn nên thực hành ngay trên VPS của mình. Dưới đây là checklist:
| Việc cần làm | Command / Hành động | Done? |
|---|---|---|
| Audit user có shell access | cat /etc/passwd | grep -v nologin | grep -v false | ☐ |
| Audit quyền sudo | grep -v '^#' /etc/sudoers + kiểm tra /etc/sudoers.d/ | ☐ |
| Tìm file SUID/SGID | find / -perm -4000 -ls 2>/dev/null | ☐ |
| Lưu baseline SUID | Lưu danh sách SUID vào file để so sánh sau | ☐ |
| Tạo user deploy với sudo giới hạn | Tạo user + file trong /etc/sudoers.d/ | ☐ |
| Khóa account không dùng | usermod -L -s /sbin/nologin olduser | ☐ |
| Kiểm tra login history | last, lastb, who | ☐ |
Bài tiếp theo mình sẽ nói về Fail2ban và các cách tự động phát hiện + block tấn công dò mật khẩu. Nếu bài này giúp bạn kiểm soát user tốt hơn, phần sau sẽ giúp bạn xử lý những kẻ đang cố phá cửa vào.
Có thể bạn cần xem thêm
- User, Group và Sudo trên Linux - Quản lý tài khoản VPS
- Checklist bảo mật VPS Linux - 15 bước thiết yếu
- Bảo vệ SSH toàn diện trên Linux VPS
- Quyền file và thư mục trên Linux - chmod, chown và rwx
- Cấu trúc thư mục Linux - Mọi thứ nằm ở đâu trên VPS
- Backup và phục hồi sự cố cho VPS Linux - Kế hoạch toàn diện
Về tác giả
Trần Thắng
Chuyên gia tại AZDIGI với nhiều năm kinh nghiệm trong lĩnh vực web hosting và quản trị hệ thống.