Bảo vệ Docker Image bằng Cosign: Chặn đứng mã độc trong chuỗi cung ứng phần mềm

Docker tutorial - IT technology blog
Docker tutorial - IT technology blog

Chuyện gì xảy ra nếu Docker Image của bạn bị “tráo hàng”?

Làm DevOps hay Backend, chắc hẳn anh em đã quá quen với lệnh docker pull từ Docker Hub hoặc Registry nội bộ. Nhưng có bao giờ bạn tự hỏi: Liệu image vừa kéo về có đúng là bản build “xịn” từ đồng nghiệp? Hay thực tế, nó đã bị một hacker nào đó chèn sẵn mã độc đào coin hoặc backdoor ngay trên đường truyền?

Đây chính là bài toán hóc búa về bảo mật chuỗi cung ứng (Supply Chain Security). Trước đây, Docker Content Trust (Notary v1) từng là giải pháp chính nhưng cực kỳ khó nuốt vì cấu hình cồng kềnh. Mình từng mất cả buổi sáng chỉ để setup mà vẫn lỗi lên lỗi xuống. Cosign (thuộc dự án Sigstore) ra đời như một vị cứu tinh, giúp việc ký và xác minh image đơn giản như cách chúng ta dùng Git hàng ngày.

Vừa rồi khi mình nâng cấp toàn bộ hệ thống từ docker-compose v1 lên v2, mình nhận thấy bảo mật ngay từ bước build là sống còn. Chỉ cần 1 lỗ hổng nhỏ, server có thể vọt lên 100% CPU do dính image lạ. Nếu không muốn rơi vào cảnh “mất bò mới lo làm chuồng”, bài viết này là dành cho bạn.

Cài đặt Cosign trong 30 giây

Cosign ăn điểm ở chỗ nó chỉ là một file thực thi duy nhất (binary). Bạn không cần cài đặt server hay database phức tạp, chỉ cần ném vào máy cá nhân hoặc CI/CD pipeline là chạy được ngay.

Với anh em dùng Linux, hãy dùng lệnh này để lấy bản mới nhất:

LATEST_VERSION=$(curl -s "https://api.github.com/repos/sigstore/cosign/releases/latest" | grep 'tag_name' | cut -d\" -f4)
curl -LO https://github.com/sigstore/cosign/releases/download/${LATEST_VERSION}/cosign-linux-amd64
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
sudo chmod +x /usr/local/bin/cosign

Nếu dùng macOS hoặc Windows, mọi thứ còn nhàn hơn:

# macOS
brew install cosign

# Windows
scoop install cosign

Cài xong, bạn gõ cosign version. Nếu thấy thông tin phiên bản hiện ra là chúng ta đã sẵn sàng “lên nòng”.

Tạo cặp khóa và ký Image đầu tiên

Cơ chế của Cosign rất trực quan: Bạn tạo một cặp khóa gồm Private Key (để ký) và Public Key (để xác minh).

1. Khởi tạo bộ khóa

Chạy lệnh sau để tạo key:

cosign generate-key-pair

Hệ thống sẽ yêu cầu bạn nhập mật khẩu (passphrase). Sau khi xong, thư mục sẽ xuất hiện hai file: cosign.key (tài sản vô giá, tuyệt đối không được mất) và cosign.pub (có thể gửi cho bất kỳ ai).

2. Thực hiện ký số

Giả sử bạn có image itfromzero/my-app:v1 đã đẩy lên Docker Hub. Để đóng dấu xác nhận, bạn chạy:

cosign sign --key cosign.key itfromzero/my-app:v1

Sau khi nhập mật khẩu, bạn sẽ thấy trên Registry xuất hiện thêm một tag mới có đuôi .sig. Cosign lưu trữ chữ ký như một artifact thông thường ngay bên cạnh image gốc. Cách làm này cực kỳ thông minh vì nó không đòi hỏi bạn phải duy trì thêm bất kỳ hạ tầng lưu trữ nào khác.

Xác minh Image: Chặn đứng rủi ro trước khi Deploy

Ký xong mà không check thì cũng bằng thừa. Ở phía server hoặc trong script deploy, bạn chỉ cần file cosign.pub để kiểm tra độ tin cậy của image.

Xác minh thủ công

Dùng lệnh sau để kiểm tra xem image có đúng do bạn ký hay không:

cosign verify --key cosign.pub itfromzero/my-app:v1

Nếu kết quả trả về mã JSON kèm thông báo Verification for itfromzero/my-app:v1 -- Check the signatures... thì bạn có thể kê gối ngủ ngon. Ngược lại, nếu ai đó lén sửa nội dung image nhưng vẫn giữ nguyên tag v1, lệnh verify sẽ báo lỗi và chặn đứng quá trình deploy.

Tự động hóa với CI/CD

Đừng bắt anh em dev phải ngồi gõ lệnh ký tay mỗi lần release. Hãy đẩy việc này cho GitHub Actions hoặc GitLab CI đảm nhận.

Đây là mẫu cấu hình GitHub Actions thực tế mình đang dùng:

- name: Sign Docker image
  env:
    COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
  run: |
    echo "${{ secrets.COSIGN_KEY }}" > cosign.key
    cosign sign --key cosign.key user/repo:tag

Keyless Signing: Đỉnh cao của sự tiện lợi

Nếu lười quản lý file cosign.key, bạn có thể thử Keyless Signing. Tính năng này cho phép bạn ký image thông qua danh tính OIDC (như tài khoản Google hoặc GitHub). Chữ ký sẽ được ghi vào nhật ký công khai Rekor, giúp việc xác minh trở nên minh bạch mà không cần lo lắng chuyện mất Private Key.

Kinh nghiệm thực chiến cho anh em

Sau một thời gian áp dụng Cosign cho các dự án tại itfromzero, mình rút ra 3 lưu ý sống còn:

  • Quản lý khóa an toàn: Đừng bao giờ lưu file .key thô trong source code. Hãy ưu tiên dùng AWS KMS, Google KMS hoặc HashiCorp Vault để bảo vệ chữ ký của bạn.
  • Chốt chặn tại Kubernetes: Việc xác minh bằng tay chỉ là bước đầu. Hãy cài thêm Kyverno hoặc Admission Controllers để cluster tự động từ chối mọi image không có chữ ký hợp lệ.
  • Quy trình chuẩn: Luôn quét lỗ hổng bằng Trivy trước khi ký. Image phải vừa “sạch” (không virus), vừa “chuẩn” (đúng chủ nhân) thì mới cho phép chạy production.

Triển khai Cosign không làm chậm workflow của bạn, nhưng nó mang lại sự tự tin tuyệt đối mỗi khi nhấn nút deploy. Hy vọng những chia sẻ này giúp anh em xây dựng được chuỗi cung ứng phần mềm vững chắc hơn!

Share: