KB-291B

Q2 Create OS user incomex on VPS Report S178 Fix 11

7 min read Revision 1
q2vpsuseraddincomexreports178-fix11

Q2 — Create OS user incomex on VPS — Report

Ngày chạy: 2026-04-17 06:50 UTC+7 Phiên: S178 Fix 11 (Q2 phụ, ngoài 8 Phase Đ43) Agent: Claude CLI qua SSH contabo VPS: vmi3080463 (38.242.240.89)

CHECKPOINT

Đã đọc: Đ41 VPS-SSOT + report Phase 2 Issue 2.

1. PRE-STATE

$ getent passwd 1001    → (empty, UID 1001 UNNAMED)
$ getent group 1001     → (empty, GID 1001 UNNAMED)
$ getent passwd incomex → (empty, không tồn tại)
$ getent group incomex  → (empty, không tồn tại)
$ grep ^incomex: /etc/passwd /etc/group → (no match, không có user/group tên incomex khác)
$ awk -F: '$3>=999 && $3<=1010' /etc/group
    systemd-journal:x:999:   (không đụng 1001)

$ stat -c "%U:%G" /opt/incomex/dot/bin /opt/incomex/context-pack*
    /opt/incomex/dot/bin            UNKNOWN:UNKNOWN   (tức 1001:1001)
    /opt/incomex/context-pack       UNKNOWN:UNKNOWN
    /opt/incomex/context-pack.tmp   UNKNOWN:UNKNOWN
    /opt/incomex/context-pack-staging UNKNOWN:UNKNOWN

PRE-STATE xác nhận UID/GID 1001 chưa được user/group nào chiếm → an toàn tạo user incomex gắn vào UID/GID đã có.

Phát hiện phụ: 2 file .sh Phase 2 (dot-dieu43-fs-init.sh, dot-dieu43-fs-verify.sh) đang root:root (do tôi ssh as root để tạo file), lệch với pattern /opt/incomex/dot/bin/ (1001:1001). Đã fix chown incomex:incomex sau khi useradd để khớp pattern — là "file chưa khớp UID 1001" đúng trường hợp §7 cho phép.

2. QUYẾT ĐỊNH THIẾT KẾ

Chọn useradd -u 1001 -g incomex -M -s /usr/sbin/nologin -c "...":

Flag Giá trị Lý do
-u 1001 UID cố định Match UID UNNAMED hiện có trên /opt/incomex/ — mục tiêu chính của Q2
-g incomex Primary group Dùng group vừa tạo (GID 1001) — tránh useradd tự sinh private group GID khác
-M Không tạo home dir incomexservice/app account, không phải user đăng nhập. /opt/incomex/ là app directory (không phải HOME — đã ghi trong prompt §4.4). Home /home/incomex ghi trong /etc/passwd để pass validator nhưng KHÔNG tạo trên FS (verified: ls /home/incomex → No such file).
-s /usr/sbin/nologin Không shell login Ngăn interactive login (service account, không cần ai SSH vào bằng user này). An toàn hơn mặc định /bin/sh.
-c "Incomex app service account" GECOS comment Ghi rõ vai trò trong /etc/passwd để ai đọc cũng hiểu.

Thứ tự an toàn: groupadd trước → useradd -g incomex — đảm bảo primary group có sẵn, tránh useradd tự sinh private group với GID khác 1001.

3. LỆNH ĐÃ CHẠY (nguyên văn)

groupadd -g 1001 incomex
useradd  -u 1001 -g incomex -M -s /usr/sbin/nologin \
         -c "Incomex app service account" incomex

# Fix ownership 2 Phase 2 scripts (thừa hưởng Phase 2 side-effect):
chown incomex:incomex /opt/incomex/dot/bin/dot-dieu43-fs-init.sh
chown incomex:incomex /opt/incomex/dot/bin/dot-dieu43-fs-verify.sh

3 lệnh trên, không thêm gì khác. Không sudo/wheel, không password, không SSH key, không bulk chown.

4. POST-STATE: 7 TIÊU CHÍ

