Menu
ESC

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

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

Đang tải...

Bài 50 — Configuration Management & Secrets

Technical BA Masterclass Bài 50/60

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

Hãy hình dung một buổi sáng thứ Hai, đội vận hành của một ngân hàng số tại TP.HCM nhận được hàng loạt cuộc gọi từ khách hàng: "Tôi chuyển khoản mà bị tính lãi suất sai." Đào lại lịch sử, đội kỹ thuật phát hiện một lập trình viên đã sửa con số lãi suất trực tiếp trong mã nguồn (hard-code) từ 6.5% thành 7.2% để chạy thử, rồi quên gỡ ra trước khi deploy lên production. Không ai review được thay đổi đó vì nó nằm lẫn trong hàng nghìn dòng code. Đây không phải lỗi kỹ thuật cao siêu — nó là lỗi quản lý cấu hình (configuration management).

Là một Technical BA, bạn có thể nghĩ "config với secret là chuyện của developer và DevOps, liên quan gì đến tôi?". Nhưng thực tế ngược lại. Chính BA là người quyết định đâu là một tham số có thể thay đổi theo thời gian (lãi suất, hạn mức, phí dịch vụ), đâu là thông tin nhạy cảm cần bảo vệ (mật khẩu database, khóa API của cổng thanh toán). Nếu bạn không viết rõ những điều này trong spec, đội dev sẽ tự quyết — và họ thường chọn cách nhanh nhất chứ không phải cách an toàn nhất. Một spec tốt về config & secrets giúp doanh nghiệp thay đổi quy tắc nghiệp vụ trong vài phút thay vì phải chờ một chu kỳ phát hành mới mất hàng tuần, đồng thời tránh được những thảm họa rò rỉ dữ liệu khiến công ty mất hàng tỷ đồng và uy tín.

Bài học này sẽ giúp bạn phân biệt rõ các loại cấu hình, hiểu cách quản lý bí mật (secrets) một cách an toàn, và quan trọng nhất — biết cách viết những yêu cầu này vào tài liệu để đội kỹ thuật triển khai đúng.

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

Configuration (cấu hình) là gì?

Cấu hình là những giá trị có thể thay đổi mà không cần sửa và build lại mã nguồn. Nguyên tắc vàng trong kỹ thuật phần mềm hiện đại — được mô tả trong tài liệu nổi tiếng The Twelve-Factor App — là: tách cấu hình ra khỏi code (separate config from code). Lý do rất đơn giản: cùng một bộ code chạy ở môi trường dev, staging và production, nhưng địa chỉ database, khóa API, mức lãi suất ở mỗi nơi lại khác nhau. Nếu bạn nhét những giá trị này vào code, bạn phải build ba phiên bản khác nhau — vừa rủi ro vừa tốn công.

Phân loại cấu hình

Để viết spec đúng, BA cần phân biệt được các loại config sau:

1. Static config (cấu hình tĩnh) — quy tắc nghiệp vụ và feature toggle. Đây là những giá trị phản ánh quyết định kinh doanh, không đổi giữa các môi trường nhưng có thể đổi theo thời gian. Ví dụ: lãi suất tiết kiệm (6.5%/năm), phí chuyển khoản liên ngân hàng (8.000đ), hạn mức rút tiền ATM/ngày (20 triệu), hay một feature toggle bật/tắt tính năng "thanh toán QR code". Điểm mấu chốt: đây là loại config mà chính nghiệp vụ — chứ không phải kỹ thuật — quyết định giá trị. BA gần như sở hữu hoàn toàn nhóm này.

2. Environment config (cấu hình theo môi trường). Đây là những giá trị thay đổi tùy môi trường chạy. Ví dụ: URL kết nối database (dev trỏ về db-dev.internal, production trỏ về db-prod.internal), endpoint của API đối tác (sandbox vs live của VNPay), số lượng worker xử lý, mức độ ghi log. Cùng một bộ code nhưng mỗi môi trường nạp một bộ giá trị khác nhau lúc khởi động.

3. Secrets (bí mật) — một dạng config đặc biệt cần bảo vệ. Secret là thông tin nhạy cảm mà nếu lộ ra sẽ gây thiệt hại: mật khẩu database, private key, khóa API của cổng thanh toán, token truy cập, chứng chỉ SSL. Về bản chất secret cũng là config theo môi trường, nhưng không bao giờ được lưu dưới dạng văn bản thường (plaintext) trong code, trong file config thông thường, hay trong Git.

Vì sao secrets cần xử lý riêng?

Sai lầm kinh điển là commit secret vào Git. Một khi đã push lên repository, secret đó tồn tại vĩnh viễn trong lịch sử Git — kể cả khi bạn xóa ở commit sau, ai cũng có thể đào lại từ commit cũ. Nếu repo là public hoặc bị lộ, kẻ tấn công có thể chiếm quyền database hoặc rút tiền qua cổng thanh toán. Vì vậy giới kỹ thuật dùng các công cụ chuyên dụng gọi là secrets manager: HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Google Secret Manager. Những công cụ này lưu secret được mã hóa, cấp quyền truy cập theo vai trò, ghi nhật ký mọi lần truy cập (audit trail), và hỗ trợ xoay vòng khóa (secret rotation) — tự động đổi mật khẩu định kỳ.

Cách config được nạp vào ứng dụng

Một ứng dụng thường nạp cấu hình theo thứ tự ưu tiên (precedence), từ thấp đến cao:

  • Giá trị mặc định trong code (default).
  • File config (application.yml, appsettings.json).
  • Biến môi trường (environment variables).
  • Tham số dòng lệnh hoặc secrets manager khi khởi chạy.
Giá trị ở tầng cao sẽ ghi đè tầng thấp. Hiểu thứ tự này giúp BA viết spec rõ ràng về việc "giá trị nào thắng khi có xung đột".

Tình huống thực tế

Tình huống 1 — Lãi suất hard-code khiến phải hotfix lúc nửa đêm

Một công ty fintech cho vay tiêu dùng ở Hà Nội, gọi tắt là FinViet, ra mắt sản phẩm vay nhanh với lãi suất 18%/năm. Đội dev hard-code con số này trong code vì "lãi suất ít khi đổi". Ba tháng sau, Ngân hàng Nhà nước ban hành trần lãi suất mới và phòng kinh doanh yêu cầu giảm xuống 15.5% ngay trong ngày. Vì con số nằm trong code, đội kỹ thuật phải sửa code, chạy lại toàn bộ quy trình test, build và deploy khẩn cấp lúc 11 giờ đêm — vừa rủi ro gây lỗi mới, vừa mệt mỏi.

Diễn giải: Lỗi gốc nằm ở spec. BA đã không xác định lãi suất là một static config nghiệp vụ cần đưa ra ngoài. Nếu ngay từ đầu spec ghi rõ "lãi suất là tham số cấu hình, có thể chỉnh qua trang quản trị mà không cần deploy", thì phòng kinh doanh chỉ cần đăng nhập, đổi số, lưu lại — xong trong 5 phút.

Bài học: Mọi con số phản ánh quyết định kinh doanh có khả năng thay đổi (lãi suất, phí, hạn mức, ngưỡng cảnh báo) đều phải được BA xác định là config và mô tả rõ trong spec ai có quyền đổi, đổi ở đâu, có cần phê duyệt không.

Tình huống 2 — Khóa API cổng thanh toán bị lộ trên GitHub

Một startup thương mại điện tử tại Singapore tích hợp cổng thanh toán Stripe. Một lập trình viên junior, để test cho nhanh, đã dán secret key của Stripe (sk_live_...) thẳng vào file cấu hình rồi commit lên repository GitHub vốn để ở chế độ public. Chỉ trong vòng vài giờ, các bot dò quét GitHub tìm thấy khóa này. Kẻ xấu dùng nó tạo các giao dịch gian lận, gây thiệt hại trước khi đội kỹ thuật kịp thu hồi (revoke) khóa và phát khóa mới.

Diễn giải: Đây là minh họa kinh điển cho việc không tách secret ra khỏi code. Đáng lẽ secret key phải nằm trong một secrets manager hoặc biến môi trường, và trong repo chỉ có một file mẫu .env.example ghi tên biến chứ không ghi giá trị thật. Việc khóa "live" và khóa "test" không được tách bạch theo môi trường cũng làm hậu quả nặng hơn.

Bài học: BA phải đưa vào spec một mục riêng về secrets, nêu rõ: danh sách các secret của hệ thống, cách lưu trữ (qua secrets manager), nguyên tắc "không bao giờ lưu secret trong code/Git", và yêu cầu tách khóa theo từng môi trường. Đây chính là điểm giao thoa giữa quản lý cấu hình và bảo mật mà BA kỹ thuật cần làm chủ.

Tình huống 3 — Sai môi trường vì cấu hình lẫn lộn

Một ngân hàng số tại Việt Nam triển khai tính năng nhắc nợ qua SMS. Trong môi trường staging, đội test cấu hình endpoint SMS trỏ về sandbox (gửi tin giả, không tốn phí). Tuy nhiên do file cấu hình của staging và production bị copy nhầm, hệ thống staging lại trỏ vào endpoint SMS production. Kết quả: hàng nghìn tin nhắn nhắc nợ thật được gửi tới khách hàng thật trong lúc đội đang test với dữ liệu giả, gây hoang mang và một số khiếu nại.

Diễn giải: Nguyên nhân là environment config không được tách bạch và kiểm soát chặt. Không có cơ chế kiểm tra "môi trường staging chỉ được phép dùng endpoint sandbox". Cũng không có quy trình duyệt thay đổi file config giữa các môi trường.

Bài học: BA nên mô tả rõ trong spec ma trận cấu hình theo môi trường (config matrix): với mỗi tham số, ghi rõ giá trị ở dev/staging/production, và nêu các ràng buộc an toàn (ví dụ: "staging tuyệt đối không được dùng endpoint hoặc khóa của production"). Đây là loại chi tiết phòng ngừa thảm họa mà chỉ BA hiểu nghiệp vụ mới nghĩ tới.

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

Đây là quy trình giúp một Technical BA xử lý phần config & secrets cho một tính năng:

Bước 1 — Lập danh mục cấu hình (config inventory). Khi phân tích một tính năng, hãy liệt kê mọi giá trị có khả năng thay đổi. Tự hỏi: "Giá trị này có thể đổi sau khi go-live không? Nếu đổi, ai quyết định?". Mọi câu trả lời "có thể đổi" đều là ứng viên config.

Bước 2 — Phân loại từng mục. Với mỗi giá trị, gán nhãn: static (nghiệp vụ), environment (theo môi trường), hay secret (nhạy cảm). Việc phân loại quyết định cách triển khai hoàn toàn khác nhau.

Bước 3 — Xác định quyền sở hữu và quyền thay đổi. Ghi rõ: ai được phép đổi giá trị này? Phòng kinh doanh tự đổi qua trang admin, hay phải tạo yêu cầu cho IT? Có cần phê duyệt (approval) hai cấp không? Đặc biệt với các tham số tài chính, hãy yêu cầu cơ chế phê duyệt và lưu vết ai đổi, đổi lúc nào, từ giá trị cũ sang giá trị mới (audit trail).

Bước 4 — Lập ma trận cấu hình theo môi trường. Tạo một bảng: cột là dev/staging/production, dòng là từng tham số. Điền giá trị (với secret thì chỉ ghi "lưu trong Vault", không ghi giá trị thật vào tài liệu). Bảng này giúp đội dev không nhầm lẫn.

Bước 5 — Viết yêu cầu xử lý secrets. Nêu rõ secret được lưu ở đâu, ai được cấp quyền đọc, có yêu cầu xoay vòng định kỳ không (ví dụ: đổi mật khẩu database mỗi 90 ngày), và yêu cầu mọi lần truy cập secret phải được ghi log.

Bước 6 — Định nghĩa hành vi khi cấu hình thiếu hoặc sai. Hỏi đội kỹ thuật: nếu một config bắt buộc bị thiếu lúc khởi động thì sao? Spec tốt thường yêu cầu "fail fast" — ứng dụng từ chối khởi động và báo lỗi rõ ràng, thay vì âm thầm chạy với giá trị mặc định nguy hiểm.

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

Lỗi 1 — Hard-code giá trị nghiệp vụ. Đây là lỗi phổ biến nhất. Mẹo: trong mọi buổi review spec, hãy quét qua từng con số và hỏi "con số này có thể đổi không?". Nếu có, nó phải là config.

Lỗi 2 — Coi secret như config thường. Mật khẩu và khóa API không được nằm chung file với các config bình thường, không được commit vào Git. Mẹo: yêu cầu repo có file .env.example chỉ chứa tên biến, và một quy tắc quét secret tự động (secret scanning) trước khi commit.

Lỗi 3 — Quá nhiều feature toggle và quên dọn. Toggle giúp bật/tắt tính năng linh hoạt, nhưng nếu để lâu không gỡ sẽ tích tụ thành "nợ kỹ thuật". Mẹo: mỗi toggle tạm thời nên có ngày hết hạn dự kiến ghi trong spec.

Lỗi 4 — Không phân biệt môi trường. Mẹo: luôn yêu cầu tách bạch hoàn toàn khóa/endpoint giữa staging và production, và đặt ràng buộc rằng môi trường thấp không được chạm vào tài nguyên thật.

Lỗi 5 — Đổi config không để lại dấu vết. Với tham số tài chính, việc không biết "ai đổi lãi suất lúc nào" là rủi ro tuân thủ nghiêm trọng. Mẹo: luôn yêu cầu audit trail cho mọi thay đổi config nghiệp vụ.

Mẹo tổng quát: Khi nghi ngờ một giá trị nên là config hay không, hãy ưu tiên đưa nó ra ngoài. Chi phí để biến một giá trị thành config từ đầu rất nhỏ, còn chi phí phải hotfix khẩn cấp vì nó bị hard-code thì rất lớn.

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

Giả sử bạn là Technical BA cho một ví điện tử (e-wallet) đang xây tính năng "Nạp tiền từ tài khoản ngân hàng". Hãy thực hiện:

  • Lập danh mục cấu hình: Liệt kê ít nhất 8 giá trị có thể là config cho tính năng này (gợi ý: hạn mức nạp tối thiểu/tối đa mỗi giao dịch, hạn mức nạp/ngày, phí nạp, danh sách ngân hàng được hỗ trợ, endpoint API ngân hàng, timeout kết nối, khóa API, feature toggle bật/tắt từng ngân hàng).
  • Phân loại: Gán nhãn static / environment / secret cho từng mục bạn vừa liệt kê.
  • Lập ma trận môi trường: Vẽ bảng dev / staging / production cho 4 tham số quan trọng nhất, đảm bảo staging không dùng tài nguyên production.
  • Viết một đoạn spec secrets: Mô tả khóa API ngân hàng được lưu ở đâu, ai có quyền đọc, có xoay vòng định kỳ không, và lần truy cập có được ghi log không.
  • Tình huống mở rộng: Phòng kinh doanh muốn đổi hạn mức nạp tối đa/ngày từ 50 triệu lên 100 triệu mà không cần deploy. Hãy viết yêu cầu mô tả ai được đổi, đổi ở đâu, có cần phê duyệt không, và thay đổi đó được ghi vết thế nào.
Hãy trình bày kết quả thành một bảng và một đoạn spec ngắn — đây chính là sản phẩm thực tế bạn sẽ giao cho đội dev.

Tóm tắt

Quản lý cấu hình và bí mật không phải chuyện kỹ thuật thuần túy mà là một trách nhiệm cốt lõi của Technical BA. Hãy ghi nhớ những điểm chính:

  • Tách config ra khỏi code — mọi giá trị có thể thay đổi đều nên là cấu hình, không hard-code.
  • Ba loại config: static (quy tắc nghiệp vụ như lãi suất, phí — do nghiệp vụ quyết định), environment (URL, endpoint khác nhau theo môi trường), và secrets (thông tin nhạy cảm).
  • Secrets phải được xử lý riêng: không bao giờ lưu trong code hay Git, dùng secrets manager, tách theo môi trường, xoay vòng định kỳ và ghi log truy cập.
  • Vai trò của BA: lập danh mục config, phân loại, xác định ai có quyền đổi, lập ma trận theo môi trường, yêu cầu audit trail và định nghĩa hành vi khi config thiếu.
Một spec config & secrets tốt giúp doanh nghiệp linh hoạt thay đổi quy tắc trong vài phút và tránh được những thảm họa rò rỉ dữ liệu tốn kém. Khi bạn nhìn thấy một con số trong yêu cầu, hãy luôn tự hỏi: "Nó có thể đổi không, và nếu đổi thì ai quyết?" — câu hỏi đơn giản ấy chính là dấu hiệu của một Technical BA chuyên nghiệp.