How our security team handle secrets

Bài tóm tắt Monzo 2019 3. Quy mô lớn Độ khó: Trung bình

Monzo · 2019 · 3. Quy mô lớn · Độ khó: Trung bình — bài gốc

Bối cảnh

  • Nền tảng Monzo 2019: khoảng 1.100 microservice Go trên Kubernetes tự vận hành (kể cả etcd), Cassandra, Kafka và NSQ.
  • Hai cơ chế phát secret song song: Kubernetes secrets cho secret "ít nguy hiểm" (lưu plaintext trong etcd, gắn vào pod dưới dạng file) và HashiCorp Vault cho vài secret rất nhạy cảm, chỉ vài engineer được chạm vào.
  • Theo Monzo, cách làm hợp lý khi còn là startup trở nên không đủ khi họ có nhiều khách, số dư lớn hơn và thành mục tiêu hấp dẫn hơn.

Thay đổi chính

  • Vấn đề của cách cũ: hai cơ chế gây nhầm lẫn; Vault ít được dùng vì khó dùng (sai là gây outage) và hầu hết engineer không biết dùng. Kubernetes secrets đọc được bởi bất kỳ ai vào được node etcd, phải sửa file cấu hình tay, thiếu thư viện chuẩn. Vault thì mọi cấu hình, kể cả thêm secret mới, đều cần một key ceremony (vài người giữ khoá họp lại, khoảng 3 giờ); không có cấu hình dạng code; mỗi service muốn đọc Vault lại cần một Kubernetes secret chứa token Vault (gà và trứng).
  • Yêu cầu cho cơ chế "mơ ước": mã hoá ở mọi nơi lưu; không đọc được tất cả cùng lúc nhưng dễ cho từng service đọc đúng secret của mình; thêm mới dễ, ghi đè khó (thay secret là nguy hiểm, thêm mới thì an toàn); không gà-và-trứng; audit được; xem được cấu hình.
  • Cấu hình lại Vault, quản lý bằng Terraform:
    • Service xác thực vào Vault bằng service account token của Kubernetes (Kubernetes auth), nhận policy mặc định kubernetes-reader. Token này vẫn là Kubernetes secret, nhưng giờ chiếm được etcd thôi chưa đủ, kẻ tấn công còn phải nói chuyện được với Vault từ trong mạng.
    • Policy templating: chèn tên service account vào đường dẫn được phép, nên mỗi service tự có một vùng đọc mặc định (secret/k8s/<namespace>/<service>/...) mà không cần key ceremony.
    • Bật mã hoá Kubernetes secrets at rest (tính năng thử nghiệm lúc đó) bằng khoá AES nằm trong Vault.
    • Người dùng vào Vault qua một proxy web dùng cơ chế xác thực nhân viên sẵn có; proxy chèn child token gắn user ID nên audit log thấy từng người.
    • Công cụ shipper secret cho mọi engineer tạo secret mới, với quy ước: secret bất biến, phần cuối đường dẫn là phiên bản (đổi giá trị là tạo tên mới, ứng dụng không phải xử lý secret đổi giữa chừng); cảnh báo nếu secret ghi lên prod mà chưa có ở staging; mỗi secret chỉ một khoá data.
    • Thư viện đọc secret có giao diện giống đọc biến cấu hình.

Vì sao

  • Mục tiêu là một cơ chế dùng được cho mọi secret: nếu cơ chế an toàn khó dùng, engineer sẽ né nó và secret rơi về chỗ kém an toàn hơn.
  • Dự định tiếp theo (2019): Vault cấp credential ngắn hạn cho Cassandra và cho AWS thay vì secret tĩnh, và scale Vault theo tải.

Bài học cho SWE

  • Phân quyền theo hành động: thêm secret mới không nguy hiểm thì để tự phục vụ, ghi đè và đọc hàng loạt mới cần kiểm soát chặt.
  • Danh tính sẵn có của workload (service account) là cách phá vòng gà-và-trứng khi bootstrap secret.
  • Secret bất biến có phiên bản biến việc đổi secret thành một deploy bình thường, có lịch sử trong code.
  • So với Uber 2025 (nhiều cloud, xoay vòng tự động; Uber 2025), đây là giai đoạn sớm hơn: gom về một kho và làm nó dễ dùng.

Liên quan