← All posts

Đưa Terraform state của bạn ra khỏi internet công cộng (mà không cần dựng VPN)

Authagonal·June 22, 2026
terraformsecurityzero-trustdevopsazure

Tập tin Terraform state của bạn là tài sản nhạy cảm bậc nhất trong toàn bộ hạ tầng cloud. Nó là một tấm bản đồ đầy đủ về mọi tài nguyên bạn đang chạy, và tùy vào provider của bạn, nó còn chứa cả bí mật ở dạng văn bản thuần: connection string, mật khẩu được sinh ra, khóa. Theo mặc định, tập tin đó nằm trong một storage account cloud với một endpoint công cộng, được khóa lại bằng đúng một thứ duy nhất là access key. Nếu khóa đó rò rỉ, kẻ tấn công chẳng cần phải dò tìm hạ tầng của bạn. Bạn đã trao cho họ tấm sơ đồ rồi.

Chúng tôi bán dịch vụ xác thực. Một nhà cung cấp auth mà để chìa khóa vương quốc của chính mình lăn lóc trên internet công cộng thì chẳng có tư cách gì giữ chìa khóa của bạn. Vì vậy state account cho production của chúng tôi hoàn toàn không có bề mặt công cộng nào cả. Để đến được đó có ba cái bẫy, và chúng tôi đã đối mặt với hình dạng của từng cái trước khi làm đúng.

Bẫy thứ nhất: con gà và quả trứng

Remote state cần một backend phải tồn tại sẵn trước khi Terraform có thể chạy. Nhưng backend bản thân nó cũng là hạ tầng, và bạn lại muốn Terraform quản lý nó. Bạn không thể dùng storage account để lưu state của chính cái storage account còn chưa tồn tại.

Lối thoát là một quy trình bootstrap hai pha có chủ đích. Pha một chạy với state local và tạo ra đúng phần nền móng: storage account chứa state, mạng nơi nó sẽ nằm, và đường truy cập. Pha hai chuyển khối backend từ local sang remote và di chuyển tập tin state nay đã tồn tại lên chính account mà nó vừa tạo ra. Từ thời điểm đó trở đi, lớp bootstrap ấy tự quản lý chính mình từ xa giống như mọi thứ khác. Đó là vài phút có cảm giác như bạn đang đứng trên một cái thang mà bạn vẫn còn đang đóng, rồi sau đó nó xong xuôi mãi mãi.

Bẫy thứ hai: bài toán tiếp cận, và khoản thuế VPN gateway

Làm cho account thành private chỉ tốn một dòng: tắt truy cập mạng công cộng và đặt một private endpoint ở phía trước nó. Giờ storage account chỉ có thể tiếp cận được từ bên trong virtual network của bạn. Mà đó lại chính là vấn đề, vì thứ cần tiếp cận nó thường xuyên nhất, tức pipeline CI của bạn, lại không nằm trong virtual network của bạn. Bạn cũng vậy.

Câu trả lời theo sách giáo khoa là dựng một VPN của provider. Một VPN gateway được quản lý, hoặc một bastion host, hoặc point-to-site với chứng chỉ client. Ai từng làm việc này đều biết khoản thuế ấy: gateway thì đắt đỏ và chậm chạp khi cấp phát, point-to-site nghĩa là phải đúc và xoay vòng chứng chỉ client, mỗi người vận hành mới là một nghi thức thiết lập, và bastion là thêm một cái hộp nữa để vá lỗi và trả tiền. Đó là cả một đống hạ tầng thường trực mà nhiệm vụ duy nhất của nó là "cho người đáng tin cậy tiếp cận một thứ riêng tư."

Chúng tôi bỏ qua tất cả. Thay vì một VPN gateway, một connector zero-trust nhỏ chạy dưới dạng container bên trong VNet, thuộc đúng loại mà Tailscale, Twingate, và Cloudflare Access chiếm giữ. Nó gia nhập một mạng lưới nhận biết danh tính. Những người được ủy quyền và pipeline CI tiếp cận private endpoint thông qua mạng lưới đó, được xác thực theo từng danh tính, với quyền truy cập được giới hạn đúng vào một tài nguyên duy nhất cần đến. Không gateway, không IP công cộng, không chứng chỉ phải xoay vòng, không jump box. CI dựng kết nối của nó trong suốt thời gian một lần chạy rồi tháo dỡ sau đó. Bài toán tiếp cận biến mất mà không kèm theo hóa đơn hạ tầng thường trực.

