Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 40 — Secret Management — Vault, KMS

Đã đọc 0/16 mục · còn khoảng 12 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn là DevOps engineer tại một startup fintech ở TP.HCM. Một sáng thứ Hai, sếp gọi bạn vào phòng họp với gương mặt tái mét: một bạn dev vừa push code lên GitHub public repo, và trong file config.js có nguyên chuỗi API key của cổng thanh toán VNPay cùng mật khẩu database production. Chỉ trong 4 giờ, một bot quét GitHub đã tìm thấy key này và bắt đầu gọi API thanh toán. Thiệt hại: hàng trăm giao dịch giả, và tệ hơn — niềm tin của khách hàng.

Đây không phải chuyện hiếm. Theo báo cáo của GitGuardian, mỗi năm có hàng triệu secret bị rò rỉ trên các repo công khai. Và secret không chỉ rò qua Git — nó rò qua log, qua debug endpoint, qua biến môi trường bị dump ra, qua Slack khi ai đó "gửi tạm cho nhau xài".

Secret Management là kỹ năng phân biệt giữa một hệ thống "chạy được" và một hệ thống "chạy được mà không bị hack". Trong bài này, chúng ta sẽ hiểu tại sao cách lưu secret truyền thống lại nguy hiểm, và cách các công cụ như HashiCorp Vault, AWS KMS, cloud secret manager giải quyết vấn đề. Đây là nền tảng bắt buộc trước khi bạn đụng tới bất kỳ hệ thống production nào.

Khái niệm cốt lõi

Secret là gì và tại sao nó khác dữ liệu thường

Secret là bất kỳ thông tin nhạy cảm nào cấp quyền truy cập vào tài nguyên: mật khẩu database, API key, private key TLS, token OAuth, chứng chỉ SSH, connection string. Điểm khác biệt cốt lõi so với dữ liệu thường là: nếu secret rơi vào tay kẻ xấu, họ có thể mạo danh hệ thống của bạn. Vì thế secret cần được bảo vệ ở ba trạng thái: khi lưu trữ (at rest), khi truyền đi (in transit), và khi sử dụng (in use).

Những cách lưu secret SAI và hậu quả

Secret trong biến môi trường (env var). Nghe thì tiện, nhưng env var rò rỉ dễ hơn bạn nghĩ. Bất kỳ process con nào cũng kế thừa env của process cha. Một crash sẽ dump toàn bộ env vào log hoặc lên Sentry. Một debug endpoint kiểu /debug/env (rất phổ biến trong framework) sẽ phơi bày tất cả. Lệnh ps eww <pid> trên Linux cho phép người dùng đọc env của process. Env var không hề "bí mật" như tên gọi.

Secret commit vào Git. Đây là lỗi chết người nhất. Git lưu toàn bộ lịch sử, nên kể cả khi bạn xóa secret trong commit sau, nó vẫn nằm trong history mãi mãi. Nguyên tắc vàng: một khi secret đã vào Git, nó bị coi là leaked vĩnh viễn — phải rotate (đổi mới) ngay lập tức, không phải chỉ xóa file. Xóa file mà không rotate là tự lừa dối mình.

Secret hardcode trong source code. Biến thể của lỗi trên, và còn nguy hiểm hơn vì nó nằm trong mọi bản build, mọi Docker image, mọi backup.

Bốn nguyên tắc của Secret Management đúng cách

  • Tập trung hóa (centralization): secret nằm ở một nơi duy nhất, có kiểm soát, thay vì rải rác khắp file cấu hình.
  • Least privilege: mỗi service chỉ đọc được đúng secret nó cần, không hơn.
  • Audit & rotation: ghi log ai truy cập secret nào lúc nào, và tự động đổi mới secret định kỳ.
  • Mã hóa toàn diện: secret luôn được mã hóa at rest và in transit.

HashiCorp Vault — bộ não quản lý secret

Vault là công cụ mã nguồn mở phổ biến nhất cho secret management. Cách hoạt động cốt lõi:

  • Sealed/Unsealed: khi khởi động, Vault ở trạng thái "sealed" — dữ liệu bị mã hóa, không đọc được. Cần các "unseal key" (chia theo thuật toán Shamir's Secret Sharing, ví dụ 3/5 key) để mở khóa. Không ai một mình mở được Vault.
  • Secret Engine: nơi lưu và sinh secret. Vault không chỉ lưu secret tĩnh (KV engine) mà còn sinh dynamic secret — ví dụ nó tạo một cặp user/password database chỉ sống 1 giờ rồi tự xóa. Ứng dụng không bao giờ biết mật khẩu "cố định" nào cả.
  • Auth Method & Policy: ứng dụng xác thực với Vault (qua token, Kubernetes ServiceAccount, AWS IAM...) và chỉ được cấp quyền theo policy.
  • Lease & Revocation: mọi secret có thời hạn (lease), và có thể bị thu hồi tức thì khi phát hiện sự cố.

KMS — Key Management Service

KMS (AWS KMS, Google Cloud KMS, Azure Key Vault) giải quyết một bài toán hơi khác: quản lý khóa mã hóa chứ không phải trực tiếp lưu secret ứng dụng. Ý tưởng cốt lõi là envelope encryption (mã hóa phong bì):

  • KMS giữ một khóa gốc (master key / CMK) không bao giờ rời khỏi module phần cứng bảo mật (HSM).
  • Khi bạn cần mã hóa dữ liệu, KMS sinh một "data key", dùng nó mã hóa dữ liệu, rồi mã hóa chính data key đó bằng master key.
  • Bạn lưu dữ liệu đã mã hóa + data key đã mã hóa cùng nhau. Khi cần giải mã, bạn gửi data key đã mã hóa lên KMS để KMS giải mã nó, rồi bạn dùng data key giải mã dữ liệu.
Lợi ích: master key không bao giờ lộ, và bạn có thể mã hóa lượng dữ liệu lớn mà không cần gọi KMS liên tục. Các cloud secret manager (AWS Secrets Manager, GCP Secret Manager) thực chất dùng KMS bên dưới để mã hóa secret của bạn.

Vault hay KMS — chọn cái nào?

Không phải chọn một. Thực tế chúng bổ trợ: Vault thường dùng KMS làm cơ chế auto-unseal (thay vì nhập tay unseal key mỗi lần). Nếu bạn ở hoàn toàn trên một cloud, cloud secret manager + KMS là lựa chọn đơn giản, ít vận hành. Nếu bạn multi-cloud, cần dynamic secret, hoặc muốn kiểm soát sâu, Vault là lựa chọn mạnh hơn nhưng tốn công vận hành.

Tình huống thực tế

Ví dụ 1 — Startup fintech và cú rò rỉ VNPay key

Quay lại câu chuyện đầu bài. Team fintech đó lưu tất cả secret trong file .env và vô tình commit lên GitHub public. Sau sự cố, họ đã làm đúng quy trình xử lý:

  • Rotate ngay lập tức: liên hệ VNPay reset merchant key, đổi mật khẩu database, thu hồi mọi token. Họ hiểu rằng xóa commit là vô nghĩa — key đã leaked là leaked.
  • Triển khai Vault: chuyển toàn bộ secret vào Vault KV engine. Ứng dụng backend xác thực với Vault qua Kubernetes ServiceAccount, đọc secret lúc runtime thay vì từ file.
  • Thêm cổng chặn: cài gitleaks vào pre-commit hook và CI pipeline để chặn secret ngay từ máy dev.
Bài học: secret rò rỉ không phải "nếu" mà là "khi nào". Điều quan trọng là quy trình phản ứng phải có sẵn, và rotation phải là bước đầu tiên chứ không phải bước cuối.

Ví dụ 2 — Sàn TMĐT dùng dynamic secret cắt đứt rủi ro credential tĩnh

Một công ty thương mại điện tử quy mô khu vực Đông Nam Á (giả định là "ShopFast", khoảng 200 microservice) gặp vấn đề kinh điển: mỗi service có một mật khẩu database "vĩnh cửu" nằm trong config. Khi một nhân viên nghỉ việc, họ không dám chắc mật khẩu nào người đó từng thấy, nên phải đổi hàng loạt — mỗi lần đổi là một đêm downtime tiềm ẩn.

Họ chuyển sang Vault Database Secret Engine. Giờ đây khi service cần kết nối DB, Vault sinh một cặp credential mới với lease 1 giờ. Sau 1 giờ, Vault tự động xóa user đó khỏi database. Kết quả:

  • Không còn mật khẩu tĩnh nào để đánh cắp. Nếu một credential bị lộ, nó cũng chỉ sống tối đa 1 giờ.
  • Khi nhân viên nghỉ, không cần đổi gì cả — họ chưa bao giờ chạm vào mật khẩu thật.
  • Audit log của Vault cho biết chính xác service nào yêu cầu credential lúc nào, phục vụ điều tra sự cố.
Bài học: dynamic secret biến rủi ro "mật khẩu bị lộ" từ thảm họa thành phiền toái nhỏ. Đây là bước tiến lớn nhất so với secret tĩnh.

Ví dụ 3 — Ngân hàng số dùng KMS envelope encryption cho dữ liệu khách hàng

Một ngân hàng số tại Việt Nam cần mã hóa dữ liệu định danh khách hàng (CMND, số tài khoản) trong database để tuân thủ quy định. Họ không thể tự lưu khóa mã hóa trong app vì như thế khóa và dữ liệu nằm cùng chỗ — bị hack một cái là mất cả hai.

Họ dùng AWS KMS với envelope encryption. Master key nằm trong HSM của AWS, không ai — kể cả admin nội bộ — trích xuất được. Mỗi bản ghi được mã hóa bằng data key riêng; data key đó lại được mã hóa bởi master key. Quyền gọi KMS được kiểm soát chặt qua IAM policy, và mọi lệnh giải mã đều để lại vết trong CloudTrail.

Khi kiểm toán tuân thủ hỏi "ai đã giải mã dữ liệu khách hàng ngày X", họ có câu trả lời chính xác từ log. Khi cần chứng minh khóa được xoay vòng định kỳ, KMS tự động rotate master key hàng năm.

Bài học: KMS tách biệt khóa khỏi dữ liệu và khỏi con người. Với các ngành bị quản lý chặt như tài chính, đây gần như là bắt buộc, không phải tùy chọn.

Hướng dẫn từng bước

Dưới đây là quy trình đưa secret management vào một dự án đang lưu secret trong .env:

Bước 1 — Kiểm kê secret. Rà soát toàn bộ codebase và config tìm secret: API key, mật khẩu, token, private key. Dùng công cụ quét như gitleaks detect --source . để tìm cả secret đã lỡ commit trong lịch sử Git.

Bước 2 — Rotate mọi secret đã từng ở trong Git. Bất kỳ secret nào từng xuất hiện trong Git history đều phải coi là compromised. Sinh secret mới trước khi làm bất cứ việc gì khác.

Bước 3 — Dựng nơi lưu trữ tập trung. Chọn Vault (self-host) hoặc cloud secret manager. Với bản demo, khởi động Vault dev:

vault server -dev
export VAULT_ADDR='http://127.0.0.1:8200'

# Ghi một secret
vault kv put secret/myapp/db password="s3cr3t-moi" user="app_user"

# Đọc lại
vault kv get secret/myapp/db

Bước 4 — Tạo policy least privilege. Định nghĩa policy chỉ cho phép đọc đúng path service cần:

# policy myapp-read.hcl
path "secret/data/myapp/*" {
  capabilities = ["read"]
}
vault policy write myapp-read myapp-read.hcl

Bước 5 — Cấu hình auth method. Cho ứng dụng chạy trên Kubernetes, dùng Kubernetes auth để pod xác thực bằng ServiceAccount thay vì nhét token vào image.

Bước 6 — Ứng dụng đọc secret lúc runtime. Thay vì đọc từ .env, app gọi Vault khi khởi động (hoặc dùng sidecar Vault Agent tự inject secret vào file/env một cách an toàn).

Bước 7 — Cài cổng chặn CI. Thêm gitleaks hoặc trufflehog vào pre-commit hook và CI để không secret nào lọt vào Git nữa.

Bước 8 — Bật audit & rotation. Bật audit log của Vault, thiết lập lịch rotation cho secret tĩnh, hoặc chuyển sang dynamic secret nếu có thể.

Lỗi thường gặp & mẹo

Lỗi: xóa secret khỏi Git mà không rotate. Đây là sai lầm phổ biến nhất. Git history bất tử; secret đã commit là đã leaked. Luôn rotate trước, dọn history sau.

Lỗi: coi env var là an toàn. Env var rò qua log crash, debug endpoint, /proc, process inspection. Đừng đặt secret nhạy cảm vào env nếu có lựa chọn tốt hơn. Nếu buộc phải dùng env, ít nhất hãy đảm bảo không có endpoint nào dump env và log không ghi env.

Lỗi: một secret dùng cho mọi service. Khi lộ, bạn phải đổi toàn hệ thống. Hãy tách secret theo service để giới hạn phạm vi ảnh hưởng (blast radius).

Lỗi: cấp quyền quá rộng. Đừng cho mọi service đọc secret/*. Least privilege giới hạn thiệt hại khi một service bị chiếm.

Lỗi: lưu unseal key và root token chung một chỗ. Toàn bộ tính bảo mật của Vault sụp đổ nếu ai đó gom đủ unseal key. Phân tán chúng cho nhiều người, cân nhắc auto-unseal bằng KMS cho production.

Mẹo: dùng .gitignore cho file secret, nhưng đừng coi đó là biện pháp bảo mật — nó chỉ chống commit vô ý, không chống người cố tình.

Mẹo: với secret cần dùng lúc build (ví dụ private key kéo dependency), dùng cơ chế build secret của Docker BuildKit (--mount=type=secret) thay vì ARG — vì ARG bị lưu vào image layer.

Mẹo: đặt cảnh báo (alert) khi có truy cập secret bất thường — số lần đọc tăng đột biến thường là dấu hiệu bị chiếm quyền.

Bài tập thực hành

  • Truy vết secret trong Git: clone một repo cá nhân của bạn, chạy gitleaks detect --source .. Nếu tìm thấy secret, viết ra quy trình xử lý theo đúng thứ tự (rotate trước, dọn history sau).
  • Dựng Vault và lưu secret: khởi động vault server -dev, tạo một KV secret cho một app giả định, viết policy chỉ cho đọc path đó, và verify rằng token với policy khác không đọc được.
  • Thiết kế envelope encryption trên giấy: vẽ sơ đồ luồng mã hóa và giải mã một bản ghi dữ liệu khách hàng bằng KMS (master key, data key, dữ liệu đã mã hóa). Chỉ rõ khóa nào rời khỏi HSM và khóa nào không.
  • So sánh dynamic vs static secret: viết một đoạn ngắn giải thích, với tình huống một nhân viên nghỉ việc, vì sao dynamic database secret giúp bạn không cần đổi mật khẩu hàng loạt.
  • Bổ sung cổng chặn CI: thêm gitleaks vào file CI (GitHub Actions/GitLab CI) của một dự án và thử commit một API key giả để xác nhận pipeline chặn được.

Tóm tắt

Secret Management là ranh giới giữa hệ thống an toàn và hệ thống chờ ngày bị hack. Những điểm cốt lõi cần nhớ:

  • Secret trong env var dễ rò qua log, debug endpoint và process inspection — đừng coi env là bí mật thật sự.
  • Secret commit vào Git bị coi là leaked vĩnh viễn; phản ứng đúng là rotate ngay, không phải chỉ xóa file.
  • Vault cung cấp lưu trữ tập trung, dynamic secret có thời hạn, audit log và revocation tức thì — biến rủi ro lộ credential thành phiền toái nhỏ.
  • KMS giải quyết bài toán quản lý khóa qua envelope encryption, tách khóa khỏi dữ liệu và khỏi con người — gần như bắt buộc với ngành tài chính, y tế.
  • Bốn nguyên tắc nền tảng: tập trung hóa, least privilege, audit & rotation, mã hóa toàn diện.
Khi bạn xây dựng hệ thống production, hãy thiết kế secret management từ đầu — vá lỗi sau sự cố luôn đắt hơn nhiều lần so với làm đúng ngay từ ngày một.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi