Bối cảnh
Các runner CI vẫn làm tốt việc của mình, và đó chính là vấn đề. Mỗi runner chạy như một docker-compose tự dựng, mount docker socket của host để workflow có thể khởi tạo container build. Phép tính khắc nghiệt: ai có thể đẩy được một workflow là có thể khởi tạo một container có đặc quyền, và ai có một container có đặc quyền thì có cả host. Một push độc hại, một action bị xâm nhập, một lỗi gõ ở một phụ thuộc bên thứ ba. Phạm vi thiệt hại là cả node.
Bài toán kinh tế cũng xấu tương tự. Mỗi runner chạy cache blob nhúng của riêng nó. Hết job này đến job khác lại pull lại cùng các image build từ registry thượng nguồn. Khởi động lại là làm lại từ đầu. Trên ba host là ba cache độc lập, ba kho tin cậy độc lập và ba cách để một workflow lỗi kéo cả đội đi xuống.
Chúng tôi đã làm gì
Chúng tôi tái dựng đội ngũ trên Nomad. Ba runner docker-in-docker không đặc quyền, mỗi cái được gắn vào một host riêng trong pool hiệu năng cao, mỗi cái chạy docker daemon lồng nhau, biệt lập. Socket trên host vẫn ở nguyên trên host. Một workflow nếu thoát sandbox thì cũng chỉ là quyền root của một người dùng không đặc quyền trong một namespace biệt lập, chứ không phải của máy.
Một máy chủ Gitea Actions cache độc lập đứng cạnh Gitea, được chống lưng bởi một volume Ceph RBD. Mọi runner đều trỏ về đó. Cache hit giờ có ý nghĩa trên toàn đội, không chỉ trong từng host, và sống sót qua các lần khởi động lại vì lưu trữ nằm trên một network block device, không phải tầng ghi của container runner. Tên miền nội bộ, chứng chỉ Vault PKI, không phơi ra ngoài.
Các lượt pull image đi qua một zot pull-through proxy mirror cho Docker Hub, GitHub Container Registry và namespace image của Gitea, kết thúc TLS bằng cùng một CA nội bộ. Các runner tin cậy nó một cách rõ ràng. Lần pull image đầu tiên cũng vẫn ở trong mạng LAN. Sự cố registry thượng nguồn không còn là vấn đề của chúng tôi.
Toàn bộ kiến trúc, Gitea, cache server, runner, ràng buộc bố trí, gắn volume, fetch chứng chỉ Vault qua artifact, sống trong một job spec Nomad duy nhất. Thêm năng lực là thay đổi một con số.
Điều gì đã thay đổi
Workflow mất con đường ngắn đến quyền root trên host. Pull image rút xuống độ trễ LAN. Cache CI trụ vững xuyên suốt cả đội và sống sót qua khởi động lại vì nó nằm trên Ceph, không phải trong tầng ghi của container. Thêm một runner thứ tư mất vài giây.
Runner không tồn tại trên host thì không thể bị xâm nhập trên host.