Software Architecture

Zero Trust Architecture: Tại sao không nên tin tưởng bất kỳ service nào bên trong hệ thống

7/19/2026 · 12p đọc


title: "Zero Trust Architecture: Tại sao không nên tin tưởng bất kỳ service nào bên trong hệ thống"
series: "Software Architecture Masterclass"
part: "Phần 4 — Bảo mật & Chất lượng"
order: 32
audience: "Solutions Architect & Technical Lead"
reading_time: "12 phút"
tags: ["zero-trust", "mTLS", "security", "network-security", "lateral-movement", "service-mesh"]

Zero Trust Architecture: Tại sao không nên tin tưởng bất kỳ service nào bên trong hệ thống

Có một câu nói vô hại nhưng nguy hiểm bậc nhất trong review kiến trúc: "cái này gọi nội bộ trong VPC thôi, không cần auth đâu". Nó nghe hợp lý — traffic không ra khỏi mạng riêng, không đi qua Internet công cộng, vậy thì tin ai nếu không tin chính hàng xóm trong cùng một khu vườn? Nhưng chính câu nói đó là lý do một breach nhỏ ở một service phụ (một job xử lý ảnh, một webhook receiver ít người để ý) biến thành một sự cố toàn hệ thống chỉ sau vài giờ.

Bài này không nói về firewall hay VPC configuration theo nghĩa kỹ thuật thuần túy. Nó nói về một giả định kiến trúc đã lỗi thời — "vị trí mạng = mức độ tin cậy" — và cái giá phải trả khi giả định đó bị một kẻ tấn công khai thác từ bên trong, sau khi đã vượt qua chu vi (perimeter) một lần duy nhất.

The Problem

Mô hình bảo mật truyền thống — thường gọi là "castle-and-moat" (lâu đài và hào nước) — xây một chu vi cứng ở biên: firewall, security group, VPC boundary, WAF (Web Application Firewall) ở cổng vào. Mọi thứ bên ngoài chu vi bị coi là thù địch và phải qua kiểm tra nghiêm ngặt. Mọi thứ bên trong chu vi — service-to-service, database, internal API — được tin tưởng gần như mặc định, bởi vì "nó đã ở trong rồi".

Hệ quả trực tiếp của giả định này: traffic giữa các internal service thường đi qua HTTP thuần (không mã hóa), không có xác thực lẫn nhau, chỉ dựa vào việc IP nguồn nằm trong dải subnet nội bộ hoặc security group cho phép. Một service gọi service khác không cần chứng minh "tôi là ai" — nó chỉ cần chứng minh "tôi đến từ đúng mạng con".

Vấn đề nảy sinh khi chu vi bị xuyên thủng — và nó luôn bị xuyên thủng, chỉ là vấn đề thời gian. Một dependency có lỗ hổng (supply-chain attack), một credential bị lộ trong log, một container image bị chèn mã độc, một nhân viên bị phishing lấy được VPN access — bất kỳ điểm vào nào cũng đủ để kẻ tấn công đặt chân vào bên trong mạng nội bộ. Một khi đã ở trong, với mô hình castle-and-moat, kẻ tấn công gần như có toàn quyền: mọi service nội bộ đều "tin" nó chỉ vì nó đang gọi từ một IP nội bộ hợp lệ.

Đây gọi là lateral movement (di chuyển ngang) — kẻ tấn công không cần khai thác thêm lỗ hổng nào nữa, chỉ cần đi từ service này sang service khác bằng chính sự tin tưởng ngầm mà kiến trúc đã cấp sẵn. Một service xử lý upload ảnh bị chiếm quyền có thể gọi thẳng tới service thanh toán, service quản lý người dùng, hay database chứa PII (Personally Identifiable Information) — không phải vì nó có quyền hợp pháp, mà vì không ai từng hỏi nó có quyền hay không. Bán kính thiệt hại (blast radius) của một breach nhỏ mở rộng ra toàn bộ hệ thống, chỉ vì chu vi là tuyến phòng thủ duy nhất.

The Theory

Zero Trust (không tin tưởng ngầm định) là một mô hình kiến trúc bảo mật dựa trên nguyên lý được diễn đạt gọn nhất bằng cụm "never trust, always verify" (không bao giờ tin tưởng, luôn luôn xác minh). Nguyên lý này không quan tâm request đến từ đâu về mặt mạng — Internet công cộng hay cùng một pod trong cùng một cluster Kubernetes đều bị đối xử như nhau: mọi request phải được xác thực (authentication — chứng minh danh tính) và ủy quyền (authorization — chứng minh có quyền) một cách tường minh, mỗi lần, bất kể vị trí mạng.

Ba trụ cột của Zero Trust:

1. Xác thực danh tính mạnh cho mọi thực thể, kể cả service-to-service. Không chỉ người dùng cuối cần đăng nhập — mỗi service, mỗi workload, mỗi job nền cũng cần một danh tính mật mã học (cryptographic identity) để chứng minh nó là chính nó. Cơ chế phổ biến nhất cho tầng service-to-service là mTLS (mutual TLS) — cả hai phía của một kết nối đều trình chứng chỉ (certificate) để xác thực lẫn nhau, thay vì chỉ server trình chứng chỉ cho client như HTTPS thông thường.

2. Ủy quyền theo nguyên tắc least privilege (đặc quyền tối thiểu), đánh giá tại mỗi lần gọi. Một service chỉ được cấp đúng quyền nó cần cho đúng hành động đang thực hiện — không phải quyền theo kiểu "đã ở trong mạng nội bộ thì được phép gọi mọi service". Quyết định ủy quyền không được cache vĩnh viễn dựa trên một lần xác thực ban đầu; nó cần được đánh giá lại (hoặc ít nhất kiểm tra token còn hiệu lực) ở mỗi lời gọi, vì ngữ cảnh có thể thay đổi (service bị thu hồi quyền, chứng chỉ bị revoke).

3. Giả định vi phạm đã xảy ra (assume breach). Đây là điểm khác biệt triết học lớn nhất so với castle-and-moat. Zero Trust không thiết kế với niềm tin "chu vi sẽ giữ vững" — nó thiết kế với giả định ngược lại: kẻ tấn công đã ở bên trong, câu hỏi là hắn có thể đi được bao xa. Mọi kiểm soát — segmentation (phân đoạn mạng nhỏ), logging chi tiết từng lời gọi, giới hạn quyền theo từng service — đều nhằm mục đích giảm tối đa bán kính thiệt hại khi (chứ không phải nếu) một điểm nào đó bị xâm nhập.

Về mặt triển khai thực tế, Zero Trust không phải một sản phẩm mua về cài đặt — nó là một tập hợp nguyên tắc thường được hiện thực hóa qua: service mesh (lớp hạ tầng quản lý giao tiếp service-to-service, tự động hóa mTLS và policy) như một lựa chọn phổ biến, identity provider cấp danh tính ngắn hạn cho workload (thay vì credential tĩnh nhúng cứng), và policy engine đánh giá quyền theo ngữ cảnh (ai, gọi gì, từ đâu, khi nào) thay vì chỉ theo IP nguồn.

The Trade-off

Đây là phần không được phép mơ hồ: Zero Trust không phải một nâng cấp miễn phí. Nó đánh đổi độ đơn giản vận hành và độ trễ lấy khả năng giới hạn thiệt hại.

Được gì:

  • Bán kính thiệt hại bị giới hạn nghiêm ngặt. Một service bị chiếm quyền chỉ có đúng quyền nó được cấp tường minh — không thể tự do gọi sang service khác chỉ vì cùng nằm trong VPC. Kẻ tấn công phải vượt qua thêm một lớp xác thực/ủy quyền ở mỗi bước di chuyển ngang, thay vì đi tự do sau một lần xâm nhập.
  • Khả năng audit và phát hiện bất thường tăng vọt. Vì mọi request đều được xác thực và log tường minh theo danh tính (không chỉ theo IP), việc phát hiện một service đang gọi sai pattern (ví dụ service upload ảnh bỗng gọi service thanh toán) trở nên khả thi — điều mà mô hình castle-and-moat gần như không nhìn thấy được, vì traffic nội bộ không được ghi log chi tiết theo danh tính.
  • Kiến trúc trở nên bền vững hơn trước các mô hình hạ tầng hiện đại. Cloud-native, multi-cloud, hay hạ tầng có nhiều bên thứ ba (nhà thầu phụ, đối tác tích hợp) khiến khái niệm "chu vi mạng rõ ràng" ngày càng mờ nhạt — không còn một "bên trong" đáng tin cậy duy nhất để bảo vệ. Zero Trust không phụ thuộc vào việc vẽ được ranh giới đó.

Mất gì — và đây là phần không được phép né tránh:

  • Độ trễ tăng ở mọi lời gọi, không phải một lần. Mỗi request service-to-service giờ phải qua bắt tay TLS song phương (nếu chưa có kết nối được giữ ấm — connection pooling), kiểm tra chứng chỉ, có thể gọi thêm tới policy engine để đánh giá ủy quyền. Trong một hệ thống có chuỗi gọi sâu (service A gọi B gọi C gọi D), độ trễ cộng dồn từ các lớp xác thực này có thể trở thành khoản chi phí đáng kể, đặc biệt với các đường dẫn nhạy cảm về độ trễ (real-time bidding, matching engine).
  • Độ phức tạp vận hành tăng đáng kể. Quản lý vòng đời chứng chỉ (cấp phát, xoay vòng — rotation, thu hồi — revocation) cho hàng trăm service là một bài toán vận hành riêng, không tầm thường. Nếu không tự động hóa tốt, một chứng chỉ hết hạn không được xoay vòng kịp thời có thể gây outage diện rộng — chính cơ chế được thiết kế để tăng bảo mật lại trở thành một điểm lỗi (failure mode) mới.
  • Chi phí phát triển ban đầu và đường cong học tập dốc hơn. Team phát triển phải hiểu và tích hợp thêm một lớp xác thực vào mọi service mới, thay vì chỉ viết business logic và tin tưởng network layer đã lo phần bảo mật. Điều này làm chậm tốc độ ra tính năng ban đầu, đặc biệt với team nhỏ chưa có hạ tầng service mesh hay policy engine sẵn có.
  • Debug và troubleshooting khó hơn. Khi một request thất bại, nguyên nhân có thể là logic nghiệp vụ, hoặc có thể là chứng chỉ hết hạn, policy bị cấu hình sai, hoặc identity provider tạm thời không phản hồi. Zero Trust thêm một tầng có thể gây lỗi (failure surface) mới cần được quan sát (bài 28 — Observability) một cách tường minh, nếu không đội vận hành sẽ mất nhiều thời gian phân biệt "lỗi nghiệp vụ" với "lỗi hạ tầng bảo mật".
  • Không loại bỏ hoàn toàn rủi ro — chỉ giới hạn nó. Zero Trust giảm bán kính thiệt hại, nhưng không phải phép màu: nếu một service bị chiếm quyền và nó thực sự có quyền hợp pháp gọi tới một service nhạy cảm (vì nghiệp vụ yêu cầu), Zero Trust không ngăn được việc đó — nó chỉ đảm bảo các service không có quyền hợp pháp không thể bị lợi dụng. Thiết kế phân quyền đúng (least privilege thực sự, không phải least privilege trên giấy) vẫn là điều kiện tiên quyết, không phải hệ quả tự động của việc bật mTLS.

Nói ngắn gọn: castle-and-moat đơn giản hơn, nhanh hơn, rẻ hơn để xây ban đầu — nhưng đặt cược toàn bộ vào một giả định duy nhất (chu vi sẽ giữ vững) mà lịch sử breach cho thấy giả định đó gần như luôn sai sớm hay muộn. Zero Trust trả giá bằng độ trễ và độ phức tạp vận hành mỗi ngày, để đổi lấy việc một sai lầm không biến thành thảm họa toàn hệ thống.

The Architecture Diagram

Sơ đồ dưới đây so sánh trực tiếp hai mô hình: bên trái là castle-and-moat (chu vi kiểm soát, nội bộ tin tưởng ngầm), bên phải là Zero Trust (mọi lời gọi service-to-service đều xác thực bằng mTLS và được policy engine đánh giá).

flowchart TB
    subgraph OLD["Mô hình chu vi truyền thống (Castle-and-Moat)"]
        direction TB
        EXT1["Traffic bên ngoài"] -->|"kiểm tra nghiêm ngặt"| FW1["Firewall / WAF<br/>(chu vi duy nhất)"]
        FW1 --> GW1["API Gateway"]
        GW1 -->|"HTTP thuần, không auth"| SVC_A1["Service A<br/>(Upload/Media)"]
        SVC_A1 -->|"tin tưởng ngầm vì cùng VPC"| SVC_B1["Service B<br/>(User Profile)"]
        SVC_B1 -->|"tin tưởng ngầm"| SVC_C1["Service C<br/>(Payment)"]
        SVC_A1 -.->|"⚠ breach tại đây"| ATT1(["Kẻ tấn công"])
        ATT1 -.->|"di chuyển ngang tự do<br/>không bị chặn"| SVC_B1
        ATT1 -.->|"di chuyển ngang tự do"| SVC_C1
        ATT1 -.->|"truy cập trực tiếp"| DB1[("Database<br/>PII + giao dịch")]
    end

    subgraph NEW["Mô hình Zero Trust"]
        direction TB
        EXT2["Traffic bên ngoài"] -->|"kiểm tra"| FW2["Firewall / WAF"]
        FW2 --> GW2["API Gateway<br/>(xác thực người dùng)"]
        GW2 -->|"mTLS + policy check"| SVC_A2["Service A<br/>(Upload/Media)<br/>identity: svc-media"]
        SVC_A2 -->|"mTLS + verify identity<br/>+ check policy"| PE["Policy Engine<br/>(ai, gọi gì, quyền gì)"]
        PE -->|"deny: svc-media<br/>không có quyền gọi payment"| SVC_C2["Service C<br/>(Payment)<br/>identity: svc-payment"]
        SVC_A2 -->|"mTLS + policy: allow<br/>(đúng scope nghiệp vụ)"| SVC_B2["Service B<br/>(User Profile)<br/>identity: svc-profile"]
        SVC_B2 -->|"mTLS + verify identity"| DB2[("Database<br/>PII + giao dịch<br/>chỉ nhận kết nối có identity hợp lệ")]
        SVC_A2 -.->|"⚠ breach tại đây"| ATT2(["Kẻ tấn công"])
        ATT2 -.->|"BỊ CHẶN: không có<br/>chứng chỉ mTLS hợp lệ<br/>để giả danh svc-payment"| SVC_C2
    end

