Đặt vấn đề: Mối nguy tiềm ẩn từ các dependency hiện đại
Các ứng dụng hiện đại phần lớn vận hành dựa trên mã nguồn mượn từ bên ngoài. Theo các báo cáo chuỗi cung ứng gần đây từ Sonatype, các thành phần mã nguồn mở thường chiếm từ 80% đến 90% codebase của một doanh nghiệp tiêu chuẩn. Phần mã nguồn độc quyền mà đội ngũ của bạn viết chỉ là phần nổi của tảng băng chìm. Ẩn sâu bên dưới là một mạng lưới phức tạp gồm base image, runtime engine, dynamic library và các transitive package.
Firewall và các cổng SSH được cấu hình bảo mật nghiêm ngặt cũng không thể cứu được bạn nếu phần mềm bạn phân phối vốn đã bị xâm phạm. Các vụ tấn công như SolarWinds và Log4Shell (CVE-2021-44228) đã chứng minh rằng kẻ tấn công nhắm vào giai đoạn build thay vì các lớp phòng thủ vòng ngoài. Nếu một lỗ hổng nghiêm trọng xuất hiện lúc 2 giờ sáng, liệu đội ngũ của bạn có thể chỉ mặt điểm tên từng container image đang chạy chính xác thư viện bị lỗi đó không? Với hầu hết các đội ngũ kỹ thuật, việc trả lời câu hỏi đơn giản ấy thường mất nhiều ngày tìm kiếm trong hoảng loạn.
Mẹo 1: Các lockfile không phản ánh toàn bộ bức tranh. Những file như package-lock.json hay Pipfile.lock chỉ theo dõi các dependency ở cấp độ ứng dụng. Chúng không hề cho bạn biết thông tin gì về các package cấp hệ điều hành như glibc, curl, hay các thư viện hệ thống động được kéo vào qua base image của container. Bạn cần kiểm toán chính artifact thực tế sẽ được bàn giao.
Khái niệm cốt lõi: Hiểu rõ về SBOM, Syft và Grype
Để giải quyết điểm mù về khả năng quan sát này, các đội ngũ kỹ thuật dựa vào Software Bill of Materials (SBOM).
SBOM là gì?
SBOM là bản kiểm kê có cấu trúc, máy đọc được, liệt kê chi tiết mọi thành phần, thư viện, transitive dependency và giấy phép (license) được đóng gói bên trong ứng dụng. Hãy hình dung nó giống như danh sách thành phần in trên bao bì thực phẩm tại siêu thị. Khi có đợt thu hồi thực phẩm, người tiêu dùng có thể kiểm tra nhãn ngay lập tức mà không cần phải mang món ăn đi xét nghiệm hóa học trong phòng lab.
Hiện nay có hai định dạng chuẩn đang chiếm ưu thế trong hệ sinh thái:
- CycloneDX: Được duy trì bởi OWASP. Thiết kế chuyên biệt cho bảo mật ứng dụng, phân tích lỗ hổng và các pipeline CI/CD tốc độ cao.
- SPDX (Software Package Data Exchange): Tiêu chuẩn ISO/IEC 5962 được bảo trợ bởi Linux Foundation. Phổ biến trong việc tuân thủ license mã nguồn mở và xác minh nguồn gốc xuất xứ (provenance).
Vai trò của Syft
Syft là một công cụ CLI gọn nhẹ từ Anchore, có nhiệm vụ kiểm tra container image, file system và file tarball. Nó quét các hệ sinh thái package—bao gồm Alpine APK, Debian APT, RPM, NPM, PyPI, Go module và Cargo crate—rồi lập danh mục thành các file chuẩn CycloneDX hoặc SPDX chỉ trong vài giây.
Vai trò của Grype
Grype đảm nhiệm khâu quét lỗ hổng bảo mật. Thay vì phải liên tục kéo (pull) các container layer nặng nề, Grype phân tích trực tiếp file SBOM đã có sẵn. Nó đối chiếu phiên bản package với dữ liệu cập nhật theo thời gian thực từ National Vulnerability Database (NVD), GitHub Security Advisories (GHSA) và các trình theo dõi bảo mật riêng của từng bản phân phối hệ điều hành.
Mẹo 2: Tách biệt khâu tạo danh mục thành phần khỏi khâu quét lỗ hổng. Hãy tạo SBOM một lần trong bước build và lưu trữ nó như một build artifact cố định. Nếu một lỗ hổng zero-day xuất hiện sau đó 6 tháng, bạn có thể quét file JSON đã lưu đó chỉ trong 3 giây mà không cần build lại hay tải lại các container image cũ trong quá khứ.
Thực hành thực tế: Tạo và quét với Syft & Grype
Dưới đây là cách cài đặt binary, tạo SBOM từ một image Node.js tối giản, kiểm tra lỗ hổng và tích hợp toàn bộ quy trình vào GitHub Actions pipeline.
Bước 1: Cài đặt Syft và Grype trên máy cục bộ
Cả hai tiện ích đều được phân phối dưới dạng binary tĩnh cho Linux, macOS và Windows mà không cần bất kỳ runtime dependency bên ngoài nào.
# Cài đặt Syft vào /usr/local/bin
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
# Cài đặt Grype vào /usr/local/bin
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
# Kiểm tra xem cả hai binary đã khả dụng chưa
syft --version
grype --version
Bước 2: Tạo SBOM với Syft
Chạy Syft đối với image mục tiêu trực tiếp từ Docker Hub. Trong ví dụ này, chúng ta nhắm vào node:18-alpine và xuất danh mục thành phần sang định dạng chuẩn CycloneDX JSON:
# In bản tóm tắt nhanh, dễ đọc ra stdout
syft node:18-alpine
# Xuất toàn bộ dữ liệu CycloneDX JSON ra file
syft node:18-alpine -o cyclonedx-json=./sbom-node.json
Mở file sbom-node.json. Bạn sẽ thấy chi tiết tên package, mã băm mật mã (cryptographic hash), package URL (PURL) và các license thượng nguồn cho cả các package hệ thống của Alpine (như busybox và ssl_client) lẫn các module Node toàn cục.
Mẹo 3: Luôn chuẩn hóa theo định dạng CycloneDX JSON để máy xử lý tự động. Bảng hiển thị trên CLI trông rất gọn gàng trên terminal, nhưng các nền tảng tuân thủ (compliance), policy engine và công cụ quét hạ nguồn đều yêu cầu dữ liệu JSON có cấu trúc.
Bước 3: Quét lỗ hổng bảo mật trên SBOM với Grype
Truyền file sbom-node.json vừa tạo vào Grype mà không cần tải lại container image:
# Quét trực tiếp file SBOM
grype sbom:./sbom-node.json
# Chỉ hiển thị các lỗ hổng đã có bản vá từ nhà cung cấp
grype sbom:./sbom-node.json --only-fixed
# Thoát với mã lỗi (non-zero) nếu phát hiện CVE mức High hoặc Critical
grype sbom:./sbom-node.json --fail-on high
Mẹo 4: Bỏ qua các lỗ hổng chưa có bản vá khi thiết lập điều kiện chặn PR. Nếu một CVE thượng nguồn chưa có bản vá được phát hành, việc làm fail pipeline sẽ khiến các kỹ sư bị chặn công việc mà không có hướng giải quyết. Hãy kết hợp --only-fixed với --fail-on high để quá trình build chỉ thất bại khi kỹ sư thực sự có thể nâng cấp phiên bản package nhằm khắc phục rủi ro.
Bước 4: Tích hợp Syft và Grype vào GitHub Actions
Tự động hóa quy trình này trên mỗi lần merge. Workflow dưới đây sẽ build container Docker cục bộ, tạo SBOM, gắn cờ cảnh báo các CVE nghiêm trọng và lưu bản kiểm kê dưới dạng build artifact được lưu trữ trong 90 ngày.
Lưu cấu hình này thành .github/workflows/security-scan.yml:
name: Quét bảo mật chuỗi cung ứng
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build-and-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout mã nguồn repository
uses: actions/checkout@v4
- name: Thiết lập Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build container image cục bộ
uses: docker/build-push-action@v5
with:
context: .
load: true
tags: my-app:latest
- name: Tạo SBOM với Syft
uses: anchore/sbom-action@v0
with:
image: my-app:latest
format: cyclonedx-json
output-file: ./sbom.cyclonedx.json
- name: Quét SBOM với Grype
uses: anchore/scan-action@v3
with:
sbom: ./sbom.cyclonedx.json
fail-build: true
severity-cutoff: high
only-fixed: true
- name: Lưu trữ artifact SBOM
uses: actions/upload-artifact@v4
if: always()
with:
name: software-bill-of-materials
path: ./sbom.cyclonedx.json
retention-days: 90
Mẹo 5: Lưu trữ SBOM cùng với nhật ký triển khai. Quá trình kiểm toán và ứng phó sự cố luôn là công việc truy vết quá khứ. Khi một khai thác nhắm vào phiên bản thư viện xuất hiện sau nhiều tháng phát hành, việc sở hữu bản lưu trữ SBOM từ bản build #142 sẽ giúp bạn xác định ngay mức độ ảnh hưởng của hệ thống.
Kết luận: Bảo mật production bắt đầu ngay từ pipeline
Bảo mật chuỗi cung ứng không phải là tạo thêm rào cản, mà là loại bỏ sự phỏng đoán mơ hồ. Sự kết hợp giữa Syft và Grype cho phép bạn theo dõi sát sao từng dependency trước khi bước vào production, đồng thời chặn đứng các CVE nghiêm trọng trước khi chúng kịp lan tới cluster triển khai. Quá trình thiết lập chỉ mất chưa đầy 15 phút, vận hành trong vài giây và mang lại cho đội ngũ của bạn sự minh bạch toàn diện về mọi thành phần trong từng bản build.

