Chương 38. Service-to-service security

Hai chương trước nói về:

Authentication:
  Bạn là ai?

Authorization:
  Bạn được làm gì?

Nhưng ta chủ yếu nói về user.

Trong hệ thống thật, không chỉ user gọi backend.

Còn có:

  • Service gọi service.
  • Worker gọi API nội bộ.
  • Cron job gọi endpoint.
  • Webhook từ bên thứ ba.
  • API gateway gọi backend service.
  • File service gọi permission service.
  • Grading service gọi submission service.
  • Billing service gọi notification service.
  • Monitoring system gọi health endpoint.

Vì vậy cần hỏi:

Khi một service gọi service khác, service nhận request có biết ai đang gọi không?

Thông điệp chính của chương:

> Internal network không tự động an toàn. Service-to-service call cũng cần xác thực, phân quyền, quản lý secret, rotation, logging, và giới hạn quyền.

---

38.1. Ví dụ dễ hiểu: nhân viên nội bộ không phải ai cũng vào được kho

Một công ty có nhiều phòng ban.

Nhân viên đều ở trong cùng một tòa nhà.

Nhưng không có nghĩa là:

Ai cũng được vào phòng tài chính.
Ai cũng được mở kho.
Ai cũng được ký hợp đồng.
Ai cũng được xem hồ sơ nhân sự.

"Ở trong nội bộ" không đủ.

Vẫn cần:

  • Thẻ.
  • Quyền.
  • Nhật ký vào/ra.
  • Hạn mức.
  • Kiểm tra khi vào khu nhạy cảm.

Service cũng vậy.

Chạy trong cùng VPC/Kubernetes cluster không có nghĩa là mọi service được gọi mọi API.

---

38.2. Service-to-service security là gì?

Service-to-service security là bảo vệ các cuộc gọi giữa các service.

Nó trả lời:

Service A có thật là Service A không?
Service A có được gọi endpoint này không?
Request có bị sửa trên đường đi không?
Secret có bị lộ không?
Nếu key bị lộ thì revoke/rotate thế nào?
Gọi sai quá nhiều có bị rate limit không?

Ví dụ:

Grading Service -> Submission Service
File Service -> Permission Service
Billing Service -> Notification Service
Webhook Provider -> Backend

Mỗi cuộc gọi cần mức bảo vệ phù hợp.

Không phải tất cả đều cần mTLS phức tạp.

Nhưng cũng không nên để:

Ai gọi endpoint nội bộ cũng được.

---

38.3. Vì sao internal network không đủ?

Nhiều người nghĩ:

Endpoint này chỉ chạy trong mạng nội bộ, nên an toàn.

Điều này nguy hiểm.

Vì nội bộ vẫn có thể bị:

  • Một service bị hack.
  • SSRF từ web app gọi vào internal endpoint.
  • Credential bị lộ.
  • Developer gọi nhầm endpoint.
  • Pod/container khác trong cluster truy cập được.
  • Misconfigured firewall/security group.
  • Log hoặc dashboard lộ URL nội bộ.
  • CI/CD job có quyền mạng rộng.

Khi một service bị chiếm, attacker có thể di chuyển ngang sang service khác.

Đây gọi là lateral movement.

Vì vậy:

> Network boundary là một lớp bảo vệ, không phải toàn bộ bảo mật.

---

38.4. Một ví dụ AI Judge rất thật

AI Judge có các service:

API Service
Submission Service
Grading Service
File Service
Notification Service
Billing/Usage Service

Grading Service cần lấy file bài nộp.

Nó gọi:

GET /internal/submissions/{id}/file

Nếu endpoint này chỉ kiểm tra:

Request đến từ mạng nội bộ.

thì rủi ro là:

Một service khác trong nội bộ có thể gọi và lấy file submission.

Đúng hơn, Submission Service nên biết:

Caller là Grading Service.
Caller có quyền lấy file cho job này.
Request có scope phù hợp.

Không phải service nào cũng được đọc file bài nộp.

---

38.5. Có những loại caller nào?

Caller không chỉ là human user.

Có thể là:

Human user:
  student, teacher, admin

Service:
  grading-service, file-service, billing-service

Worker:
  grading-worker, export-worker, email-worker

Integration:
  LMS, school system, webhook provider

Script/automation:
  migration job, cron job, admin script

Mỗi loại caller cần identity riêng.

Không nên để mọi thứ dùng chung:

INTERNAL_API_KEY=super-secret

cho toàn bộ hệ thống.

Nếu lộ, không biết ai dùng.

Không revoke riêng được.

Không giới hạn quyền riêng được.

---

38.6. Service identity

Service identity là danh tính của service.

Ví dụ:

service:grading-service
service:file-service
service:notification-service
service:billing-service

Khi service gọi API, nó chứng minh danh tính bằng:

  • API key.
  • Signed JWT.
  • mTLS certificate.
  • Cloud IAM identity.
  • Workload identity.
  • Service mesh identity.

Service nhận request kiểm tra:

Caller là ai?
Caller có được gọi endpoint này không?

Tương tự user auth, nhưng actor là service.

---

38.7. API key là gì?

API key là một secret dùng để xác thực caller.

Ví dụ:

X-API-Key: sk_live_...

Hoặc:

Authorization: Bearer internal_key_...

Service nhận request kiểm tra key có hợp lệ không.

API key đơn giản và dễ dùng.

Phù hợp với:

  • Internal service nhỏ.
  • Webhook đơn giản.
  • Integration.
  • Admin script.
  • Giai đoạn đầu.

Nhưng API key có hạn chế:

  • Nếu lộ, ai cầm key cũng gọi được.
  • Khó biết request có bị replay không nếu không thêm cơ chế.
  • Nếu dùng chung key, không phân biệt caller.
  • Key thường cần lưu server-side để verify.
  • Cần rotation.

API key không xấu.

Nhưng phải dùng có kỷ luật.

---

38.8. API key tốt nên như thế nào?

Một API key tốt nên:

  • Dài và ngẫu nhiên.
  • Không đoán được.
  • Có prefix để nhận diện loại key.
  • Lưu dạng hash nếu có thể.
  • Có owner/caller rõ.
  • Có scope/quyền.
  • Có thời hạn hoặc rotation policy.
  • Có revoke.
  • Có audit log.
  • Không hardcode trong source code.

Ví dụ metadata:

key_id
key_hash
owner_service
scopes
created_at
last_used_at
expires_at
revoked_at

Không nên chỉ có:

if request.headers["X-API-Key"] == ENV["SECRET"]:
    allow

cho mọi endpoint nội bộ.

Cách đó tiện lúc đầu, nhưng khó vận hành khi hệ thống lớn hơn.

---

38.9. Scope cho API key

Scope là phạm vi quyền.

Ví dụ:

grading:read_submission
grading:write_result
file:create_signed_url
notification:send_email
billing:record_usage

Nếu Grading Service chỉ cần đọc submission và ghi result, key của nó không nên có quyền:

user:delete
billing:refund
tenant:export_all

Least privilege vẫn áp dụng với service.

> Service chỉ nên có quyền vừa đủ để làm việc của nó.

---

38.10. JWT cho service-to-service

Thay vì API key tĩnh, service có thể dùng JWT.

Ví dụ payload:

{
  "iss": "synvia-auth",
  "sub": "service:grading-service",
  "aud": "submission-service",
  "scope": "submission.read grading.write",
  "exp": 1770000000
}

Service nhận request verify:

  • Chữ ký.
  • Issuer.
  • Audience.
  • Expiration.
  • Subject.
  • Scope.

Ưu điểm:

  • Token ngắn hạn.
  • Có thể chứa service identity/scope/audience.
  • Service verify bằng public key.
  • Hợp với microservices.

Nhược điểm:

  • Cần hệ thống cấp token.
  • Cần quản lý key ký.
  • Cần xử lý revoke/rotation.
  • Dễ nhầm nếu tự chế.

JWT hữu ích khi hệ thống cần identity/scope rõ hơn API key tĩnh.

---

38.11. Audience trong JWT rất quan trọng

Audience nói token dành cho service nào.

Ví dụ:

aud = submission-service

Token này không nên dùng để gọi:

billing-service

Nếu service không kiểm tra audience, token bị dùng sai chỗ.

Ví dụ:

Grading Service có token gọi Submission Service.
Attacker dùng token đó gọi Billing Service.
Billing Service chỉ verify chữ ký, không check aud.

Đây là lỗi thiết kế.

Với JWT service-to-service, luôn nghĩ đến:

issuer
subject
audience
expiration
scope

---

38.12. mTLS là gì?

mTLS là mutual TLS.

TLS thông thường:

Client verify server.

Ví dụ browser kiểm tra website có certificate hợp lệ.

mTLS:

Client verify server.
Server cũng verify client.

Nói dễ hiểu:

> Hai bên đều phải xuất trình giấy tờ.

Trong service-to-service:

Service A có certificate.
Service B có certificate.
Khi gọi nhau, cả hai xác thực lẫn nhau.

mTLS mạnh hơn API key ở mức transport identity.

Nó rất hữu ích trong hệ thống lớn hoặc cần zero trust nghiêm túc.

---

38.13. mTLS mạnh ở đâu?

mTLS giúp:

  • Xác thực service ở tầng kết nối.
  • Mã hóa traffic.
  • Giảm rủi ro secret tĩnh trong header bị copy dùng lại.
  • Kết hợp tốt với service mesh.
  • Gắn identity với workload/certificate.

Ví dụ:

submission-service chỉ nhận request từ certificate của grading-service.

Không phải service nào cũng gọi được.

mTLS đặc biệt hữu ích khi:

  • Có nhiều service.
  • Nhiều team.
  • Môi trường production nghiêm túc.
  • Compliance cao.
  • Internal network không đáng tin hoàn toàn.
  • Cần identity workload rõ.

---

38.14. mTLS khó ở đâu?

mTLS cũng có chi phí:

  • Cấp certificate.
  • Rotate certificate.
  • Trust chain.
  • Debug khó hơn.
  • Local dev phức tạp hơn.
  • Cần proxy/service mesh hoặc platform hỗ trợ tốt.
  • Misconfiguration có thể làm service không gọi nhau được.

Nếu hệ thống nhỏ, API key hoặc JWT có thể đủ.

Không nên nhảy vào mTLS chỉ vì nghe bảo mật hơn.

Nhưng cũng nên biết nó là lựa chọn mạnh khi hệ thống lớn lên.

---

38.15. API key, JWT, mTLS khác nhau thế nào?

| Cơ chế | Dễ hiểu | Điểm mạnh | Điểm cần cẩn thận | |---|---:|---|---| | API key | Cao | Đơn giản, dễ tích hợp | Key lộ là nguy hiểm, cần scope/rotation | | JWT | Trung bình | Token ngắn hạn, có scope/audience | Cần verify đúng, quản lý signing key | | mTLS | Thấp hơn | Xác thực hai chiều ở tầng kết nối | Vận hành cert/mesh phức tạp |

Chọn nhanh:

Ít service, nhu cầu đơn giản:
  API key có scope + rotation.

Nhiều service, cần token ngắn hạn/scope/audience:
  JWT service token.

Hệ thống lớn, cần workload identity mạnh:
  mTLS/service mesh/workload identity.

Không có một đáp án cho mọi app.

---

38.16. Webhook security

Webhook là khi bên thứ ba gọi vào hệ thống của bạn.

Ví dụ:

Payment provider -> Backend
LMS -> Backend
GitHub -> Backend
AI provider -> Backend callback

Webhook rất dễ bị giả mạo nếu không xác thực.

Không nên chỉ tin:

Request đến đúng URL.

Vì URL có thể lộ.

Webhook thường cần:

  • Signature.
  • Timestamp.
  • Secret riêng cho từng integration.
  • Replay protection.
  • Idempotency.
  • Logging.

Ví dụ:

X-Signature: ...
X-Timestamp: ...

Backend tính lại chữ ký từ body + timestamp + secret.

Nếu khớp mới nhận.

---

38.17. Replay attack là gì?

Replay attack là dùng lại request cũ.

Ví dụ:

Webhook "payment_succeeded" hợp lệ được gửi lúc 10:00.
Attacker copy request.
11:00 attacker gửi lại request y hệt.

Nếu backend chỉ kiểm tra signature của body, request vẫn hợp lệ.

Cách giảm:

  • Timestamp trong chữ ký.
  • Reject request quá cũ.
  • Event id/idempotency key.
  • Lưu event đã xử lý.

Ví dụ:

Nếu timestamp lệch quá 5 phút thì reject.
Nếu event_id đã xử lý thì bỏ qua.

Webhook security luôn đi cùng idempotency.

---

38.18. Secret là gì?

Secret là thông tin nhạy cảm dùng để xác thực hoặc truy cập.

Ví dụ:

  • API key.
  • Database password.
  • JWT signing key.
  • OAuth client secret.
  • Webhook secret.
  • Private key.
  • mTLS certificate key.
  • Cloud access key.
  • Gemini/OpenAI/API provider key.

Secret bị lộ có thể cho attacker gọi API, đọc dữ liệu, ghi dữ liệu, hoặc tiêu tiền.

Vì vậy secret phải được quản lý nghiêm túc.

---

38.19. Không hardcode secret

Không nên để secret trong source code.

Ví dụ xấu:

GEMINI_API_KEY = "..."

trong file code.

Vì code có thể:

  • Lên Git.
  • Bị share.
  • Nằm trong image build.
  • Bị log.
  • Bị copy sang môi trường khác.

Secret nên nằm trong:

  • Secret manager.
  • Environment variable được quản lý.
  • Kubernetes Secret kết hợp encryption/RBAC phù hợp.
  • Cloud IAM/Workload Identity khi có thể.

Với production, secret manager là hướng tốt hơn.

---

38.20. Secret manager là gì?

Secret manager là nơi lưu và cấp secret an toàn hơn.

Ví dụ:

  • AWS Secrets Manager.
  • AWS Parameter Store.
  • Google Secret Manager.
  • Azure Key Vault.
  • HashiCorp Vault.
  • Doppler.
  • 1Password Secrets Automation.

Secret manager giúp:

  • Lưu secret tập trung.
  • Kiểm soát ai/service nào đọc được.
  • Audit access.
  • Version secret.
  • Rotate secret.
  • Không nhét secret vào code.

Không nhất thiết app nhỏ phải dùng Vault phức tạp ngay.

Nhưng production nghiêm túc nên có cách quản lý secret rõ ràng.

---

38.21. Principle of least privilege cho secret

Không phải service nào cũng cần mọi secret.

Ví dụ:

Notification Service cần email provider key.

Nó không cần:

Database admin password.
Gemini API key.
Billing provider secret.

Grading Service cần:

AI provider key.
Object storage read access cho submission files.

Nó không cần:

Billing refund key.
User deletion key.

Mỗi service chỉ nên được cấp secret cần thiết.

Nếu một service bị hack, thiệt hại được giới hạn.

---

38.22. Key rotation là gì?

Key rotation là thay key/secret định kỳ hoặc khi cần.

Ví dụ:

Thay API key cũ bằng API key mới.

Lý do:

  • Key có thể đã lộ.
  • Nhân sự thay đổi.
  • Chính sách bảo mật.
  • Giảm rủi ro secret tồn tại quá lâu.
  • Provider yêu cầu.

Rotation không nên là thao tác hoảng loạn thủ công mỗi lần sự cố.

Nên có quy trình.

---

38.23. Rotation phải hỗ trợ giai đoạn chồng lấn

Nếu service A dùng key để gọi service B, rotation ngay lập tức có thể làm hệ thống lỗi.

Quy trình tốt:

1. Tạo key mới.
2. Service B chấp nhận cả key cũ và key mới.
3. Cập nhật Service A dùng key mới.
4. Quan sát traffic key mới.
5. Revoke key cũ.

Giai đoạn chồng lấn giúp zero downtime.

Không nên:

Xóa key cũ trước rồi mới deploy key mới.

Trừ khi đang xử lý leak khẩn cấp và chấp nhận gián đoạn.

---

38.24. JWT signing key rotation

JWT dùng signing key.

Nếu rotate signing key, service verify token phải biết key mới.

Thường dùng:

kid

trong JWT header.

kid cho biết token được ký bằng key nào.

Verifier dùng kid để lấy public key tương ứng.

Quy trình:

1. Publish public key mới.
2. Bắt đầu ký token mới bằng private key mới.
3. Tiếp tục chấp nhận token cũ tới khi hết hạn.
4. Gỡ key cũ sau khi token cũ hết hạn.

Đây là lý do access token nên có expiration hợp lý.

Nếu token sống quá lâu, rotation khó hơn.

---

38.25. Không log secret/token

Log là nơi secret hay bị lộ.

Không nên log:

  • Authorization header.
  • API key.
  • Refresh token.
  • Password.
  • Reset token.
  • Webhook secret.
  • Private key.
  • Full signed URL nếu chứa secret dài hạn.

Ví dụ xấu:

logger.info("request headers", headers)

Nếu headers chứa:

Authorization: Bearer ...

token bị ghi vào log.

Log thường được nhiều người và hệ thống đọc hơn production database.

Đừng biến log thành kho secret.

---

38.26. Service authorization

Sau khi xác thực caller là service nào, vẫn cần phân quyền.

Ví dụ:

Caller = grading-service

Nó có được gọi:

GET /internal/submissions/{id}/file
POST /internal/grading-results
DELETE /internal/users/{id}

Không.

Grading Service có thể được:

submission.read_for_grading
grading_result.write
usage.record_ai_call

Nhưng không được:

user.delete
billing.refund
tenant.export_all

Service auth cũng có authentication và authorization.

Không chỉ user mới có permission.

---

38.27. User context forwarding

Đôi khi service A gọi service B thay mặt user.

Ví dụ:

API Service nhận request từ teacher.
API Service gọi Report Service tạo report.

Report Service cần biết:

Ai yêu cầu?
Tenant nào?
User có quyền export không?

Có hai thứ khác nhau:

Caller service:
  api-service

End user:
  teacher user_9

Đừng trộn hai identity này.

Request nội bộ có thể mang:

service identity
end-user identity/context

Report Service có thể kiểm tra:

api-service có quyền gọi report.create
user_9 có quyền export course_12

Hai lớp kiểm tra khác nhau.

---

38.28. Đừng tin header user tự gửi

Một pattern nguy hiểm:

X-User-Id: user_9

Service nhận request tin header này ngay.

Nếu endpoint bị gọi trực tiếp, attacker có thể set:

X-User-Id: admin

Nếu dùng header nội bộ để forward identity, phải đảm bảo:

  • Chỉ gateway/service tin cậy được set header.
  • Edge phải xóa header từ client.
  • Request nội bộ có service authentication.
  • Header được ký hoặc nằm trong token nếu cần.

Không bao giờ tin header identity đến trực tiếp từ internet.

---

38.29. Network policy và firewall

Auth ở application layer quan trọng.

Nhưng network layer vẫn cần.

Ví dụ:

Only API Gateway can call public-facing backend.
Only Grading Service can call internal grading endpoint.
Database only accepts connection from app subnets.

Network policy giúp giảm bề mặt tấn công.

Trong Kubernetes có thể dùng NetworkPolicy.

Trong cloud có security group/firewall.

Tư duy:

Không service nào nên nói chuyện với mọi service nếu không cần.

Network policy không thay thế auth.

Nó là lớp bảo vệ thêm.

---

38.30. Rate limit giữa service

Internal API cũng cần rate limit hoặc quota.

Vì bug nội bộ có thể tạo bão request.

Ví dụ:

Worker lỗi retry quá nhanh.
Notification Service bị spam.
Billing Service bị ghi usage trùng.
File Service bị tạo signed URL liên tục.

Rate limit nội bộ giúp:

  • Bảo vệ service downstream.
  • Phát hiện bug.
  • Giới hạn blast radius.
  • Tránh tốn chi phí.

Không phải mọi internal endpoint cần limit chặt.

Nhưng endpoint tốn tài nguyên hoặc nhạy cảm nên có.

---

38.31. Idempotency trong service-to-service

Request nội bộ cũng có thể retry.

Ví dụ:

Billing Service không trả response kịp.
Caller retry record usage.

Nếu không idempotent, usage bị ghi đôi.

Những API nội bộ tạo tác động nên hỗ trợ idempotency.

Ví dụ:

Idempotency-Key: job_123_ai_call_1

Service nhận request lưu key đã xử lý.

Nếu request đến lại, trả kết quả cũ hoặc bỏ qua an toàn.

Security và reliability thường đi cùng nhau.

---

38.32. Audit log cho service call

Với endpoint nhạy cảm, nên log:

  • Caller service.
  • End user nếu có.
  • Action.
  • Resource.
  • Tenant.
  • Request id/correlation id.
  • Result allow/deny.
  • Time.

Ví dụ:

caller=grading-service
action=submission.file.read
resource=submission_123
tenant=school_A
result=allow

Audit giúp điều tra:

  • Ai đọc file này?
  • Service nào tạo signed URL?
  • Request nào ghi kết quả chấm?
  • Key nào đang được dùng?

Không log secret.

Log identity và decision.

---

38.33. Correlation ID

Correlation ID giúp theo dõi một request đi qua nhiều service.

Ví dụ:

request_id = req_abc

Luồng:

API Service -> Submission Service -> Grading Service -> Billing Service

Mỗi service log cùng request_id.

Khi có lỗi, ta tìm được toàn bộ đường đi.

Correlation ID không phải cơ chế bảo mật trực tiếp.

Nhưng nó cực kỳ hữu ích cho audit và incident response.

---

38.34. SSRF và internal endpoint

SSRF là khi attacker khiến server của bạn gọi URL do attacker chỉ định.

Ví dụ:

Backend có feature fetch URL preview.
Attacker đưa URL http://internal-service/admin.
Backend gọi vào internal service.

Nếu internal endpoint tin mọi request nội bộ, attacker có thể lợi dụng server làm cầu nối.

Cách giảm:

  • Internal endpoint vẫn cần auth.
  • Chặn request tới IP nội bộ nếu feature fetch URL.
  • Allowlist domain.
  • Network segmentation.
  • Metadata service protection.
  • Không expose admin endpoint không auth.

Đây là lý do "internal network an toàn" là giả định yếu.

---

38.35. Background job có cần service credential không?

Có.

Worker cũng là một caller.

Ví dụ:

grading-worker gọi File Service.
export-worker gọi Report Service.
email-worker gọi Notification Service.

Mỗi worker nên có identity/quyền riêng.

Không nên để mọi worker dùng chung admin key.

Ví dụ:

grading-worker:
  file.read_submission
  grading_result.write
  usage.record

email-worker:
  notification.send_email

Nếu email-worker bị lỗi, nó không nên có quyền đọc file bài nộp.

---

38.36. Cloud IAM và workload identity

Trong cloud, có thể tránh dùng secret tĩnh bằng workload identity.

Ý tưởng:

Workload đang chạy có identity do cloud/platform cấp.

Ví dụ:

  • AWS IAM Role for Service Account.
  • GCP Workload Identity.
  • Azure Managed Identity.

Service không cần giữ access key dài hạn.

Nó nhận credential ngắn hạn từ platform.

Ưu điểm:

  • Ít secret tĩnh hơn.
  • Dễ revoke theo role/service account.
  • Audit tốt hơn.
  • Phù hợp cloud-native.

Nếu dùng cloud managed service, nên tìm hiểu workload identity sớm.

Nó thực dụng hơn việc phát access key dài hạn khắp nơi.

---

38.37. Service mesh là gì trong bảo mật?

Service mesh như Istio, Linkerd có thể giúp:

  • mTLS giữa service.
  • Service identity.
  • Traffic policy.
  • Retry/timeout.
  • Observability.
  • Authorization policy.

Nó đưa một phần network/security logic ra khỏi app code.

Nhưng service mesh cũng thêm:

  • Độ phức tạp vận hành.
  • Debug khó hơn.
  • Cấu hình nhiều.
  • Yêu cầu team hiểu platform.

Không phải app nhỏ nào cũng cần service mesh.

Nhưng với nhiều microservices nghiêm túc, nó là một lựa chọn đáng biết.

---

38.38. Zero trust là gì ở mức thực dụng?

Zero trust không có nghĩa là không tin ai theo kiểu cực đoan.

Ở mức thực dụng, nó nghĩa là:

Không tự động tin request chỉ vì nó đến từ mạng nội bộ.
Luôn xác thực caller.
Luôn giới hạn quyền.
Luôn log/audit.
Luôn giả định một phần hệ thống có thể bị compromise.

Zero trust hỏi:

  • Caller là ai?
  • Caller có quyền gì?
  • Resource nào được truy cập?
  • Request có hợp lệ không?
  • Secret có được quản lý/rotate không?
  • Nếu service bị hack, thiệt hại lan đến đâu?

Đây là tư duy, không chỉ là mua tool.

---

38.39. Khi nào cần zero trust nghiêm túc?

Cần nghiêm túc hơn khi:

  • Có nhiều microservices.
  • Nhiều team deploy độc lập.
  • Dữ liệu nhạy cảm.
  • Multi-tenant lớn.
  • Enterprise/compliance.
  • Hạ tầng phức tạp.
  • Có service public và internal xen kẽ.
  • Có nhiều third-party integration.
  • Rủi ro account/service compromise cao.

Nếu hệ thống còn nhỏ, không cần dựng mọi thứ cực phức tạp.

Nhưng vẫn nên giữ các nguyên tắc:

  • Secret không hardcode.
  • Internal endpoint nhạy cảm có auth.
  • Key riêng theo service.
  • Scope hẹp.
  • Rotation có kế hoạch.
  • Audit cho action nhạy cảm.

Làm đúng từ nhỏ sẽ dễ lớn hơn.

---

38.40. Một thiết kế vừa phải cho AI Judge

Giả sử AI Judge đang ở mức vừa:

API Service
Worker
File/Object Storage
AI Provider
Notification Provider
Database
Queue

Chưa cần service mesh.

Nhưng nên có:

1. Secret manager hoặc quản lý env secret nghiêm túc.
2. API key riêng cho từng integration nội bộ nếu có internal API.
3. Scope riêng cho worker.
4. Gemini/API provider key chỉ cấp cho worker cần gọi AI.
5. Webhook có signature verify.
6. Object storage dùng IAM/signed URL, không public bừa.
7. Log không chứa token/secret.
8. Rotation plan cho key quan trọng.
9. Audit khi service đọc file private hoặc ghi result.

Đây là bảo mật thực dụng.

Không quá to.

Nhưng tránh các lỗi nguy hiểm nhất.

---

38.41. Một thiết kế lớn hơn cho AI Judge

Khi hệ thống lớn hơn:

API Gateway
Auth Service
Submission Service
Grading Service
File Service
Billing Service
Notification Service
Analytics Pipeline
Worker pools

Có thể cần:

  • JWT service token có audience/scope.
  • mTLS hoặc service mesh.
  • Workload identity trong cloud.
  • Network policy giữa service.
  • Permission service hoặc policy chung.
  • Centralized audit log.
  • Secret manager bắt buộc.
  • Automated key rotation.
  • Rate limit nội bộ.
  • Incident response process.

Mục tiêu:

Nếu Grading Service bị compromise,
nó không thể xóa user, refund billing, export toàn bộ tenant, hoặc đọc mọi secret.

Đây là least privilege ở cấp hệ thống.

---

38.42. Những lỗi phổ biến

Lỗi 1:

Internal endpoint không auth vì "chỉ nội bộ".

Lỗi 2:

Một INTERNAL_SECRET dùng cho mọi service.

Lỗi 3:

