How we built a secure, performant, multi-tenant cloud platform to run untrusted code

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

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

Bài giới thiệu kiến trúc kèm quảng bá Deno Subhosting; ít số liệu, phần bảo mật chỉ liệt kê. Mọi nhận định là theo Deno.

Bối cảnh

  • Deno Deploy là cloud multi-tenant chạy JavaScript/TypeScript trên V8 isolate, phân tán toàn cầu; Subhosting cho doanh nghiệp chạy code không tin cậy của chính user của họ (edge function của Netlify: hơn 255 triệu request/ngày, 2024).
  • Yêu cầu: cách ly tenant tối đa, cold start thấp, tự nhân bản toàn cầu và tự co giãn mà user không cấu hình gì, deploy toàn cầu trong vài giây, giá rẻ.

Thay đổi chính

  • Control plane / data plane: control plane lo tạo và quản lý deployment, tài khoản, metering, billing, dashboard; data plane gồm mọi edge region (bucket lưu code, edge proxy, VM chạy isolate gọi là "runner").
  • Vòng đời deployment:
    • Tiền xử lý để giảm cold start: transpile TypeScript bằng swc, tải hết dependency (tránh "network waterfall" khi V8 tự hỏi từng import, mỗi lần khoảng 100 ms), cắt phần thừa của gói npm, sắp code theo thứ tự BFS của import để stream vào V8.
    • Bất biến: vendor toàn bộ dependency cùng code, nên deployment chạy lần nào cũng như nhau, kể cả khi URL import đổi hay chết.
    • Postgres không nằm trên đường request: Postgres giữ thông tin user và project; nếu Postgres sập thì không đăng nhập web được, nhưng deployment đang có vẫn chạy.
    • Nhân bản: code đã xử lý được đẩy lên bucket ở nhiều nơi trên thế giới.
    • Cuối cùng control plane báo cho edge proxy ở mọi region cập nhật bảng ánh xạ domain → deployment giữ trong bộ nhớ.
  • Vòng đời request: Anycast đưa request tới region gần nhất; edge proxy tra bảng domain, chọn runner theo số isolate "phù hợp" cho deployment đó (tuỳ RPS và tài nguyên mỗi request) rồi theo CPU của runner, CPU và bộ nhớ của isolate. Runner chưa có isolate cho deployment thì kéo code từ bucket gần nhất nạp vào isolate mới; isolate rảnh thì tắt.
  • Vì sao isolate: mỗi khách một VM thì cấp mới chậm, giữ chạy sẵn thì đắt; isolate (thiết kế cho mỗi tab trình duyệt) khởi động nhanh, ít bộ nhớ, và một runner giữ được rất nhiều isolate.
  • Bảo mật: threat model với 5 nguyên tắc (mỗi tenant chỉ chạm runtime và dữ liệu của mình, không chạm nội bộ, không chiếm tài nguyên của isolate khác, không dùng sai mục đích như đào bitcoin); nhiều lớp namespaces, cgroups, seccomp; thêm "watch dog" giám sát tài nguyên và giết tenant đáng ngờ nếu các lớp kia bị vượt.

Vì sao

  • Tách control plane khỏi đường request: hỏng phần quản trị không làm hỏng phần đang phục vụ (Độ tin cậy và multi-region).
  • Đóng gói bất biến, nhân bản sẵn gần user, rồi mới đổi bảng định tuyến: deploy là một lần đổi con trỏ (Deploy và release an toàn).

Bài học cho SWE

  • Liệt kê những gì nằm trên đường request; DB quản trị không nên có mặt ở đó.
  • Vendor dependency vào artifact deploy để chạy lại được y hệt.
  • Cold start là bài toán tiền xử lý (gói sẵn, sắp sẵn, để gần) nhiều hơn là bài toán runtime.
  • Multi-tenant chạy code lạ cần nhiều lớp cách ly và một cơ chế phát hiện/giết ở cuối, không chỉ một lớp sandbox.
  • Đặt cạnh sự cố DDoS năm 2023 (Deno 2023): cách ly giữa deployment đã giữ các tenant khác sống, còn phần tự co giãn cho một deployment bị dội tải thì không theo kịp; ứng dụng đã vendor dependency thì không bị ảnh hưởng, đúng với lý do vendor ở bài này.

Liên quan