Asia Business Builders — Merchant Banking Các vai trong Postgres Phụ lục 3 · đo 26/09 · cập nhật 08/10/2026

Phụ lục 3 của Kiến trúc SIXDO Data Hub · PostgreSQL 16.15

19 vai trong Postgres — chỉ 5 là của dự án

14 vai còn lại do PostgreSQL tự tạo sẵn; không vai nào của dự án là thành viên của chúng

Mỗi vai của dự án giữ một ranh giới dữ liệu: ai được ghi, ai chỉ đọc số, ai được thấy tên và số điện thoại khách, chatbot được thấy gì. Mọi con số trên trang này đo trực tiếp trên hub ngày 26/09/2026, 10:06–10:20, sau khi tạo vai claude_ro. Không có mật khẩu nào trên trang. Tài liệu chính: Kiến trúc SIXDO Data Hub.

19vai trong Postgres
5vai do dự án tạo
14vai dựng sẵn của PostgreSQL
4vai đăng nhập được

Phần 01

Vì sao có 19 vai — thật ra chỉ có 5

Truy vấn select * from pg_roles trả 19 dòng. Trong đó 14 là vai PostgreSQL 16 tự tạo lúc cài đặt (tên bắt đầu bằng pg_), không đăng nhập được và không vai nào của dự án là thành viên — chúng nằm đó trên mọi máy chủ PostgreSQL 16. Phần còn lại là 5 vai của dự án.


Cập nhật 08/10/2026 — trang này đo ngày 26/09 trên laptop, khi laptop còn là máy hub. Từ đêm 05→06/10 kho chạy trên PC văn phòng. Đo lại trên PC lúc 15:32 ngày 08/10 (vai chỉ đọc, chỉ danh mục hệ thống): 20 vai, 6 của dự án, 5 đăng nhập được. Vai mới claude_ro_laptop (07/10): thành viên bi_reader, tối đa 4 kết nối, cùng 8 cài đặt như claude_ro cộng ghi mọi câu lệnh vào nhật ký; đăng nhập từ laptop qua NetBird và chuyển tiếp cổng trên PC. bi_reader nay 24 bảng / view (thêm dim_thue_gtgt 27/09), bi_full 30. Bốn vai đăng nhập cũ trên PC đều có mật khẩu 32 ký tự sinh ngẫu nhiên (đo 07/10, không in). Vai sắp tới: claude_ro_ceo, chờ duyệt. Bản đồ các lớp mà các vai này canh: Phụ lục 7.

VaiMột câu: để làm gìĐăng nhậpAi / cái gì dùng
datahubChủ sở hữu toàn bộ dữ liệu — vai duy nhất được ghiCó · SUPERUSERĐồng bộ đêm 01:00, dbt, task kiểm sức khoẻ, script của agent
bi_readerVùng số liệu được phép rời máy: 23 bảng / view, không tên hay SĐT kháchCóBản tin Teams 07:00; là "nhóm" mà claude_ro và bi_full kế thừa
bi_piiNhóm quyền cho vùng dữ liệu cá nhân: 6 bảng có tên, SĐT, email, địa chỉ khách, họ tên nhân viênKhôngKhông ai đăng nhập; chỉ bi_full là thành viên
bi_fullNgười thấy tất cả trên máy này = bi_reader + bi_pii (29 bảng / view)CóPower BI Desktop, DBeaver
claude_roChatbot hỏi số qua MCP — đọc đúng vùng bi_reader, kèm 8 cài đặt an toànCó · tối đa 4 kết nốiMáy chủ MCP bi/mcp/mcp_datahub_ro.py (tạo 26/09 10:06)

Gộp bớt thì hỏng ở đâu

Năm vai là số nhỏ nhất giữ được bốn ranh giới đang có. Mỗi dòng dưới đây là một cách gộp nghe có vẻ gọn, và thứ nó làm vỡ:

Nếu…Thì hỏng
Power BI dùng luôn datahubMật khẩu lưu trong kho credential của Power BI Desktop trở thành chìa khoá vạn năng: đọc mọi dữ liệu cá nhân, sửa và xoá được cả hub. Lộ máy hay lộ tài khoản Windows là lộ cả chìa này — trong khi báo cáo chỉ cần đọc.
Chatbot dùng bi_fullCâu "20 khách mua nhiều nhất" trả về họ tên và SĐT thật, và chúng đi lên máy chủ AI bên ngoài — không thu hồi được. Trái cổng GATE D, phạm vi (c).
Chatbot dùng bi_reader luôn, bỏ claude_roMất 8 cài đặt an toàn gắn vào vai: một câu hỏi viết sai có thể chạy vô hạn, ghi file tạm không giới hạn ra đĩa, giữ khoá làm dbt đêm bị kẹt. Audit cũng không tách được câu của chatbot với câu của bản tin.
Bỏ nhóm bi_pii, cấp thẳng 6 bảng cho bi_fullChạy được, nhưng mỗi người mới được xem dữ liệu cá nhân phải cấp lại 6 bảng, và 6 model dbt phải cấp quyền cho một vai đăng nhập cụ thể mỗi đêm.

Phần 02

Vai nào thấy gì — một bảng

Đo bằng cách đóng vai thật (SET ROLE rồi đọc từng bảng), không bằng hàm hỏi quyền — hàm đó từng báo "có quyền" trong khi đọc thật thì bị từ chối (bẫy thiếu quyền vào schema, 17/09). Với claude_ro: đăng nhập thật từ máy chủ Windows, cổng 5433.


Vai Dữ liệu thô
raw, staging · 30
Vùng số liệu
mart + dq · 23
Vùng dữ liệu cá nhân
mart · 6
Đối chiếu chi tiết
dq · 3
Ghi / sửa / xoá Hàm lấy khoá đồng bộ
datahub✓✓✓✓✓✓
bi_full—✓✓———
bi_reader—✓————
claude_ro—✓————
bi_pii (nhóm)——✓———

✓ đọc / dùng được · — Postgres từ chối (mã 42501). Số dưới tên cột là số bảng / view trong vùng đó.

1Vùng số liệu (23) = 15 trong mart (dòng hàng, đơn không địa chỉ, thanh toán, hồ sơ khách giả danh — mã khách, giới tính, tỉnh, hạng thẻ —, các bảng tổng hợp bản tin) + 8 trong dq (cổng chất lượng). Sau quyết định "đường A" ngày 25/09, vùng này được phép đi lên máy chủ AI qua chatbot.
2Vùng dữ liệu cá nhân (6): dim_customer, dim_customer_pii (tên, SĐT, email, ngày sinh khách), fact_order (địa chỉ giao hàng), dim_salesperson, dim_salesperson_bi (họ tên nhân viên — dời vào đây sáng 26/09, quyết định D-1b = A2), và fact_order_line — bảng này không có dữ liệu cá nhân, được xếp vào vùng theo yêu cầu 22/09 để tra dòng hàng bằng DBeaver. Nên hiểu vùng này là "chỉ bi_full thấy", không phải "túi dữ liệu cá nhân".
3Đối chiếu chi tiết (3): dq_order_recon, dq_exception, dq_fk_check — mang mã khách từng đơn, chỉ datahub đọc. Số tổng của chúng có ở các bảng dq_*_tomtat trong vùng số liệu.
4Hàm lấy khoá đồng bộ: 16 hàm pg_advisory_lock / pg_try_advisory_lock… Trước 26/09 mọi vai gọi được; một câu của chatbot giành đúng khoá 91626 lúc 01:00 sẽ làm đồng bộ đêm bỏ lượt mà không báo. Đã thu hồi khỏi PUBLIC ngày 26/09 10:06 (quyết định D-3); chỉ ingest/sync.py dùng, bằng datahub là superuser nên không bị ảnh hưởng.

Phần 03

Năm vai của dự án — từng vai một

Mỗi vai: để làm gì, cái gì dùng nó, mật khẩu nằm đâu, sinh ra từ file nào, và lộ mật khẩu thì mất gì. Quyền đọc từng bảng không cấp tay: bảng trong kho được dbt dựng lại mỗi đêm, nên quyền được cấp lại bằng post_hook của từng model — đó là nguồn sự thật.


datahub — chủ nhà

Để làm gìVai duy nhất được ghi. Chủ database datahub, chủ 4 schema và cả 62 bảng / view (raw 16 · staging 14 · mart 21 · dq 11).
Thuộc tínhSUPERUSER · đăng nhập được · không giới hạn kết nối
Cái gì dùngĐồng bộ đêm ingest/sync.py + dbt run / dbt test (task 01:00) · task kiểm sức khoẻ 09/15/21h · script đo của agent (luôn trong giao dịch chỉ đọc)
Mật khẩu.env → PG_PASSWORD. Chuỗi ngẫu nhiên 32 ký tự từ lần xoay 22/09
Sinh ra từLúc khởi tạo container: POSTGRES_USER trong infra/docker-compose.yml
Lộ mật khẩu thìMất tất cả — đọc mọi dữ liệu cá nhân, sửa / xoá dữ liệu, tạo vai mới cho chính mình

bi_reader — vùng số liệu

Để làm gìĐọc 23 bảng / view (15 mart + 8 dq) — số liệu bán hàng, hồ sơ khách giả danh, cổng chất lượng. Không thấy tên, SĐT, email, địa chỉ khách; từ 26/09 08:11 cũng không thấy họ tên nhân viên.
Thuộc tínhĐăng nhập được · kiêm vai trò "nhóm": claude_ro và bi_full kế thừa quyền từ nó
Cái gì dùngBản tin doanh số Teams notify/teams_digest.py (task 07:00 / 09:30). Trước 22/09 Power BI cũng dùng vai này
Mật khẩu.env → BI_READER_PASSWORD. Do người đặt — độ mạnh chưa kiểm
Sinh ra từinfra/03_bi_reader.sql (mốc P2.2, 17/09) + post_hook "cấp cho bi_reader" ở 23 model dbt
Lộ mật khẩu thìMất vùng số liệu — toàn bộ doanh số từng dòng và hồ sơ khách giả danh; không ghi được, không thấy dữ liệu cá nhân

bi_pii — nhóm vùng dữ liệu cá nhân

Để làm gìGiữ quyền đọc 6 bảng chỉ bi_full được thấy (Phần 02, ghi chú 2)
Thuộc tínhKhông đăng nhập được, không có mật khẩu (đo: trường mật khẩu rỗng). Thành viên duy nhất: bi_full
Vì sao là nhómSáu bảng này bị dbt tạo lại mỗi đêm, quyền cũ mất theo. post_hook của 6 model cấp lại cho một tên cố định; muốn thêm người được xem dữ liệu cá nhân chỉ cần GRANT bi_pii TO … một lần
Sinh ra từinfra/05_pii_unlock.sql phần A (22/09, sau khi cổng GATE D được ký)
Lộ mật khẩu thìKhông có mật khẩu để lộ. Rủi ro là cấp nhầm thành viên — một dòng GRANT bi_pii TO claude_ro là dữ liệu cá nhân đi lên máy chủ AI

bi_full — người thấy tất cả trên máy

Để làm gì= bi_reader + bi_pii: đọc 29 bảng / view. Vẫn không đọc được dữ liệu thô và 3 bảng đối chiếu chi tiết; không ghi được
Thuộc tínhĐăng nhập được · thành viên của bi_reader và bi_pii
Cái gì dùngPower BI Desktop (từ 22/09 — đọc được view dữ liệu cá nhân dim_customer_pii) và DBeaver để tra cứu
Mật khẩu.env → BI_FULL_PASSWORD + kho credential của Power BI Desktop (hai mục nguồn: tên máy và địa chỉ IP loopback). Do người đặt — độ mạnh chưa kiểm
Sinh ra từinfra/05_pii_unlock.sql phần B (22/09)
Lộ mật khẩu thìMất dữ liệu cá nhân của 385.833 khách (tên, SĐT, email, ngày sinh, địa chỉ giao hàng) — nhưng không sửa hay xoá được gì. File .pbix cũng là một bản sao dữ liệu cá nhân: theo GATE D chỉ một người cầm

claude_ro — chatbot

Để làm gìCho chatbot hỏi số (P2.10, đường A) đọc đúng vùng bi_reader (23) — không hơn, không kém. Đo 26/09: tập đọc được của claude_ro trùng tập của bi_reader từng bảng
Thuộc tínhĐăng nhập được · tối đa 4 kết nối · chỉ là thành viên của bi_reader
8 cài đặt gắn vào vaiGiao dịch mặc định chỉ đọc · mỗi câu tối đa 60 giây · chờ khoá tối đa 3 giây · giao dịch bỏ quên bị ngắt sau 30 giây · không chạy song song · giờ Việt Nam · tên ứng dụng claude-mcp. Bảy cài đặt này là dây an toàn, không phải khoá: phiên nào cũng tự tắt được. Khoá thật là không có quyền ghi — đo: tự tắt chế độ chỉ đọc rồi thử tạo bảng vẫn bị từ chối 42501. Cài đặt thứ tám thì phiên không tự gỡ được: mỗi câu ghi file tạm ra đĩa tối đa 1 GB (quyết định D-10, đặt 26/09). Câu nặng nhất đã đo dùng chưa tới 40% mức đó; câu nào vượt thì dừng ngay, báo lỗi 53400
Cái gì dùngMáy chủ MCP bi/mcp/mcp_datahub_ro.py — chưa có ai dùng (bước 4.4 chưa làm)
Mật khẩu.env → CLAUDE_RO_PASSWORD + %APPDATA%\postgresql\pgpass.conf của tài khoản Windows của chủ dự án. Chuỗi ngẫu nhiên 32 ký tự, sinh 26/09 (không ai nhìn thấy, kể cả agent)
Sinh ra từinfra/04_claude_ro.sql, chạy 26/09 10:06 · nghiệm thu infra/04b_nghiemthu_claude_ro.py 10:07: 27/27 ô đạt
Lộ mật khẩu thìMất vùng số liệu như bi_reader — nhưng chỉ từ máy này (cổng chỉ nghe loopback) và tối đa 4 phiên cùng lúc

Phần 04

14 vai dựng sẵn — có sẵn, không dùng, đừng cấp

PostgreSQL 16 tạo sẵn các vai này để quản trị viên trao một nhóm quyền đặc biệt mà không phải cho superuser. Ở hub: cả 14 đều không đăng nhập được, và không vai nào của dự án là thành viên (đo pg_auth_members: quan hệ thành viên duy nhất giữa chúng là cấu trúc có sẵn — pg_monitor gộp quyền của 3 vai giám sát). Chúng vô hại chừng nào không ai GRANT chúng.


VaiCho phép gìNếu cấp nhầm cho vai báo cáo / chatbot
pg_read_all_dataĐọc mọi bảng, view, bỏ qua quyền từng bảngCao
xuyên thủng vùng dữ liệu cá nhân bằng một dòng
pg_write_all_dataGhi, sửa, xoá mọi bảngCao
pg_read_server_filesĐọc file bất kỳ trên máy chủ cơ sở dữ liệu (trong container)Cao
pg_write_server_filesGhi file trên máy chủ cơ sở dữ liệuCao
pg_execute_server_programChạy lệnh hệ điều hành trong containerCao
pg_signal_backendHuỷ truy vấn / ngắt phiên của vai thường khác (không đụng được superuser)TB
ngắt được bản tin, Power BI
pg_read_all_statsXem mọi thống kê, kể cả câu SQL đang chạy của vai khácTB
pg_monitorGộp pg_read_all_settings + pg_read_all_stats + pg_stat_scan_tables và các hàm giám sátTB
pg_stat_scan_tablesChạy hàm giám sát có thể giữ khoá đọc lâu trên bảngTB
có thể làm dbt đêm chờ
pg_create_subscriptionTạo đăng ký nhân bản dữ liệu sang máy khác (mới ở bản 16; cần thêm quyền tạo trên database)TB
pg_read_all_settingsĐọc mọi cài đặt, kể cả cài đặt thường chỉ superuser xemThấp
pg_checkpointRa lệnh ghi dồn dữ liệu xuống đĩa (CHECKPOINT)Thấp
pg_use_reserved_connectionsDùng các kết nối để dành (mới ở bản 16)Thấp
pg_database_ownerKhông cấp được. Thành viên ngầm là chủ database đang dùng — ở đây là datahub; sở hữu schema public—

