DataOps nâng cao 28 — Tự động hoá quản trị: Policy-as-code
Quản trị không phải tài liệu, mà là code chạy trong pipeline
Ở nhiều tổ chức, "governance" là một thư mục SharePoint đầy chính sách PDF mà không ai đọc, cộng với một hội đồng phê duyệt họp hai tuần một lần để gác cổng thủ công. Kết quả có thể đoán trước: chính sách và thực tế lệch nhau, người làm data đi vòng cho kịp deadline, và khi thanh tra NHNN hỏi "bảng chứa CMND của khách hàng được mã hoá và giới hạn quyền như thế nào", câu trả lời là một cuộc rà soát thủ công kéo dài nhiều tuần.
Bài này lật ngược cách tiếp cận đó. Governance automation nghĩa là biến chính sách dữ liệu thành quy tắc máy kiểm được (machine-checkable rules), nhúng vào CI và nền tảng, để mỗi thay đổi được kiểm tự động, vi phạm bị chặn trước khi lên production, và mọi thứ đều có bằng chứng để giải trình. Trong ngân hàng, đây không phải xa xỉ mà là điều kiện sống còn: rủi ro rò rỉ PII, phạt tuân thủ và mất uy tín đều đắt hơn nhiều so với chi phí tự động hoá.
Bài kế thừa nền tảng self-service ở DataOps nâng cao 7 — Platform & self-service, quality/contract ở DataOps nâng cao 5 — Quality & contracts, và các chủ đề quản trị nền ở Governance — Tổng quan.
Compliance-as-code / Policy-as-code
Ý tưởng trung tâm: viết chính sách thành quy tắc executable, chạy trong CI/pipeline để chặn vi phạm thay vì phát hiện sau. Một chính sách "as-code" tốt phải: (1) diễn đạt được ý định nghiệp vụ, (2) máy kiểm được không mơ hồ, (3) chạy nhanh trong CI, (4) cho thông báo lỗi rõ ràng để người sửa được.
Vài chính sách điển hình cho một warehouse ngân hàng:
| Chính sách | Quy tắc máy kiểm | Hành vi khi vi phạm |
|---|---|---|
| Mọi cột PII phải có tag và masking | model chứa cột nhạy cảm phải khai meta.pii: true + policy tag | CI fail |
| Không bảng nào public | không grant PUBLIC/allUsers trên schema/table | CI fail, block deploy |
| Model phải có owner, description, test | mọi model có meta.owner, description, ≥1 test | CI fail |
| Naming convention | staging stg_, marts dim_/fct_, không tên viết tắt tuỳ ý | CI warn/fail |
| Retention khai báo | mọi bảng có meta.retention_days | CI fail nếu thiếu |
| Không PII ở tầng public mart | cột pii: true không được materialize ở schema báo cáo | CI fail |
Công cụ
- OPA / Rego (Open Policy Agent): engine policy tổng quát. Ta xuất metadata (dbt
manifest.json, danh sách grants, mô tả hạ tầng dưới dạng JSON) rồi viết rule Rego đánh giá. Mạnh khi chính sách cắt ngang nhiều hệ (data + hạ tầng + CI). - dbt project evaluator: package dbt kiểm best-practice — model thiếu test/description, source không dùng, cấu trúc DAG sai tầng, model không có owner. Chạy như một phần của
dbt build. - dbt-checkpoint: pre-commit hooks kiểm nhanh trên diff (model mới phải có description, có test, có tag) — bắt lỗi ngay lúc commit, trước cả CI.
- Custom checks: script Python đọc
manifest.json/catalog.jsoncho luật đặc thù NCB mà công cụ chuẩn không có (ví dụ: cột khớp danh mục PII nội bộ phải có masking policy tương ứng).
Ví dụ rule Rego chặn bảng public (minh hoạ, không phải block chạy được):
package datawarehouse.grants
# deny nếu có bất kỳ grant nào tới PUBLIC
deny[msg] {
some g
input.grants[g].grantee == "PUBLIC"
msg := sprintf("Cấm grant PUBLIC trên %v", [input.grants[g].object])
}
# deny nếu bảng gắn pii=true nhưng thiếu masking policy
deny[msg] {
some t
input.tables[t].meta.pii == true
not input.tables[t].masking_policy
msg := sprintf("Bảng PII %v thiếu masking_policy", [input.tables[t].name])
}
Ví dụ khai báo policy trong dbt (minh hoạ) — model được coi là "đủ điều kiện governance" nhờ metadata bắt buộc:
# models/marts/customer/dim_customer.yml (minh hoạ)
models:
- name: dim_customer
description: "Dimension khách hàng, khoá theo customer_id"
meta:
owner: "team-huy-dong@ncb"
pii: true
retention_days: 3650
classification: "restricted"
columns:
- name: national_id
meta: { pii: true, policy_tag: "PII.NATIONAL_ID" }
tests: [not_null]
tests:
- dbt_utils.expression_is_true:
expression: "national_id is null or masked = true"
Ví dụ cấu hình dbt_project.yml cho dbt project evaluator (minh hoạ) — bật kiểm owner và test coverage:
vars:
dbt_project_evaluator:
documentation_coverage_target: 95
test_coverage_target: 90
models_without_owner_severity: error
Metadata-driven governance: phân loại & gắn tag tự động
Con người không thể gắn tag tay cho hàng nghìn cột — và sẽ quên. Cách bền vững là quét cột tự động để phát hiện dữ liệu nhạy cảm rồi gắn tag, sau đó để tag lan truyền theo lineage.
Phân loại tự động: một scanner định kỳ quét tên cột + mẫu dữ liệu mẫu, so với danh mục PII (regex cho số CMND/CCCD 9–12 số, số điện thoại 0[0-9]{9}, email, số thẻ). Cột khớp được đề xuất tag pii, classification. Với ngân hàng nên để scanner đề xuất và người phê duyệt hàng loạt, tránh false positive gắn nhầm cột account_balance là PII.
Tag lan truyền theo lineage: nếu stg_customers.national_id là PII, mọi cột phái sinh trực tiếp từ nó trong dim_customer, mart_kyc cũng được đánh dấu PII tự động. Đây là chỗ lineage sinh từ dbt (column-level lineage) trả cổ tức: policy không phải khai lại ở từng tầng, mà chảy theo dữ liệu.
Access control theo tag (tag-based access): quyền không gắn vào từng bảng thủ công mà gắn vào tag. "Ai được đọc cột tag PII.NATIONAL_ID" định nghĩa một lần; mọi cột mang tag đó tự động thừa hưởng luật. Thêm cột PII mới → tự động được bảo vệ, không cần nhớ cấp/thu quyền.
Governance ở ranh giới: data contract
Nơi dễ mất kiểm soát nhất là ranh giới giữa các domain: một domain đổi schema, domain hạ nguồn vỡ; hoặc PII rò sang một data product không được phép nhận. Data contract biến giao diện dữ liệu thành hợp đồng máy kiểm được: schema, kiểu, ràng buộc chất lượng, và phân loại nhạy cảm của từng trường.
Contract cho phép nhúng governance ngay tại điểm trao đổi: contract khai national_id là PII.restricted, thì CI của bên tiêu thụ có thể từ chối nếu data product của họ là tầng public. Chi tiết cơ chế contract ở DataOps nâng cao 5 — Quality & contracts; ở quy mô nhiều domain, mô hình phân quyền governance liên bang (federated) xem DataOps nâng cao 14 — Data Mesh at scale.
Chính sách truy cập là code: grants, masking, RLS
Cấp quyền bằng tay qua UI là nguồn lỗi kinh điển: cấp rồi quên thu, cấp nhầm role, không ai biết ai có quyền gì. Grants-as-code đưa toàn bộ ma trận quyền vào Git, review qua PR, áp qua CI — đúng tinh thần Governance — Access control.
# access/roles.yml (minh hoạ)
roles:
analyst_huy_dong:
read: [marts.dim_customer, marts.fct_deposit]
masked_columns: [dim_customer.national_id, dim_customer.phone]
compliance_officer:
read: [marts.*]
unmasked_columns: [dim_customer.national_id] # có mục đích KYC hợp pháp
- Masking as code: cột PII định nghĩa masking policy trong code; role thường thấy dữ liệu che (
***), chỉ role có mục đích hợp pháp (KYC, điều tra gian lận) mới thấy rõ. Áp bằng migration versioned, không sửa tay trên warehouse. - RLS (Row-Level Security) as code: giới hạn dòng theo vai trò — ví dụ chi nhánh chỉ thấy khách của chi nhánh mình. Luật RLS là code, được test tự động.
Toàn bộ được kiểm bởi policy-as-code: một rule Rego xác minh không có role nào đọc được cột PII mà không có masking, không role nào ngoài whitelist unmask được national_id.
Audit & lineage tự động phục vụ giải trình
Governance không dừng ở "chặn được vi phạm" — phải chứng minh được ta kiểm soát. Ba thứ cần tự động:
- Audit log truy cập: ai đọc bảng nào, khi nào, cột nào (đặc biệt cột PII). Log tập trung, bất biến, giữ theo retention.
- Lineage tự động: sinh từ dbt (không khai tay), trả lời "dữ liệu này từ đâu, chảy đi đâu" — cần khi báo cáo sự cố rò rỉ hoặc chứng minh phạm vi ảnh hưởng.
- Change history: mọi thay đổi policy/grant/schema là commit Git — ai đổi, khi nào, được ai duyệt.
Khi thanh tra hỏi "cột CMND được bảo vệ ra sao", câu trả lời là: policy-as-code này (link commit), grants-as-code này, audit log 12 tháng này, lineage này — thay vì một cuộc rà soát thủ công. Chi tiết catalog/lineage/audit xem Governance — Tổng quan.
Nhúng tuân thủ NĐ13/NHNN vào pipeline
Nghị định 13/2023/NĐ-CP về bảo vệ dữ liệu cá nhân và các quy định NHNN đặt ra nghĩa vụ về consent (đồng ý), mục đích xử lý, retention (lưu trữ), quyền xoá. Governance automation nhúng các nghĩa vụ này thành kiểm tra tự động (chi tiết pháp lý ở Governance — Privacy & compliance):
- Consent & mục đích: mỗi bảng PII khai
purpose(mục đích thu thập); pipeline nào dùng dữ liệu ngoài mục đích đã khai → CI cảnh báo. Bản ghi thiếu consent flag không được đưa vào mart marketing. - Retention: mọi bảng PII bắt buộc khai
retention_days; một job tự động phát hiện/che/xoá bản ghi quá hạn; policy-as-code fail nếu bảng thiếu khai báo. - Quyền xoá (right to erasure): có quy trình xoá/che theo
customer_idchảy qua mọi hệ (nhờ lineage), và test tự động xác nhận sau khi xử lý không còn dấu vết ở tầng phân tích.
SQL: một CHECK governance tự động
Dưới đây là một check governance có thể chạy trực tiếp trên sandbox: quét bảng customers phát hiện giá trị giống PII (số điện thoại / CMND) lọt vào cột full_name — dấu hiệu dữ liệu bẩn hoặc phân loại sai cần cảnh báo. Loại check này chạy định kỳ trong pipeline như một data-quality/governance gate.
-- ▶ Chạy được
SELECT id, full_name, created_at
FROM customers
WHERE full_name ~ '[0-9]{9,12}'
OR full_name ~ '0[0-9]{9}'
ORDER BY created_at DESC;
Câu trên trả về các bản ghi khách hàng mà trường tên chứa chuỗi số dài giống CMND/CCCD (9–12 số) hoặc số điện thoại di động (0 + 9 số) — những giá trị đáng lẽ không được nằm ở cột tên. Trong CI, biến thể của nó có thể chạy dưới dạng test dbt: nếu COUNT(*) > 0 thì fail và chặn deploy.
Governance by default trên nền tảng self-service
Cách bền vững nhất không phải kiểm ở cuối, mà làm cho con đường dễ nhất cũng là con đường tuân thủ. Golden path ở DataOps nâng cao 7 — Platform & self-service đã nhúng sẵn: template dbt có macro mã hoá PII, cấu hình mặc định gắn owner/retention, CI mặc định chạy policy-as-code, mọi model tự đăng ký catalog.
Khi domain dùng golden path, họ tuân thủ mà không phải cố gắng. Policy-as-code khi đó không phải rào cản khó chịu mà là lưới an toàn — bắt trường hợp domain đi lệch đường. Đây cũng là góc DevSecOps của dữ liệu, tương đồng công cụ ở Security — DevSecOps tooling.
Đo lường & cân bằng kiểm soát với tốc độ
Governance tự động phải đo được, nếu không sẽ trôi:
| Chỉ số | Ý nghĩa | Mục tiêu |
|---|---|---|
| % model có owner | Trách nhiệm rõ ràng | 100% |
| % cột PII đã gắn tag | Phủ phân loại | > 95% |
| % model có test + description | Chất lượng + tài liệu | > 90% |
| Số vi phạm bị CI chặn/tháng | Lưới an toàn hoạt động | Theo dõi xu hướng |
| Số bảng public ngoài ý muốn | Rò rỉ tiềm tàng | 0 |
| Thời gian policy check trong CI | Không làm chậm dev | < 2 phút |
Nguyên tắc cân bằng cốt lõi: không gác cổng thủ công. Hội đồng phê duyệt họp hai tuần một lần giết tốc độ và không thực sự an toàn hơn — con người rà tay bỏ sót nhiều hơn máy. Thay vào đó: chính sách rõ ràng thành code, kiểm tự động tức thì trong CI, chỉ những ngoại lệ hiếm (đi lệch golden path) mới cần con người xem. Đây là cách vừa nhanh vừa kiểm soát chặt — đúng tinh thần DataOps áp cho quản trị.
Use case thực tế
NCB xây một data product mart_kyc phục vụ đội tuân thủ, chứa national_id, phone, full_name của khách hàng. Trước đây quy trình là: đội huy động tự dựng bảng, mở ticket nhờ platform cấp quyền, và mỗi quý một cuộc rà soát thủ công kiểm PII — mất trung bình 3 tuần/data product và vẫn sót lỗi (một lần national_id lọt sang mart marketing không mã hoá).
Sau khi áp governance automation:
- Ngày 1 — Analyst tạo model từ golden path. dbt-checkpoint (pre-commit) chặn ngay commit vì model thiếu
descriptionvàowner; sửa trong 2 phút. - CI trên PR — dbt project evaluator + custom check chạy 90 giây: phát hiện
national_idlà PII (khớp danh mục) nhưng thiếu masking policy → chặn PR với thông báo rõ. Analyst thêmmeta: { pii: true, policy_tag: "PII.NATIONAL_ID" }; masking tự áp qua tag. - Rego check — xác minh không grant PUBLIC, chỉ role
compliance_officerunmask đượcnational_id. Grants-as-code merge qua PR, áp tự động. - Sau merge — Lineage tự sinh; tag PII lan truyền; audit log bật. Retention 3650 ngày khai trong
meta, job xoá quá hạn tự chạy.
Kết quả sau 6 tháng: time-to-first-pipeline giảm từ ~3 tuần xuống < 1 ngày; 0 bảng public ngoài ý muốn; 98% model có owner + tag; 47 vi phạm bị CI chặn trước production (trước đây sẽ lọt và phát hiện muộn). Khi NHNN thanh tra bảo vệ dữ liệu cá nhân, đội cung cấp policy-as-code, grants-as-code, audit log và lineage trong 1 ngày thay vì nhiều tuần rà tay.
Ghi nhớ
- Governance là code chạy trong CI/nền tảng, không phải tài liệu tĩnh hay hội đồng gác cổng thủ công.
- Policy-as-code: viết chính sách (PII có tag/masking, không bảng public, model có owner/test, naming, retention) thành rule máy kiểm được — OPA/Rego, dbt project evaluator, dbt-checkpoint, custom check — chặn vi phạm trong CI.
- Metadata-driven: quét cột phân loại PII tự động, tag lan truyền theo lineage, access control gắn theo tag (thêm cột PII mới tự được bảo vệ).
- Grants/masking/RLS as code: ma trận quyền trong Git, review qua PR, áp qua migration — không sửa tay trên warehouse.
- Audit + lineage tự động để giải trình ai/gì/khi nào; nhúng kiểm tra NĐ13/NHNN (consent, mục đích, retention, quyền xoá).
- Governance by default trên golden path: con đường dễ nhất cũng tuân thủ sẵn; policy-as-code là lưới an toàn cho trường hợp đi lệch.
- Đo lường (% owner/tag/test, số vi phạm bị chặn, số bảng public) và cân bằng: tự động thay cho gác cổng thủ công — vừa nhanh vừa kiểm soát chặt.
Bài viết liên quan
CSV/JSON/Parquet/Avro, lưu trữ theo hàng vs cột, nén, và OLTP vs OLAP.
Data Engineering là gì, vai trò trong vòng đời dữ liệu, và bức tranh hệ sinh thái công cụ.
Vì sao xử lý phân tán, mô hình Spark (RDD/DataFrame), lazy evaluation, shuffle và tối ưu.
Đảm bảo chất lượng & minh bạch dữ liệu bằng dbt: data tests dựng sẵn (unique, not_null, relationships, accepted_values), singular test, unit test, và tài liệu tự sinh kèm lineage graph.