Bỏ qua và tới nội dung chính
Thiết kế contract và DSL

Policy và RBAC nên được biểu diễn thế nào trong contract

Policy và RBAC chỉ nên xuất hiện trong contract dưới dạng quy tắc có thể thi công, kiểm tra và truy vết. Một contract tốt không ôm hết mọi thứ, cũng không mô tả lại code; nó khóa đúng phạm vi, đúng ngôn ngữ và làm cho đầu ra ít bất ngờ hơn.

Huỳnh Kim Đạt Huỳnh Kim Đạt
11 lượt xem 8 phút đọc
Policy và RBAC nên được biểu diễn thế nào trong contract

TL;DR

Policy và RBAC nên được biểu diễn trong contract dưới dạng rule có cấu trúc gồm role, action, resource, condition, effect và scope. Hãy tách rõ domain, workflow, policy và API contract để có thể thi công, kiểm thử và truy vết thay vì viết mô tả chung chung hoặc bám quá sát implementation.

Key Takeaways

  • RBAC chỉ là một phần của policy; policy rộng hơn và phải mô tả điều kiện, phạm vi và hiệu lực.
  • Contract nên tách rõ các lớp domain, app, rule, workflow, policy và API.
  • Policy contract cần có cấu trúc rõ: role, resource, action, condition, effect, scope.
  • Workflow và policy phải liên kết để quyền được hiểu đúng theo trạng thái xử lý.
  • Contract tốt giúp sinh test, audit và traceability; contract tệ chỉ tạo thêm giấy tờ.

Policy và RBAC nên được biểu diễn thế nào trong contract

Khi nói về policyRBAC trong contract, sai lầm phổ biến nhất là biến contract thành một bộ tài liệu dài, đầy khẩu hiệu, nhưng không đủ cấu trúc để đội kỹ thuật thi công. Ở chiều ngược lại, cũng có nhiều contract đi quá sát implementation, mô tả lại từng if-else trong code, khiến contract nhanh lỗi thời ngay khi hệ thống thay đổi. Cách tiếp cận đúng là biểu diễn policy và RBAC như những quy tắc có thể đọc được, kiểm tra được và truy vết được.

Với các hệ thống theo hướng contract-first, software factory, hay DSL contract như Midi Coder theo đuổi, contract không phải giấy tờ trang trí. Nó là điểm nối giữa nghiệp vụ, workflow, rule engine, API contract và cơ chế phân quyền. Vì vậy, policy và RBAC cần được đặt vào đúng lớp, đúng mức trừu tượng.

Các lớp contract cốt lõi cần tách rõ

Một contract tốt thường không dồn mọi thứ vào một chỗ. Nên tách các lớp sau để tránh lẫn ngôn ngữ và tránh mâu thuẫn:

  • Domain contract: mô tả thực thể, trạng thái, thuộc tính, ràng buộc nghiệp vụ cốt lõi.
  • App contract: mô tả hành vi ở mức ứng dụng, use case, command, query, entry point.
  • Rule contract: mô tả các điều kiện và hệ quả có tính quyết định, có thể kiểm tra được.
  • Workflow contract: mô tả các bước, transition, điều kiện chuyển trạng thái và actor tham gia.
  • Policy contract: mô tả chính sách truy cập, giới hạn hành vi, nghĩa vụ kiểm soát, phạm vi áp dụng.
  • API contract: mô tả interface đầu vào, đầu ra, schema, error, versioning.

Nếu trộn lẫn các lớp này, tài liệu sẽ rất khó dùng. Ví dụ, policy không nên bị chôn trong mô tả endpoint, còn RBAC không nên chỉ được viết như một ghi chú rời rạc trong workflow.

Policy và RBAC nên nằm ở đâu

RBAC là mô hình phân quyền theo vai trò. Policy là tập quy tắc xác định ai được làm gì, trong điều kiện nào, trên tài nguyên nào, với giới hạn nào. RBAC có thể là một phần của policy, nhưng policy rộng hơn RBAC.

