186 lines
14 KiB
Markdown
186 lines
14 KiB
Markdown
# ADR-015 — Xác thực service-to-service bằng Service JWT ngắn hạn
|
||
|
||
*Tên file: `adr/ADR-015_service-jwt-xac-thuc-service-to-service.md`*
|
||
|
||
| | |
|
||
|---|---|
|
||
| **Status** | `Proposed` |
|
||
| **Date** | 2026-09-15 |
|
||
| **Người quyết** | Security (chưa có người — `OQ-007`) + Tech Lead (bảo mật — `decision-radar.md §5`; Security có quyền phủ quyết cuối cùng) — chưa ký thật |
|
||
| **Người đề xuất** | SA (qua skill `sa-2-architecture`, hoạt động `adr`) |
|
||
| **Điểm radar** | **5/10** *(chấm theo `decision-radar.md §2`, kế thừa nguyên ước lượng đã ghi ở `SEC_e-commerce_v1.0.md §2.4`: Chi phí đảo ngược=1 (1–3 tuần — đổi cơ chế sau khi đã code tốn sửa cả hai đầu gọi) · Bán kính ảnh hưởng=2 (mọi lời gọi cross-network nội bộ TB3/TB4 + tiền lệ cho các `IF` tương lai) · Chạm `QAS` Must=1 (gián tiếp `QAS-002`/`QAS-010` — thêm bước xin token có thể ăn vào ngân sách latency đã eo hẹp, cần đo lại) · Ràng buộc dài hạn=1 (chuẩn nội bộ cho service-to-service, trong một release) · Tranh cãi=0 → **5 ⇒ `ADR` bắt buộc** (5–7), dưới ngưỡng 8 nên không bắt buộc POC, nhưng cần đo lại latency overhead trước khi `Accepted`)* |
|
||
| **Supersedes** | — |
|
||
| **Superseded by** | — |
|
||
| **Liên quan** | `ASR-002` · `ASR-007` · `QAS-002` · `QAS-010` · `THR-09` · `THR-13` · `SEC_e-commerce_v1.0.md §1 (TB3/TB4)`, `§2.4` · `SAD_e-commerce_v1.0.md §7` (ràng buộc không thêm hạ tầng mới) · `ADR-002` · `ADR-007` · `ADR-012` · `OQ-050` · `DEC-28` |
|
||
|
||
> ⚠️ **ADR bất biến sau khi `Accepted`.** Muốn đổi quyết định thì viết ADR mới có
|
||
> `Supersedes: ADR-015` và đổi trạng thái bản cũ thành `Superseded by`. Không sửa nội dung ADR
|
||
> đã `Accepted`, không xoá ADR đã `Rejected`.
|
||
|
||
---
|
||
|
||
## 0. Ghi chú Preflight & ngoại lệ gate
|
||
|
||
Viết cùng lượt với `ADR-014`/`ADR-016`/`ADR-017` dưới ngoại lệ gate ghi ở `DEC-31` (tiếp nối
|
||
`DEC-01…30`) — xem `ADR-014 §0` cho bối cảnh đầy đủ. Riêng `ADR-015`: hiện thực hoá hướng **PA-3**
|
||
đã chọn TẠM ở `SEC_e-commerce_v1.0.md §2.4` (duyệt từng phần, `DEC-28`).
|
||
|
||
🔴 **Lưu ý quan trọng nhất của ADR này:** đây là quyết định **bảo mật** — theo `decision-radar.md
|
||
§5`, loại quyết định này do **Security chốt**, không phải Tech Lead hay SA. Security **hiện chưa
|
||
có người được chỉ định** (`OQ-007`, mở từ GĐ1). ADR này **không thể chuyển `Accepted`** cho tới
|
||
khi có đại diện Security thật ký — bất kể Tech Lead có đồng ý nội dung hay không, đúng nguyên tắc
|
||
"Security có quyền phủ quyết AG2" (`sa-2-architecture/SKILL.md`, hoạt động 6). Người dùng (vai
|
||
điều phối dự án chạy thử) đã được cảnh báo lại và **khẳng định muốn tiếp tục** dưới ngoại lệ.
|
||
|
||
---
|
||
|
||
## 1. Bối cảnh
|
||
|
||
`SEC_e-commerce_v1.0.md §1`/`§2.4` phát hiện một khoảng trống: hai ranh giới cross-network nội bộ
|
||
— TB3 (Nhóm Giao dịch ↔ Nhóm Hỗ trợ, `IF-021`/`IF-022`) và TB4 (Cart & Order → Payment, `IF-006`,
|
||
**ranh giới nhạy cảm nhất vì Payment giữ tiền thật**, `ASR-002`) — hiện **chỉ dựa vào network
|
||
reachability** (security group VPC), không có cơ chế xác thực danh tính bên gọi. `THR-09` và
|
||
`THR-13` (Spoofing, mức 🔴) ghi rõ: một service khác trong cùng VPC (kể cả bị compromise) có thể
|
||
giả danh gọi thẳng các endpoint này nếu security group cấu hình sai.
|
||
|
||
`SAD_e-commerce_v1.0.md §7` (v1.2) đã đặt một ràng buộc rõ ràng: **không tự thêm hạ tầng mới**
|
||
(VD internal ALB/App Mesh) vào sơ đồ ở lượt thiết kế này — mọi hạ tầng mới là một quyết định kiến
|
||
trúc riêng, ngoài phạm vi. Điều này loại trực tiếp phương án service mesh/mTLS đầy đủ trừ khi có
|
||
một `ADR` riêng chấp nhận thêm hạ tầng.
|
||
|
||
**Ràng buộc đang chi phối:**
|
||
|
||
| Nguồn | Nội dung |
|
||
|---|---|
|
||
| `ASR-002` | Payment Service cô lập PCI-DSS SAQ A — TB4 là ranh giới nhạy cảm nhất |
|
||
| `ASR-007` | Chỗ ra quyết định ownership/authz — mở rộng tinh thần sang cả xác thực giữa các service nội bộ |
|
||
| `SAD §7` (v1.2) | Không tự thêm hạ tầng mới ngoài phạm vi thiết kế hiện tại |
|
||
| `CON-05` | Đội vận hành chưa xác nhận có kinh nghiệm vận hành hạ tầng phân tán phức tạp (service mesh) |
|
||
|
||
**Cái đã biết chắc / cái còn là giả định:**
|
||
|
||
| Điều | 🟢 Đã kiểm chứng / 🔴 Giả định | Bằng chứng |
|
||
|---|---|---|
|
||
| Hạ tầng ký/verify JWT của Identity & Access (`CMP-02`) đã tồn tại cho xác thực người dùng cuối | 🟢 Đã kiểm chứng | `SEC §2` |
|
||
| Thêm 1 bước xin/verify service token không ăn quá nhiều vào ngân sách latency `QAS-002`/`QAS-010` | 🔴 Giả định mới — cần đo lại | Chưa đo — GĐ3 |
|
||
| AWS Cloud Map + ECS Service Connect (đã chốt ở `INF §3`, mức `DEC`, không `ADR`) tương thích với việc đính kèm header service JWT ở tầng ứng dụng | 🟢 Đã kiểm chứng (đây là 2 lớp độc lập — network discovery vs application-layer auth) | `INF §3` |
|
||
|
||
## 2. Phương án đã cân nhắc
|
||
|
||
### PA-1 — Chỉ dựa network (security group)
|
||
|
||
| | |
|
||
|---|---|
|
||
| **Mô tả** | Giữ nguyên hiện trạng — không thêm cơ chế xác thực nào giữa các service nội bộ |
|
||
| **Ưu** | Không tốn công triển khai |
|
||
| **Nhược** | Không đáp ứng "defense in depth" cho dữ liệu PII/tiền đi qua TB3/TB4; một security group cấu hình sai = không còn ranh giới nào; không giảm thiểu `THR-09`/`THR-13` |
|
||
| **Chi phí đảo ngược** | Thấp về kỹ thuật, nhưng để lại `THR-09`/`THR-13` ở mức 🔴 không giảm thiểu — rủi ro bảo mật tồn đọng |
|
||
|
||
### PA-2 — mTLS qua service mesh (AWS App Mesh/Private CA)
|
||
|
||
| | |
|
||
|---|---|
|
||
| **Mô tả** | Mỗi ECS task có chứng chỉ riêng, xác thực lẫn nhau ở tầng TLS |
|
||
| **Ưu** | Mạnh nhất, chuẩn ngành cho zero-trust nội bộ |
|
||
| **Nhược** | Thêm hạ tầng mới (App Mesh) — **mâu thuẫn trực tiếp** với ràng buộc đã ghi ở `SAD §7` v1.2 ("không tự thêm hạ tầng mới ngoài phạm vi"); đội chưa xác nhận có kinh nghiệm vận hành mesh (`CON-05`) |
|
||
| **Chi phí đảo ngược** | Cao — triển khai rồi tháo dỡ mesh tốn nhiều tuần, ảnh hưởng mọi service |
|
||
|
||
### PA-3 — Service JWT ngắn hạn ký bởi Identity & Access *(chọn)*
|
||
|
||
| | |
|
||
|---|---|
|
||
| **Mô tả** | Mỗi service tự xin "service token" (JWT riêng, `sub=service-name`, TTL ngắn ~5 phút, đề xuất) từ Identity & Access qua IAM role (không cần secret tĩnh), đính kèm header khi gọi `IF-006`/`IF-021`/`IF-022`; bên nhận verify chữ ký giống verify JWT người dùng (tái dùng hạ tầng ký/verify đã có) |
|
||
| **Ưu** | Không cần hạ tầng mới ngoài quy ước header + logic verify (tái dùng key JWT của `CMP-02`); tương thích với ràng buộc "không thêm hạ tầng mới" của `SAD §7`; nâng được một lớp phòng thủ so với hiện trạng thuần network |
|
||
| **Nhược** | Cần Identity & Access cấp phát token cho service (thêm luồng nội bộ mới, nhỏ); vẫn phụ thuộc network layer làm lớp phòng thủ đầu (không phải mTLS zero-trust đầy đủ); thêm 1 round-trip xin token có thể ăn vào ngân sách latency (cần đo lại) |
|
||
| **Chi phí đảo ngược** | Trung bình (1–3 tuần) — đổi cơ chế sau khi đã code cả hai đầu gọi (bên gửi xin token, bên nhận verify) tốn sửa cả hai phía |
|
||
|
||
### Bảng so sánh
|
||
|
||
| Tiêu chí | PA-1 | PA-2 | PA-3 |
|
||
|---|---|---|---|
|
||
| Giảm thiểu `THR-09`/`THR-13` (Spoofing) | ❌ Không | ✅ Mạnh nhất | ✅ Có (một lớp phòng thủ bổ sung) |
|
||
| Tương thích ràng buộc `SAD §7` (không thêm hạ tầng mới) | ✅ | ❌ Vi phạm trực tiếp | ✅ |
|
||
| Tương thích năng lực đội hiện tại (`CON-05`) | ✅ | 🔴 Chưa xác nhận có kinh nghiệm | ✅ Tái dùng hạ tầng JWT sẵn có |
|
||
| Chi phí đảo ngược | Thấp (nhưng để lại rủi ro) | Cao | Trung bình |
|
||
|
||
## 3. Quyết định
|
||
|
||
> **Chọn PA-3 — Service JWT ngắn hạn ký bởi Identity & Access, giữ nguyên security group làm lớp
|
||
> phòng thủ đầu.**
|
||
|
||
**Vì sao:** Đây là phương án duy nhất vừa nâng được một lớp phòng thủ thật sự (giảm thiểu
|
||
`THR-09`/`THR-13`) vừa **không vi phạm** ràng buộc đã ghi ở `SAD §7` v1.2 ("không tự thêm hạ tầng
|
||
mới ngoài phạm vi") và không đòi hỏi năng lực vận hành mesh mà đội chưa xác nhận có (`CON-05`).
|
||
|
||
**Phạm vi áp dụng:** Mọi lời gọi cross-network nội bộ giữa các nhóm triển khai — hiện tại là TB3
|
||
(`IF-021`/`IF-022`) và TB4 (`IF-006`); áp dụng cho mọi `IF` cross-network tương lai theo cùng
|
||
chuẩn (thiết lập tiền lệ).
|
||
|
||
### Điều kiện chuyển `Proposed → Accepted`
|
||
|
||
| Điều kiện | Ai xác nhận | Trạng thái hiện tại |
|
||
|---|---|---|
|
||
| **Có đại diện Security thật ký** — đây là quyết định bảo mật, Security có quyền phủ quyết | Security | 🔴 **Chặn cứng — chưa có người** (`OQ-007`, mở từ GĐ1) |
|
||
| Tech Lead xác nhận hướng PA-3 (không đổi sang PA-2 mTLS) | Tech Lead | Mở (`OQ-050` chưa đóng) |
|
||
| Đo lại latency overhead của bước xin/verify token, xác nhận không ăn quá nhiều vào ngân sách `QAS-002`/`QAS-010` | Tech Lead + QA | Chưa chạy — GĐ3 |
|
||
|
||
## 4. Phương án bị loại và lý do
|
||
|
||
| Phương án | Loại vì | Gắn với | Điều kiện nào thì xét lại |
|
||
|---|---|---|---|
|
||
| PA-1 — Chỉ dựa network | Không giảm thiểu `THR-09`/`THR-13` (Spoofing mức 🔴) — để lại rủi ro bảo mật đã biết mà không có biện pháp bổ sung | `ASR-002`, `THR-13` | Không xét lại — đây là hiện trạng đã bị đánh giá không đủ |
|
||
| PA-2 — mTLS/App Mesh | Vi phạm trực tiếp ràng buộc `SAD §7` v1.2 ("không tự thêm hạ tầng mới ngoài phạm vi"); đội chưa xác nhận có kinh nghiệm vận hành mesh (`CON-05`) | `SAD §7`, `CON-05` | Xét lại nếu tổ chức cần zero-trust đầy đủ hơn (VD mở rộng nhiều team/service hơn đáng kể) **và** có `ADR` riêng chấp nhận thêm hạ tầng mesh, **và** đội xác nhận đủ năng lực vận hành |
|
||
|
||
## 5. Hệ quả
|
||
|
||
**Hệ quả tích cực**
|
||
|
||
- Nâng một lớp phòng thủ thật sự cho TB3/TB4 (giảm thiểu `THR-09`/`THR-13`), thay vì chỉ dựa
|
||
network reachability
|
||
- Không cần hạ tầng mới — tái dùng hạ tầng ký/verify JWT sẵn có của Identity & Access
|
||
- Thiết lập một chuẩn chung cho mọi `IF` cross-network tương lai
|
||
|
||
**Hệ quả tiêu cực phải sống chung**
|
||
|
||
- Identity & Access cần thêm luồng cấp phát service token (endpoint/logic mới, dù nhỏ)
|
||
- Thêm 1 round-trip mạng (xin token) có thể ăn vào ngân sách latency vốn đã eo hẹp
|
||
(`QAS-002`/`QAS-010`) — cần đo lại trước khi `Accepted`
|
||
- Vẫn phụ thuộc network layer làm lớp phòng thủ đầu — không phải zero-trust đầy đủ như mTLS
|
||
|
||
**Cái quyết định này khoá lại**
|
||
|
||
| Muốn đổi về sau thì | Tốn |
|
||
|---|---|
|
||
| Đổi sang mTLS/App Mesh sau này | Cần viết `ADR` mới chấp nhận thêm hạ tầng, triển khai mesh, đào tạo đội vận hành — nhiều tuần |
|
||
|
||
**Việc phát sinh**
|
||
|
||
| Việc | Chủ | Hạn | Ghi ở đâu |
|
||
|---|---|---|---|
|
||
| Identity & Access thiết kế endpoint/logic cấp service token | Dev (Identity & Access) | Trước khi Dev thi công TB3/TB4 | Thiết kế chi tiết thuộc GĐ3 |
|
||
| Đo lại latency overhead trên đường găng checkout | SA/QA (GĐ3) | Trước go-live | `FAIL`/`FIT` GĐ3 |
|
||
| Viết `FIT-31` thật (service-authn test) | QA/Dev (GĐ3) | GĐ3 | `03-enablement/FIT_e-commerce.md` |
|
||
|
||
## 6. Cách kiểm chứng quyết định này được tuân thủ
|
||
|
||
| Cách kiểm | Công cụ | Chạy ở đâu | `FIT` |
|
||
|---|---|---|---|
|
||
| Gọi `IF-006`/`IF-021`/`IF-022` không có service JWT hợp lệ (thiếu, hết hạn, hoặc sai chữ ký) bị từ chối | Integration test | CI + staging | `FIT-31` *(ứng viên, đã đề xuất ở `SEC §11`)* |
|
||
| Đo p95 latency đường găng checkout với bước xin/verify token, xác nhận vẫn ≤ ngân sách `QAS-002` | Load test (k6) | Staging | Ứng viên bổ sung — cùng nhóm `FIT-23/24/25` của `ADR-013` |
|
||
|
||
## 7. Điều kiện xét lại
|
||
|
||
| Dấu hiệu | Ngưỡng | Ai theo dõi |
|
||
|---|---|---|
|
||
| Latency overhead đo được ăn quá nhiều vào margin `QAS-002` (margin còn lại theo `ADR-013` ~1.280–1.880ms) | Overhead > 100ms p95 (đề xuất, chưa xác nhận) | Tech Lead |
|
||
| Tổ chức mở rộng nhiều team/service hơn đáng kể, cần zero-trust đầy đủ | Số service cross-network > gấp đôi hiện tại (2 ranh giới TB3/TB4) | Tech Lead + Security |
|
||
|
||
## 8. Tham chiếu
|
||
|
||
- POC: Không bắt buộc (radar 5/10, dưới ngưỡng 8) — nhưng khuyến nghị đo lại latency trước khi
|
||
`Accepted`
|
||
- Bài đo: `FIT-31` (ứng viên GĐ3)
|
||
- Tài liệu ngoài: —
|
||
- Thảo luận: `SEC_e-commerce_v1.0.md §2.4` (phát hiện + đề xuất), `THR-09`/`THR-13`,
|
||
`OQ-050`/`DEC-28` (chọn hướng TẠM)
|