Enforcing best practice on self-serve infrastructure with Terraform, Atlantis and Policy As Code

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

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

Đọc qua trình duyệt (blog Medium custom domain, Wayback không có bản); raw/ chỉ là placeholder.

Bối cảnh

  • Toàn bộ hạ tầng Google Cloud cùng Google Workspace, Fastly, PagerDuty, Route53, StatusCake… quản lý bằng Terraform, trong 33 repository (2021) cộng các module nội bộ (mỗi module một repo, phát hành bằng git tag) mã hoá best practice như label bắt buộc, region.
  • Mục tiêu: developer tự sở hữu hạ tầng từ lúc tạo tới lúc bỏ, vẫn tuân thủ chuẩn công ty, với ít can thiệp nhất của đội hạ tầng nhỏ. Vấn đề cố hữu của Terraform: mỗi team làm một kiểu (có team có pipeline CI/CD, có team chạy từ laptop một người).

Thay đổi chính

  • Atlantis làm pipeline Terraform chung (sau khi thử GitHub Actions và Cloud Build): webhook từ repo kích hoạt plan trong Atlantis trên GKE, kết quả comment vào PR; duyệt xong thì comment atlantis apply. Atlantis giữ khoá theo PR để không apply các PR xung đột trên cùng môi trường. Không cần 33 instance: gom repo vào instance theo bộ credential cần dùng (GCP, Route53, Fastly…).
  • Credential: không dùng JSON key (sống lâu, không tự xoay, dễ rò), không dùng service account mặc định của node (pod khác trên cùng node sẽ thừa hưởng quyền rất lớn của Atlantis). Dùng Workload Identity: mỗi instance Atlantis một Kubernetes service account gắn với một Google service account riêng.
  • Chỉ public đường webhook /events: trang chủ của Atlantis không có xác thực và có nút "Disable apply commands", nên ai tình cờ thấy cũng có thể chặn mọi thay đổi hạ tầng production. Admin vào trang chủ qua kubectl port-forward.
  • Policy as code: thử checkov, terrascan, terraform-compliance, OPA, regula, Conftest. Nhận xét: phân tích tĩnh code Terraform không đáng tin (sót resource trong module lồng nhau, không nạp biến từ tfvars), phân tích trên plan đáng tin hơn; khả năng viết check riêng quan trọng hơn bộ check có sẵn (vốn thiên về AWS). Chọn thư viện Rego của Regula (hàm duyệt file plan JSON phức tạp) chạy qua Conftest, mà Atlantis hỗ trợ sẵn trong bước plan.
  • Policy tải từ repo policy-as-code ở mỗi lần plan (luôn dùng bản mới nhất); mỗi policy có tài liệu markdown được link trong thông báo vi phạm, có unit test (_test.rego + _infra.tf gồm resource qua và trượt) chạy trên GitHub Actions.
  • Ví dụ policy: label team phải là team có thật; không tạo resource ngoài EU; chỉ dùng module ngoài trong whitelist; module nội bộ phải đạt phiên bản tối thiểu (nâng tag tối thiểu trong policy để ép nâng cấp); cấm bucket GCS public; chỉ Google Group do Terraform quản lý được có trong IAM; cấm role quá rộng như project owner.
  • Hai kiểu policy: kiểu xét toàn bộ cấu hình (thêm policy mới là lộ mọi vi phạm cũ, xử lý bằng waiver theo resource ID + policy ID) và kiểu chỉ xét thay đổi trong PR (mở cổng 22 thì cần chủ sở hữu được chỉ định gõ atlantis approve; lần plan sau không báo lại).

Vì sao

  • Theo Loveholidays: một đội hạ tầng duyệt mọi PR không scale và biến thành nút cổ chai, khiến người ta nhờ làm hộ thay vì tự làm; đưa tuân thủ vào pipeline giữ được self-serve mà vẫn thấy hạ tầng nào đang được tạo. Atlantis đã chạy production khoảng một năm lúc viết bài.

Bài học cho SWE

  • Cổng tuân thủ nên chạy trên kết quả đã tính (plan) chứ không trên mã nguồn, vì đó mới là thứ sẽ được áp dụng.
  • Công cụ có quyền tạo/xoá hạ tầng là mục tiêu giá trị cao: credential riêng cho từng instance, không lộ giao diện quản trị.
  • Policy mới gặp nợ cũ: cần cơ chế miễn trừ tường minh (waiver) để bật được policy mà không chặn mọi người.

Liên quan