Điểm khác biệt cốt lõi nằm ở nửa dưới mỗi sơ đồ: trong mô hình cũ, một breach tại Service A cho phép kẻ tấn công đi xuyên suốt hệ thống chỉ vì nó đã "ở trong". Trong mô hình Zero Trust, cùng một breach tại Service A bị chặn ngay ở lời gọi kế tiếp — vì kẻ tấn công không có chứng chỉ mTLS hợp lệ để giả danh một service khác, và policy engine từ chối bất kỳ quyền nào ngoài scope nghiệp vụ thực sự của service đó.

Implementation Guardrails

  1. mTLS giữa mọi service nội bộ là mức tối thiểu bắt buộc, không phải tùy chọn nâng cao. Không có ngoại lệ "service này chạy nội bộ nên dùng HTTP thuần cho nhanh" — mọi kết nối service-to-service, kể cả giữa hai service trong cùng một cluster, cùng một subnet, phải qua mTLS. Ngoại lệ đầu tiên được chấp nhận sẽ trở thành tiền lệ cho mọi ngoại lệ sau đó.
  2. Không service nào được tin tưởng một request chỉ dựa trên nguồn gốc mạng (IP, subnet, security group). Việc kiểm tra "request đến từ dải IP nội bộ hợp lệ" không phải là xác thực — nó chỉ là một tín hiệu bối cảnh yếu, dễ giả mạo một khi kẻ tấn công đã có chỗ đứng bên trong mạng. Danh tính phải được xác minh bằng chứng chỉ mật mã học hoặc token có chữ ký, không bằng vị trí mạng.
  3. Chứng chỉ và token phải có thời gian sống ngắn và tự động xoay vòng. Credential tĩnh, không hết hạn, cấu hình cứng trong biến môi trường là bề mặt tấn công lớn nhất trong một hệ thống Zero Trust không hoàn chỉnh. Chứng chỉ ngắn hạn (vài giờ đến vài ngày) tự động cấp lại qua identity provider giới hạn thời gian một credential bị lộ có thể bị lợi dụng.
  4. Policy phải được định nghĩa theo nguyên tắc least privilege tường minh cho từng service, không phải một policy mặc định "allow all trong nội bộ". Mỗi service chỉ được khai báo đúng danh sách service nó cần gọi và hành động cụ thể — mọi lời gọi ngoài danh sách đó bị từ chối mặc định (deny-by-default), không phải chấp nhận mặc định (allow-by-default) rồi chặn từng trường hợp phát hiện được sau này.

Architect's Verdict

Zero Trust giờ là kỳ vọng mặc định cho bất kỳ hệ thống nào xử lý dữ liệu nhạy cảm — tài chính, y tế, thông tin định danh cá nhân — không còn là một lựa chọn nâng cao dành riêng cho các tổ chức lớn có ngân sách bảo mật dư dả. Một kiến trúc chỉ dựa vào bảo mật chu vi là một khoản nợ kỹ thuật đang âm thầm tích lũy lãi suất, không phải một khoản tiết kiệm chi phí — nó chỉ chưa đến hạn trả. Nếu ngân sách và thời gian có hạn, đừng cố Zero Trust hóa toàn bộ hệ thống trong một lần; bắt đầu từ những service chạm vào dữ liệu nhạy cảm nhất và đường đi ngắn nhất tới chúng, rồi mở rộng dần — một Zero Trust triển khai từng phần nhưng đúng ưu tiên vẫn tốt hơn một kế hoạch "Zero Trust toàn diện" nằm mãi trên giấy.

🔗 Bài viết liên quan: Security by Design · Identity & Access Management (IAM)


Bài trước: Security by Design · Bài tiếp theo: Identity & Access Management (IAM)

Zero Trust Architecture: Tại sao không nên tin tưởng bất kỳ service nào bên trong hệ thống