Bẫy thứ ba: cú khóa mà bạn không thể làm trong một bước

Bản năng hiển nhiên là khai báo account là private ngay từ đầu, trong cùng một lần Terraform apply tạo ra nó. Làm vậy là bạn cắt đứt dây nối trước khi đường riêng tư tồn tại: lần apply cần ghi state qua endpoint công cộng, mà private endpoint và DNS thì chưa được đấu nối, thế là bạn khóa Terraform, và cả chính bạn, ra khỏi đúng cái account bạn đang tạo. Chúng tôi đã suy luận thấu đáo chuyện này trước khi kích hoạt nó, đó là lần duy nhất mà bài chạy thử diễn ra trong đầu bạn thay vì trong terminal.

Vì vậy cú khóa là một bước riêng biệt có chủ đích, chỉ chạy sau khi mạng, private endpoint, và connector đều đã dựng xong và được chứng minh. Một câu lệnh chuyển truy cập mạng công cộng sang trạng thái vô hiệu hóa. Khoảnh khắc nó có hiệu lực, endpoint công cộng biến mất, danh sách IP được phép cũ trở nên vô nghĩa vì chẳng còn bề mặt công cộng nào để cho phép bất cứ thứ gì vào, và mọi lần chạy về sau đều tiếp cận state qua mạng lưới. Chúng tôi xác minh nó theo cách duy nhất có giá trị: bằng cách kiểm tra rằng account giờ đáp ứng từ đường riêng tư và từ chối đường công cộng.

Nửa còn lại: không có mật khẩu để mà đánh cắp

Giết chết endpoint công cộng là gỡ bỏ cánh cửa mạng. Nước cờ tương ứng là đảm bảo cũng chẳng có khóa thường trực nào nằm phía sau nó. Pipeline của chúng tôi không giữ thông tin xác thực cloud nào cả. Nó xác thực bằng workload identity federation: hệ thống CI xuất trình một token OIDC ngắn hạn, cloud tin tưởng token đó cho một repository cụ thể, và trao lại quyền truy cập hết hạn trong vài phút. Không có bí mật service principal nào nằm trong vault chờ rò rỉ, vì ngay từ đầu đã chẳng có bí mật nào.

Truy cập state cũng tuân theo cùng quy tắc. Terraform đọc và ghi state blob bằng một directory token ngắn hạn gắn với danh tính đó, không phải bằng access key của storage account. Vậy nên hai thứ mà kẻ tấn công thèm muốn nhất, một lối vào và một thông tin xác thực để dùng nó, hóa ra lại là một endpoint chỉ-riêng-tư và một token đã hết hạn ngay khi chúng đang đọc nó. Không có gì tĩnh để mà lấy đi.

Tại sao phải bận tâm

Các tập tin state thường không rò rỉ vì có ai đó phá vỡ mã hóa. Chúng rò rỉ vì account để công khai, một khóa lọt vào một log hay một fork hay một chiếc laptop, và chẳng có gì khác cản đường. Gỡ bỏ endpoint công cộng đi là loại bỏ trọn vẹn cả nhóm tình huống "khóa bị rò rỉ" ra khỏi mô hình mối đe dọa. Cái khóa trở nên vô dụng nếu không đồng thời nằm trên mạng lưới.

Đó là cùng một nguyên tắc mà chúng tôi dùng để xây dựng sản phẩm: đừng đặt bảo mật sau một cánh cửa công sức hay hạng gói, cứ làm đi, vì phương án còn lại chính là thứ bạn hối tiếc lúc 2 giờ sáng. Mọi tính năng bảo mật mà chúng tôi giao cho khách hàng, SSO và SAML, SCIM, MFA, webhook bắt buộc, xuất audit, đều được bật ở mọi gói, không bị giữ lại để chào bán lên hạng enterprise. Xem những gì được bao gồm.