Nếu có ai (người hay công cụ) đề xuất "cho claude_ro / bi_reader vai pg_read_all_data cho tiện" — từ chối. Quyền đó bỏ qua toàn bộ ranh giới ở Phần 02 mà không cần đụng tới bi_pii. Các file infra/*.sql không chặn được lúc cấp; chỉ lần chạy nghiệm thu infra/04b_nghiemthu_claude_ro.py kế tiếp mới thấy tập đọc được của claude_ro lệch khỏi bi_reader.

Phần 05

Đăng nhập từ đâu — và mật khẩu nằm ở đâu

Cùng một vai, đăng nhập từ hai chỗ khác nhau thì Postgres kiểm khác nhau. Luật nằm trong pg_hba.conf của container.


Kết nối từLuậtHệ quả
Bên trong container (docker exec … psql)trustKhông kiểm mật khẩu, vào được bằng bất kỳ vai nào kể cả datahub. Ai chạy được lệnh docker trên máy này là có toàn quyền hub
Máy chủ Windows qua loopback — Power BI, DBeaver, bản tin, chatbotscram-sha-256Phải đúng mật khẩu. Đo 26/09: sai mật khẩu → từ chối 28P01 sau 9 ms. Postgres thấy mọi kết nối này từ cùng một địa chỉ Docker gateway → không phân biệt được máy nguồn
Máy khác trong mạng / Internet—Không với tới: cổng chỉ mở trên loopback. Sẽ đổi ở Pha 7 (máy trạm, CEO hỏi qua VPN)

Mật khẩu từng vai nằm ở đâu

VaiKhoá trong .envNơi khácLoại mật khẩu
datahubPG_PASSWORD—Ngẫu nhiên 32 ký tự (xoay 22/09)
bi_readerBI_READER_PASSWORD—Người đặt · chưa kiểm độ mạnh
bi_fullBI_FULL_PASSWORDKho credential Power BI DesktopNgười đặt · chưa kiểm độ mạnh
claude_roCLAUDE_RO_PASSWORDpgpass.conf (tài khoản của chủ dự án)Ngẫu nhiên 32 ký tự (26/09)
bi_pii——Không có — không đăng nhập được

.env bị git chặn (không bao giờ vào repo), nhưng mọi tài khoản Windows trên máy đọc được nó (backlog ACL-THU-MUC-REPO, mức CAO). Hôm nay máy chỉ có một người dùng nên chưa gấp; phải khoá thư mục repo trước khi thêm tài khoản thứ hai. pgpass.conf thì nằm trong hồ sơ riêng của tài khoản Windows.

Tự đếm lại

SQL Liệt kê vai của dự án và vai chúng kế thừa
select r.rolname, r.rolsuper, r.rolcanlogin, r.rolconnlimit, (select string_agg(g.rolname, ', ') from pg_auth_members m join pg_roles g on g.oid = m.roleid where m.member = r.oid) as ke_thua from pg_roles r where r.rolname not like 'pg\_%' order by 1;

Phần 06

Sắp tới — và những điều không được làm

Danh sách vai sẽ còn đổi một lần nữa khi hub chuyển sang máy trạm và CEO hỏi chatbot từ máy riêng.


ViệcKhi nàoĐổi gì
Vai claude_ro_ceoPha 7, trên máy trạm (quyết định D-8 = C)Như claude_ro + ghi lại mọi câu SQL vào nhật ký Postgres, để phía máy trạm tách được câu CEO hỏi. Tổng số vai của dự án thành 6
Xoay mật khẩu mọi vai đăng nhậpTrước khi mở cổng ra VPN (bước 7.1b, D-9 = (i))bi_reader, bi_full đổi sang chuỗi ngẫu nhiên; nhập lại ở Power BI, DBeaver. Khi đó mọi vai đăng nhập đều thử được từ máy CEO — chỉ mật khẩu ngẫu nhiên chặn
Hoàn tác claude_ro nếu cầnBất cứ lúc nàorevoke bi_reader from claude_ro; drop role claude_ro; + trả quyền 16 hàm khoá cho PUBLIC (plan P2.10 §9)
Không GRANT bi_pii TO claude_ro — đó là đúng một dòng biến chatbot thành đường đưa dữ liệu cá nhân lên máy chủ AI. Muốn mở thì người ký GATE D phải sửa file cổng trước.
Không cấp vai pg_* nào ở Phần 04 cho vai báo cáo hay chatbot.
Không đưa mật khẩu datahub cho công cụ báo cáo, DBeaver dùng hằng ngày, hay chatbot. Máy chủ MCP tự từ chối nếu kết nối bằng superuser hoặc vai thuộc bi_pii.
Không kiểm quyền bằng has_table_privilege() — nó trả "có" cả khi thiếu quyền vào schema. Kiểm bằng SET ROLE … rồi đọc thật.
Không cấp quyền bảng trực tiếp trong psql rồi coi là xong — bảng được dựng lại mỗi đêm, quyền cấp tay mất sau 01:00. Quyền phải đi qua thành viên nhóm hoặc post_hook của dbt.

Phần 07

Tóm lại

19 vai nghe nhiều, nhưng 14 là vai có sẵn của PostgreSQL không ai dùng. Năm vai của dự án là năm ranh giới: ghi (datahub) · số liệu (bi_reader) · dữ liệu cá nhân (bi_pii) · người xem tất cả (bi_full) · chatbot (claude_ro).

62bảng / view, tất cả do vai chủ nhà sở hữu
29bảng / view nhiều nhất một vai không phải superuser đọc được
23bảng / view chatbot đọc được — bằng đúng vùng số liệu
0vai của dự án là thành viên một vai dựng sẵn

Phản biện cho chính thiết kế này

1datahub là một chìa vạn năng dùng cho mọi việc chạy tự động và cho script của agent; mật khẩu của nó nằm trong .env mà mọi tài khoản Windows đọc được. Tách vai "nạp dữ liệu thô" khỏi vai "dựng kho" sẽ giảm thiệt hại khi lộ — đổi lại thêm một mật khẩu phải bàn giao. Chưa đề xuất làm trước khi chuyển máy.
2bi_reader vừa là vai đăng nhập của bản tin, vừa là nhóm cho chatbot kế thừa: ai có mật khẩu bi_reader đọc được đúng vùng của chatbot nhưng không có 8 cài đặt an toàn. Tách một nhóm không đăng nhập riêng cho "vùng số liệu" thì sạch hơn, nhưng phải sửa post_hook của 23 model — chưa đáng với 2 người dùng.
3Ranh giới giữ bằng quyền, nhưng bên trong container thì không kiểm mật khẩu. Mọi thứ trên trang này đứng trên giả định: chỉ chủ máy chạy được docker.
← Về tài liệu chính: Kiến trúc SIXDO Data Hub