# Tiêu chí Expected Actual PASS?
C1 id incomex UID/GID 1001 uid=1001(incomex) gid=1001(incomex) uid=1001(incomex) gid=1001(incomex) groups=1001(incomex) PASS
C2 getent passwd incomex có entry non-empty incomex:x:1001:1001:Incomex app service account:/home/incomex:/usr/sbin/nologin PASS
C3 getent group incomex có entry non-empty incomex:x:1001: PASS
C4 Phase 2 scripts hiển thị tên owner incomex:incomex -rwxr-xr-x 1 incomex incomex 4966 ... dot-dieu43-fs-init.sh / -rwxr-xr-x 1 incomex incomex 3853 ... dot-dieu43-fs-verify.sh PASS
C5 context-pack* 3 folder hiển thị tên incomex:incomex /opt/incomex/context-pack incomex:incomex mode=755 / .tmp incomex:incomex mode=755 / -staging incomex:incomex mode=755 PASS
C6 dot-dieu43-fs-verify.sh exit 0 0 0 (3/3 PASS) PASS
C7 dot-dieu43-fs-init.sh idempotent 0 + 0 diff exit 0, IDEMPOTENT: OK (0 diff) PASS

Verify output C6 (nguyên văn):

[INFO] dot-dieu43-fs-verify v1.0.0
[INFO] Ownership reference: /opt/incomex/dot/bin (uid:gid = 1001:1001) / mode 755
[PASS] /opt/incomex/context-pack (owner=1001:1001 mode=755)
[PASS] /opt/incomex/context-pack.tmp (owner=1001:1001 mode=755)
[PASS] /opt/incomex/context-pack-staging (owner=1001:1001 mode=755)
[PASS] Phase 2 filesystem verified — 3/3 folder OK

(script vẫn in UID:GID dạng số 1001:1001 vì dùng stat -c '%u:%g' — là intended behavior, không thay đổi. Muốn hiển thị %U:%G tên user thì phải sửa script, ngoài scope Q2.)

Bonus observation: /opt/incomex/dot vẫn root:root (app-level owner), /opt/incomex/dot/binincomex:incomex (nơi DOT script sống). Pattern này hợp lý: root sở hữu container dir, incomex sở hữu vùng code runtime.

5. BẤT THƯỜNG PHÁT SINH

Không có sự cố.

Một điểm nhỏ để Desktop biết: /etc/passwd ghi home là /home/incomex nhưng thư mục đó KHÔNG tồn tại trên FS (vì -M). Với service account dùng nologin, đây là pattern chuẩn — hệ thống không bao giờ thực sự cần home dir này. Nếu về sau có process nào cố cd ~ khi chạy as incomex, sẽ fail — nhưng không có use case đó.

Nếu Desktop muốn "sạch" hoàn toàn, có thể usermod -d /nonexistent incomex để đổi home thành /nonexistent (convention cho service account). Không bắt buộc.

6. KẾT LUẬN

Q2 PASS — 7/7 tiêu chí.

User OS incomex:incomex (UID 1001, GID 1001) đã tồn tại trên VPS. 4 luật Đ33/Đ35/Đ41/Đ43 giờ khớp thực tế VPS khi nói "owner incomex:incomex". Phase 2 Đ43 vẫn PASS sau thay đổi. Phase 1 Đ43 (PG-only) không bị ảnh hưởng.

Tác động rộng

  • Các file/folder đang UID 1001 trên toàn hệ thống (không chỉ /opt/incomex/) sẽ tự động hiển thị tên incomex:incomex trong ls -la, stat, v.v.
  • Scripts Phase 2 giờ owner khớp pattern folder parent (incomex:incomex cả 2).
  • Sẵn sàng Phase 6 (install cron dưới user incomex — tính năng của Phase 6, không phải Q2).

KHÔNG làm gì rộng hơn (theo §2 M4 + §7)

  • Không tạo user khác (không postgres/directus OS user)
  • Không bulk chown /opt/incomex/ (tự hiển thị tên khi lookup UID)
  • Không sudo/wheel/admin group
  • Không password/SSH key
  • Không shell login (nologin)

Report by Claude CLI — S178 Fix 11 Q2 — 2026-04-17