Secret hardcode trong source code.

Lỗi 4:

Log Authorization header.

Lỗi 5:

Webhook không verify signature.

Lỗi 6:

JWT verify chữ ký nhưng quên check audience/scope/expiration.

Lỗi 7:

API key không có owner, không biết ai đang dùng.

Lỗi 8:

Không có quy trình rotate key.

Lỗi 9:

Worker dùng admin credential quá rộng.

Lỗi 10:

Tin X-User-Id header từ request ngoài internet.

---

38.43. Checklist service-to-service

Trước khi mở một endpoint nội bộ, hỏi:

  • Ai được gọi endpoint này?
  • Caller chứng minh identity bằng gì?
  • Caller có scope/quyền gì?
  • Request có cần end-user context không?
  • Có cần tenant_id không?
  • Có cần idempotency key không?
  • Có rate limit không?
  • Có audit log không?
  • Secret/token lưu ở đâu?
  • Secret rotate thế nào?
  • Nếu key lộ thì revoke ra sao?
  • Endpoint có bị SSRF gọi tới được không?
  • Network policy có giới hạn caller không?
  • Response có trả dữ liệu quá rộng không?

Nếu không trả lời được, endpoint chưa sẵn sàng production.

---

38.44. Bảng chọn nhanh

| Tình huống | Cách làm thường hợp | |---|---| | App nhỏ, vài internal call | API key riêng từng service + scope + rotation | | Nhiều service cần identity rõ | JWT service token có aud/scope/exp | | Hệ thống lớn/compliance cao | mTLS/service mesh/workload identity | | Webhook từ bên thứ ba | Signature + timestamp + idempotency | | Worker gọi service | Credential riêng cho worker, quyền hẹp | | Cloud managed service | Dùng IAM/workload identity nếu có | | Secret production | Secret manager hoặc cơ chế quản lý secret rõ | | Key bị lộ | Revoke ngay, rotate, audit usage | | Endpoint nhạy cảm | Auth + authorization + audit + rate limit | | User context qua nhiều service | Tách service identity và end-user identity |

---

38.45. Tóm tắt bằng AI Judge

Trong AI Judge, service-to-service security cần bảo vệ:

Grading Worker -> File/Submission Service
Grading Worker -> AI Provider
Grading Worker -> Usage/Billing Service
API Service -> Report/Export Worker
Webhook Provider -> Backend
Notification Worker -> Email Provider

Các nguyên tắc:

Mỗi service/worker có identity riêng.
Mỗi key/token có scope hẹp.
Internal endpoint nhạy cảm vẫn cần auth.
Webhook phải verify signature.
Secret không hardcode.
Token/key không log.
Key phải rotate được.
Service đọc/ghi dữ liệu nhạy cảm phải audit.

Thiết kế nhỏ:

API key riêng + secret manager + scope + audit.

Thiết kế lớn:

JWT service token/mTLS/workload identity/service mesh.

Điểm quan trọng:

Chạy trong cùng backend không có nghĩa là được tin tuyệt đối.

---

38.46. Kết luận của chương

Service-to-service security là phần nhiều hệ thống bỏ qua cho tới khi đã muộn.

Ban đầu, một endpoint nội bộ không auth có vẻ tiện.

Nhưng khi hệ thống có worker, webhook, microservices, third-party integration, và dữ liệu nhạy cảm, sự tiện đó trở thành rủi ro.

Thông điệp cần nhớ:

> Đừng tin request chỉ vì nó đến từ mạng nội bộ. Hãy xác thực caller, giới hạn quyền, quản lý secret đúng cách, rotate key, và audit hành động nhạy cảm.

API key đơn giản nhưng phải có owner/scope/rotation.

JWT mạnh hơn khi cần token ngắn hạn, audience và scope rõ.

mTLS/workload identity/service mesh hữu ích khi hệ thống lớn và cần identity cấp workload.

Ở chương tiếp theo, ta sẽ nói về web security thực dụng: HTTPS, CORS, CSRF, XSS, SQL injection, SSRF, file upload attack, rate limiting và audit log.