Tự động hóa Software Bill of Materials (SBOM) với Syft và Grype: Bảo mật chuỗi cung ứng CI/CD

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

Bối cảnh & Lý do: Bảo mật chuỗi cung ứng phần mềm với SBOM

Các ứng dụng hiện đại hiếm khi chỉ bao gồm mã nguồn do nội bộ tự viết. Giữa các thư viện npm, các base layer của Debian, cùng các Go module bắc cầu (transitive), một service đơn lẻ có thể dễ dàng kéo theo hơn 1.200 dependency từ bên thứ ba. Khi một lỗ hổng CVE chưa được vá xuất hiện trong một dependency gián tiếp sâu tới bốn cấp, các công cụ quét truyền thống thường khiến bạn phải đoán mò xem nó bắt nguồn từ đâu.

Đây là lúc Software Bill of Materials (SBOM) phát huy vai trò. Hãy hình dung SBOM như một bảng thành phần dinh dưỡng chi tiết cho file binary hoặc Docker image của bạn. Nó liệt kê đầy đủ từng package, phiên bản, giấy phép (license) và mã kiểm tra SHA-256 được tích hợp trong bản build. Bản kiểm kê này biến một container bí ẩn thành một bản kê khai (manifest) rõ ràng, giúp bạn dễ dàng truy vết và kiểm toán qua từng bản release lên môi trường production, kết hợp cùng các phương pháp ký và xác thực container image bằng Cosign.

Bộ đôi Syft và Grype của Anchore xử lý bài toán này thông qua quy trình hai giai đoạn tách biệt (decoupled). Đầu tiên, Syft kiểm kê các package trên toàn bộ container, filesystem gốc và file nén thành các định dạng tiêu chuẩn mở như SPDX và CycloneDX. Tiếp theo, Grype tiếp nhận bản kiểm kê đó và đối chiếu với các nguồn cấp dữ liệu lỗ hổng cập nhật nhất từ NVD, GitHub Advisories cùng các hệ thống theo dõi bảo mật của Linux.

Việc tách biệt khâu kiểm kê khỏi khâu quét là một điểm cộng lớn. Cách tiếp cận này giúp dịch chuyển bảo mật sang trái (shift-left) để phát hiện sớm các package độc hại ngay trong pull request mà không làm tốn thêm 10 phút giải nén lại các layer của image trong pipeline.

Cài đặt: Thiết lập Syft và Grype trên máy cá nhân và Build Runner

Cả hai công cụ đều được biên dịch thành các static binary bằng Go và không phụ thuộc vào bất kỳ runtime bên ngoài nào. Bạn có thể triển khai chúng lên laptop hoặc CI runner chỉ trong chưa đầy 10 giây.

Mẹo 1: Dùng script cài đặt chính thức để thiết lập nhanh trên máy local

Bạn đang thử nghiệm trên macOS hay một máy ảo Linux local? Hãy tải trực tiếp các script cài đặt chính thức vào biến môi trường PATH của bạn:

# Cài đặt Syft vào /usr/local/bin
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sudo 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 | sudo sh -s -- -b /usr/local/bin

# Kiểm tra cài đặt
syft version
grype version

Mẹo 2: Đóng gói sẵn binary vào Custom CI Base Image

Việc tải binary CLI trong mỗi lần pipeline chạy sẽ tiêu tốn băng thông mạng và tiềm ẩn nguy cơ build thất bại mỗi khi GitHub giới hạn lượt tải (rate-limit). Nếu bạn quản lý các build agent tùy chỉnh trên Kubernetes hoặc self-hosted GitHub runner, hãy đóng gói sẵn các phiên bản cố định vào chính runner image của bạn:

FROM alpine:3.19

ARG SYFT_VERSION=v1.1.0
ARG GRYPE_VERSION=v0.74.0

RUN apk add --no-cache curl ca-certificates bash \
    && curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin ${SYFT_VERSION} \
    && curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin ${GRYPE_VERSION}

Việc cố định (pin) tag phiên bản rõ ràng sẽ bảo vệ CI của bạn khỏi các lỗi do thay đổi schema hoặc các cờ lệnh (flag) bất ngờ bị loại bỏ.

Cấu hình: Tạo SBOM và tự động hóa quá trình quét trong CI/CD Pipeline

Hãy tránh việc quét bảo mật trực tiếp một lần duy nhất trên các container đang chạy. Thay vào đó, hãy tạo SBOM trước như một build artifact bất biến, sau đó để Grype đánh giá file này. Bạn sẽ kiểm tra chính xác bảng thành phần phần mềm chuẩn bị đưa lên production—không thừa, không thiếu.

Tạo SBOM theo tiêu chuẩn bằng Syft

Syft hỗ trợ kiểm kê theo nhiều định dạng tiêu chuẩn. Trong môi trường doanh nghiệp, SPDX JSON (tiêu chuẩn ISO) và CycloneDX JSON (tiêu chuẩn OWASP) là hai lựa chọn phổ biến nhất. Để kiểm kê một app image local, bạn chỉ cần chạy một lệnh duy nhất:

# Tạo SBOM định dạng SPDX JSON từ Docker image local
syft my-app:v1.2.0 -o spdx-json=sbom.spdx.json

# Hoặc kiểm tra trực tiếp một thư mục mã nguồn trong repository
syft dir:./src -o cyclonedx-json=sbom.cdx.json

Quét SBOM bằng Grype

Truyền trực tiếp file sbom.spdx.json vừa tạo vào Grype. Việc quét một image dung lượng 1,2 GB từ đầu có thể tiêu tốn 45 giây disk I/O. Ngược lại, việc quét file SBOM đã tạo sẵn chỉ mất khoảng 2 đến 3 giây vì Grype chỉ cần phân tích cú pháp JSON:

# Quét SBOM đã tạo và báo lỗi nếu phát hiện bất kỳ CVE mức High hoặc Critical nào
grype sbom:./sbom.spdx.json --fail-on high

Quy trình chuẩn tích hợp với GitHub Actions

Quy trình làm việc dưới đây sẽ build container, tạo bản kê khai SPDX, dừng quy trình build nếu phát hiện lỗ hổng nghiêm trọng, và lưu trữ SBOM để phục vụ kiểm toán tuân thủ:

name: Pipeline bảo mật chuỗi cung ứng

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build-and-audit:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout mã nguồn
        uses: actions/checkout@v4

      - name: Build container image
        run: |
          docker build -t internal/api-service:${{ github.sha }} .

      - name: Tạo SBOM bằng Syft
        uses: anchore/sbom-action@v0
        with:
          image: internal/api-service:${{ github.sha }}
          format: spdx-json
          output-file: sbom.spdx.json

      - name: Quét SBOM bằng Grype
        uses: anchore/scan-action@v3
        with:
          sbom: sbom.spdx.json
          fail-build: true
          severity-cutoff: high

      - name: Tải lên SBOM artifact
        uses: actions/upload-artifact@v4
        with:
          name: sbom-artifact
          path: sbom.spdx.json

Mẹo 3: Xử lý cảnh báo giả bằng file cấu hình Grype

Quá trình phân loại cảnh báo CVE khó tránh khỏi việc gặp phải các cảnh báo chưa có bản vá từ upstream hoặc liên quan đến các tính năng binary đã bị vô hiệu hóa. Thay vì làm rối log của pipeline, bạn có thể loại bỏ các cảnh báo giả đã được xác minh bằng cách sử dụng file .grype.yaml được quản lý phiên bản:

# .grype.yaml
ignore:
  - vulnerability: CVE-2023-44487
    package:
      name: golang.org/x/net
      version: 0.15.0
    reason: "HTTP/2 Rapid Reset: Service chạy phía sau AWS ALB edge kết thúc HTTP/2; runtime không bị ảnh hưởng."
check-for-app-update: false

Hãy commit file này vào thư mục gốc của repository hoặc chỉ định trực tiếp bằng lệnh grype -c .grype.yaml sbom:./sbom.spdx.json.

Kiểm tra & Giám sát: Kiểm toán kết quả, quản lý ngưỡng và duy trì khả năng giám sát liên tục

Tự động hóa kiểm thử trong CI mới chỉ là bước đầu. Giảm thiểu tình trạng quá tải cảnh báo (alert fatigue) cho lập trình viên trong khi vẫn duy trì tuân thủ nghiêm ngặt về bảo mật và giấy phép với các chính sách Kubernetes Policy as Code qua Kyverno mới là bước thứ hai.

Kiểm tra package và giấy phép (license)

Vi phạm giấy phép nguồn mở có thể dẫn đến những rắc rối pháp lý nghiêm trọng. Syft trích xuất mã định danh giấy phép cùng với tên package, giúp việc kiểm toán bản quyền trở nên dễ dàng trước khi mã nguồn được đưa lên staging:

# Xuất bảng tổng quan rõ ràng về các package và license
syft my-app:v1.2.0 -o table

# Lọc các license GPL hoặc AGPL trong toàn bộ SBOM bằng jq
cat sbom.spdx.json | jq '.packages[] | select(.licenseConcluded | test("GPL")) | {name: .name, version: .versionInfo, license: .licenseConcluded}'

Mẹo 4: Kiểm toán định kỳ liên tục mà không cần build lại

Một container image hoàn hảo được build vào thứ Hai hoàn toàn có thể xuất hiện hai lỗ hổng CVE mức Critical vào thứ Năm. Nhưng vì bạn đã lưu trữ artifact SBOM dung lượng 800 KB từ trước, bạn không cần phải tải về và build lại toàn bộ Docker image 2 GB chỉ để kiểm tra mức độ ảnh hưởng.

Hãy thiết lập một cron job định kỳ hoặc GitHub Actions workflow chạy Grype hàng ngày đối với các SBOM của các bản release production trước đây:

# Tải bản cập nhật mới nhất của cơ sở dữ liệu lỗ hổng (tải về khoảng 30-50MB)
grype db update

# Kiểm toán SBOM bản release production đối chiếu với cơ sở dữ liệu CVE hiện tại
grype sbom:./artifacts/prod-v1.2.0.spdx.json --only-fixed

Tùy chọn --only-fixed giúp cô lập những vấn đề đã có sẵn bản vá từ nhà cung cấp. Điều này giúp backlog bảo mật của bạn tập trung vào những bản sửa lỗi có thể deploy ngay lập tức, thay vì mất thời gian vào những cảnh báo chưa có cách khắc phục. Bên cạnh đó, việc kết hợp công cụ này song song với quét lỗ hổng tự động bằng Trivy Operator trên cụm Kubernetes sẽ giúp bạn hoàn thiện hệ thống phòng thủ đa tầng.

Checklist tóm tắt để kiểm toán chuỗi cung ứng

  • Tạo SBOM ngay sau khi chạy docker build.
  • Lưu trữ các manifest SBOM song song với image tag trong container registry hoặc S3 bucket.
  • Cấu hình Grype quét trực tiếp file SBOM nhẹ thay vì phải giải nén tarball image nhiều layer.
  • Duy trì file .grype.yaml được ghi chép rõ ràng và review kỹ lưỡng để giải trình các cảnh báo được bỏ qua.
  • Lên lịch kiểm toán SBOM định kỳ ở chế độ offline nhằm kịp thời phát hiện các lỗ hổng zero-day giữa các đợt release production.
Share: