HỌC BẰNG THỰC HÀNH
← Lộ trình học
01 · Linux Administration · BREAK/FIX

Break/Fix: dịch vụ tài liệu báo Permission denied

Tạo sự cố trong phạm vi lab của bài, thu bằng chứng, sửa rồi kiểm tra.

Cốt lõi

Tình huống

Dịch vụ tài liệu nội bộ kdc-docs chạy bằng tài khoản kdc-docs và phục vụ /srv/kdc-docs trên port 8082. Sau đợt "siết bảo mật" của một đồng nghiệp, dịch vụ không khởi động. Một người khác đề xuất chmod -R 777 /srv/kdc-docs cho nhanh.

Nhiệm vụ: đưa dịch vụ hoạt động lại, không cấp quyền cho other, giữ nội dung thuộc root, và viết RCA.

Vì sao cần học

Permission denied là lỗi phổ biến nhất trên Linux, và chmod 777 là cách sửa tệ nhất. Kỹ năng cần có: tái hiện lỗi bằng đúng tài khoản của dịch vụ, đi dọc đường dẫn để tìm thư mục chặn, và nhận ra những lớp quyền không hiện rõ như ACL.

Mục tiêu

  • Đọc mã lỗi systemd (status=200/CHDIR) và log của dịch vụ.
  • Tái hiện bằng sudo -u <user> và kiểm tra từng cấp đường dẫn bằng namei -l.
  • Nhận ra ACL mask đang che quyền group (dấu + trong ls -l, getfacl).
  • Cấp quyền tối thiểu: group của dịch vụ được đọc, other không có gì.

Điều kiện tiên quyết

  • Bài User, group và thư mục dùng chung (phần ACL) và Vận hành web service bằng systemd.

Tạo sự cố

Đọc kỹ script, lưu vào ~/break-permission.sh trên VM, chạy sudo bash ~/break-permission.sh.

#!/usr/bin/env bash
# KDC Break/Fix: permission denied. Chỉ chạy trên VM lab có /etc/kdc-lab.
set -euo pipefail
[[ $EUID -eq 0 ]] || { echo "Chạy bằng sudo." >&2; exit 1; }
grep -qs '^KDC-LAB' /etc/kdc-lab || { echo "Không thấy marker /etc/kdc-lab; script chỉ chạy trên máy lab." >&2; exit 1; }
read -r -p "Script sẽ tạo dịch vụ kdc-docs với quyền sai. Tiếp tục? [y/N] " answer
[[ $answer == y ]] || exit 1

id -u kdc-docs &>/dev/null || useradd --system --no-create-home --shell /usr/sbin/nologin kdc-docs
systemctl stop kdc-docs.service 2>/dev/null || true
rm -rf /srv/kdc-docs
install -d -o root -g root -m 700 /srv/kdc-docs
echo '<h1>KDC-DOCS</h1>' > /srv/kdc-docs/index.html
chown root:kdc-docs /srv/kdc-docs/index.html
chmod 640 /srv/kdc-docs/index.html
setfacl -m m::- /srv/kdc-docs/index.html

cat > /etc/systemd/system/kdc-docs.service <<'UNIT'
[Unit]
Description=KDC internal docs

[Service]
User=kdc-docs
WorkingDirectory=/srv/kdc-docs
ExecStart=/usr/bin/python3 -m http.server 8082 --bind 127.0.0.1 --directory /srv/kdc-docs
Restart=on-failure
RestartSec=2

[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
systemctl enable kdc-docs.service
systemctl start kdc-docs.service || true
echo "Đã tạo sự cố. Bắt đầu từ: systemctl status kdc-docs"
Giải thích lệnh và tham số

chown root:kdc-docs <file> đặt owner là root và group là kdc-docs; dấu : phân cách user với group. setfacl -m m::- <file> đặt ACL mask không có quyền; mask giới hạn quyền hiệu lực của group và named user/group trong ACL. Đây là các thao tác script cố ý thực hiện để tạo sự cố, chưa phải cách sửa.

read -r -p hỏi xác nhận như bài Break/Fix trước; sudo bash ~/break-permission.sh phải chạy trên VM lab. Các dòng User=, WorkingDirectory=, ExecStart= nằm trong unit file được script ghi, không gõ trực tiếp vào shell.

Bấm Kiểm tra kết quả một lần để thấy trạng thái xuất phát.

Điều tra

  1. Symptom: dịch vụ đang ở trạng thái nào, mã lỗi là gì?
  2. Scope: chỉ tài khoản dịch vụ bị chặn, hay root cũng bị?
  3. Layer: đi từ / xuống tới file: cấp nào chặn tài khoản kdc-docs?
  4. Evidence: quyền hiện ra trong ls -l có phải toàn bộ sự thật không?
  5. Fix: cấp đúng quyền tối thiểu, restart, kiểm tra bằng chính tài khoản dịch vụ.

Đọc các công cụ điều tra

namei -l <đường-dẫn> tách đường dẫn thành từng thành phần và in quyền/owner/group (-l) ở mỗi cấp; dùng để tìm thư mục cha không cho đi qua. sudo -u kdc-docs cat ... đọc file bằng đúng user dịch vụ, thay vì quyền root. getfacl in ACL và quyền effective bị mask giới hạn; ls -ld xem quyền thư mục, ls -l <file> xem quyền file.

Gợi ý (chỉ mở khi bế tắc)

  • Mức 1, hướng nhìn: có hai chỗ chặn ở hai cấp khác nhau. Sửa xong chỗ thứ nhất, triệu chứng sẽ đổi.
  • Mức 2, công cụ: systemctl status kdc-docs, journalctl -u kdc-docs -n 20, sudo namei -l /srv/kdc-docs/index.html, sudo -u kdc-docs cat /srv/kdc-docs/index.html, getfacl /srv/kdc-docs/index.html.
  • Mức 3, một bước: thư mục cần group kdc-docs với quyền r-x. Với file, dấu + trong ls -l nghĩa là có ACL; quyền group thật bị giới hạn bởi mask.

Viết RCA

Tạo ~/kdc-labs/rca/permission-denied.md:

# RCA: kdc-docs không phục vụ được tài liệu

## Triệu chứng
## Evidence
## Nguyên nhân gốc
## Cách sửa
## Phòng tránh

Trong Phòng tránh, giải thích vì sao chmod -R 777 bị từ chối và đề xuất cách kiểm tra quyền sau mỗi lần "siết bảo mật".

Tự kiểm tra (Verification)

systemctl is-active kdc-docs
sudo -u kdc-docs cat /srv/kdc-docs/index.html
curl -s http://127.0.0.1:8082/
ls -ld /srv/kdc-docs; ls -l /srv/kdc-docs/index.html
Giải thích lệnh và tham số

sudo -u kdc-docs chạy cat bằng tài khoản dịch vụ để thử quyền truy cập thật. curl -s ẩn tiến độ. ls -ld xem quyền chính thư mục (-d) ở dạng chi tiết (-l); ls -l <file> xem quyền file.

Chọn server và bấm Kiểm tra kết quả.

Ghi chú production

  • Nội dung tĩnh nên thuộc root (hoặc tài khoản deploy) và chỉ cho dịch vụ quyền đọc. Dịch vụ bị khai thác cũng không sửa được nội dung.
  • chmod trên file có ACL thay đổi mask, không phải quyền của group sở hữu. Đọc getfacl trước khi kết luận.
  • Trên RHEL, nếu quyền Unix đúng mà vẫn bị chặn, bước tiếp theo là kiểm tra SELinux (bài SELinux: context, port và boolean).

Dọn dẹp

sudo systemctl disable --now kdc-docs.service
sudo rm -f /etc/systemd/system/kdc-docs.service
sudo systemctl daemon-reload
sudo rm -rf /srv/kdc-docs
sudo userdel kdc-docs
Giải thích lệnh và tham số

systemctl disable --now bỏ cấu hình tự chạy khi boot và dừng service ngay. daemon-reload yêu cầu systemd đọc lại unit file sau khi sửa/xóa. rm -f xóa file và không hỏi xác nhận; -r thêm xóa đệ quy thư mục cùng nội dung, nên -rf gộp hai tùy chọn này. userdel kdc-docs xóa tài khoản lab.

Tài liệu chính thức