Trong contract, nên biểu diễn:

  • Role: ai là tác nhân hợp lệ trong hệ thống.
  • Resource: đối tượng bị tác động.
  • Action: thao tác được phép hoặc bị cấm.
  • Condition: điều kiện ngữ cảnh để quyền có hiệu lực.
  • Effect: allow, deny, require-approval, mask, audit-only.
  • Scope: phạm vi áp dụng theo tenant, phòng ban, dự án, dữ liệu sở hữu, trạng thái hồ sơ.

Nói ngắn gọn: RBAC định nghĩa khung vai trò; policy định nghĩa luật thực thi.

Khóa phạm vi và ngôn ngữ để contract có thể dùng cho thi công

Một contract hữu dụng phải giới hạn phạm vi biểu đạt. Nếu cho phép mô tả policy bằng văn xuôi tự do, đội triển khai sẽ phải tự diễn giải. Nếu bám chặt vào framework cụ thể, contract sẽ mất tính bền vững.

Cách tốt là dùng ngôn ngữ DSL ngắn gọn, có cấu trúc, ví dụ:

resource: invoice
actions: [create, read, update, approve, export]
roles:
  accountant: [create, read, update]
  manager: [read, approve]
  auditor: [read, export]
policies:
  - effect: allow
    role: accountant
    action: update
    when: resource.status in [draft, rejected] and resource.owner_department = user.department
  - effect: allow
    role: manager
    action: approve
    when: resource.total_amount <= user.approval_limit
  - effect: deny
    action: export
    when: resource.contains_sensitive_data = true and user.clearance != high

Điểm quan trọng không phải cú pháp YAML hay JSON, mà là contract phải ép được các thành phần chính: actor, action, resource, condition, effect. Khi đó, policy có thể được dùng để sinh kiểm tra, sinh test, map sang middleware, audit log hoặc tài liệu API.

Phần nào nên viết ngắn, phần nào bắt buộc phải rõ

Nên viết ngắn ở các phần:

  • Mục tiêu tổng quát của policy.
  • Nguyên tắc thiết kế như least privilege, deny by default.
  • Ghi chú giải thích bối cảnh nghiệp vụ.

Bắt buộc phải rõ và có cấu trúc ở các phần:

  • Danh sách role chuẩn và ý nghĩa từng role.
  • Danh sách action có kiểm soát quyền.
  • Resource nào thuộc phạm vi policy.
  • Điều kiện áp dụng quyền hoặc từ chối quyền.
  • Quan hệ giữa policy và workflow state.
  • Quy tắc ưu tiên khi nhiều policy xung đột.
  • Yêu cầu audit, traceability, logging.

Nếu các phần bắt buộc này chỉ được viết bằng mô tả tự do như “quản lý có thể duyệt khi cần thiết”, contract gần như không thể thi công thống nhất.

Policy phải gắn với workflow, không đứng riêng

Rất nhiều hệ thống mô tả RBAC tách rời luồng xử lý, dẫn tới quyền nhìn thì đúng nhưng chạy thực tế lại sai. Ví dụ, quyền approve không chỉ phụ thuộc role manager mà còn phụ thuộc trạng thái chứng từ, hạn mức duyệt và phạm vi sở hữu dữ liệu.

Do đó, workflow contract và policy contract phải liên kết với nhau. Một transition chỉ hợp lệ khi:

  • Actor có role phù hợp.
  • Policy cho phép action ở trạng thái hiện tại.
  • Các điều kiện dữ liệu được thỏa mãn.
  • Nghĩa vụ hậu kiểm như audit hoặc notification được khai báo rõ.

Đây là điểm quan trọng trong các hệ thống cần traceability: từ một hành động trong UI hay API, có thể lần ngược về rule nào, policy nào và contract nào đã cho phép hành động đó.

Lỗi thường gặp

1. Contract ôm hết mọi thứ

Khi một contract cố gắng chứa toàn bộ business logic, UI text, chi tiết database, framework config và policy cùng lúc, nó sẽ trở nên cồng kềnh và mâu thuẫn. Contract lúc đó không còn là nguồn sự thật rõ ràng.

2. Contract bám sát code quá mức

Nếu contract viết theo kiểu “gọi hàm A, check biến B, qua middleware C”, nó chỉ là ảnh chụp implementation. Khi code refactor, contract lập tức lỗi thời dù nghiệp vụ không đổi.

3. Chỉ mô tả role mà không mô tả điều kiện

Viết “manager được duyệt đơn” là chưa đủ. Duyệt đơn nào, trong trạng thái nào, với hạn mức nào, trên tenant nào? Không có điều kiện thì RBAC chỉ là danh sách vai trò không dùng được.

4. Không định nghĩa ưu tiên giữa allow và deny

Policy thực tế luôn có ngoại lệ. Nếu không có quy tắc ưu tiên, cùng một action có thể vừa được phép vừa bị cấm tùy người đọc.

5. Không có mapping giữa contract và kiểm thử

Một policy contract tốt nên dẫn được tới test case: ai, ở trạng thái nào, với dữ liệu nào, thì được hay không được thực hiện hành động nào.

Ví dụ contract tệ

Managers can approve documents.
Admins can do everything.
Users can edit their own data when appropriate.
Sensitive data should be protected.

Đây là contract tệ vì:

  • Mơ hồ về resource và action.
  • Không có condition.
  • Không có scope.
  • Không định nghĩa “appropriate” hay “sensitive”.
  • Không thể sinh test hay truy vết quyết định phân quyền.

Ví dụ contract tốt

roles:
  - employee
  - manager
  - admin
resource: leave_request
actions:
  - create
  - read
  - update
  - submit
  - approve
  - reject
policy_rules:
  - id: PR-001
    effect: allow
    role: employee
    action: [create, read, update, submit]
    scope: own_resource
    when: resource.status in [draft, rejected]
  - id: PR-002
    effect: allow
    role: manager
    action: [read, approve, reject]
    scope: same_department
    when: resource.status = pending and resource.total_days <= user.approval_limit_days
  - id: PR-003
    effect: deny
    role: manager
    action: approve
    when: resource.requester_id = user.id
  - id: PR-004
    effect: allow
    role: admin
    action: [read]
    scope: all
obligations:
  - audit on approve
  - notify requester on reject
conflict_resolution: deny_overrides

Contract này tốt hơn vì nó trả lời được các câu hỏi cốt lõi: ai, làm gì, với cái gì, trong điều kiện nào, trên phạm vi nào, và khi xung đột thì xử lý ra sao.

Gợi ý thiết kế cho Midi Coder và mô hình contract-first

Nếu đi theo hướng contract coding hoặc software factory, hãy xem policy và RBAC là một phần của chuỗi hợp đồng có thể thực thi:

  • Domain contract xác định resource và state.
  • Workflow contract xác định transition.
  • Policy contract xác định actor nào được kích hoạt transition nào.
  • API contract xác định nơi transition được gọi và schema cần thỏa mãn.
  • Traceability map liên kết rule ID, endpoint, test case và audit event.

Cách làm này đặc biệt phù hợp với DSL contract vì mỗi rule đều có thể mang mã định danh riêng, giúp theo dõi thay đổi và impact analysis tốt hơn.

Kết luận

Policy và RBAC trong contract không nên được viết như khẩu hiệu quản trị, cũng không nên bị kéo xuống mức code cụ thể. Chúng nên được biểu diễn như những quy tắc có cấu trúc, đủ ngắn để dễ đọc nhưng đủ chặt để thi công, kiểm thử và truy vết. Một contract tốt không phải contract dài nhất; đó là contract làm cho code đầu ra ít bất ngờ hơn.

Frequently Asked Questions

RBAC có đủ để biểu diễn phân quyền trong contract không?

Không hẳn. RBAC chỉ trả lời ai thuộc vai trò nào, còn policy cần mô tả thêm action, resource, condition, scope và hiệu lực như allow hoặc deny.

Policy nên viết ở mức business hay mức code?

Nên viết ở mức quy tắc có thể thi công, không quá mơ hồ như business note, cũng không gắn chặt vào framework hay hàm cụ thể trong code.

Vì sao policy cần gắn với workflow contract?

Vì nhiều quyền chỉ hợp lệ ở một số trạng thái hoặc transition nhất định. Tách rời workflow khỏi policy dễ tạo ra quyền đúng trên giấy nhưng sai khi chạy thực tế.

Một policy contract tốt có cần traceability không?

Có. Mỗi rule nên có định danh và có thể liên kết tới endpoint, test case, audit event hoặc yêu cầu nghiệp vụ tương ứng.