Trong chu trình phát triển phần mềm Cloud-Native năm 2026, một container image không đơn thuần là tệp thực thi của ứng dụng, mà là một tập hợp phân lớp phức tạp gồm nhân hệ điều hành thu nhỏ (Userland OS packages như glibc, openssl, libcurl), hàng trăm thư viện mã nguồn mở phụ thuộc (npm, pip, Go modules, Cargo, Maven) và các tệp cấu hình hạ tầng. Thống kê thực tế từ các cuộc kiểm toán chuỗi cung ứng phần mềm theo tiêu chuẩn NIST SP 800-190 cho thấy hơn 78% lỗ hổng bảo mật nghiêm trọng (CRITICAL / HIGH CVEs) trên môi trường Kubernetes Production không nằm ở mã nguồn nghiệp vụ do lập trình viên viết ra, mà ẩn náu trong các tầng Base Image lỗi thời hoặc các gói thư viện chuyển tiếp (Transitive Dependencies) chưa được kiểm duyệt.
Triển khai chiến lược bảo mật container và quét lỗ hổng với Trivy Clair xuyên suốt từ khâu đóng gói trên máy trạm, kiểm cổng tự động trên đường ống CI/CD, lưu trữ tại Container Registry cho tới kiểm soát thực thi trên cụm Kubernetes là yêu cầu bắt buộc của mọi kiến trúc DevSecOps hiện đại. Bài viết chuyên sâu này mổ xẻ cơ chế phân tích tầng ảnh chuẩn OCI, đặt lên bàn cân hai công cụ mã nguồn mở hàng đầu hiện nay là Aqua Security Trivy v0.58+ và Quay Clair v4.8+, đồng thời cung cấp quy trình thực chiến kết hợp Multi-stage Distroless/Wolfi, danh mục thành phần phần mềm SBOM (CycloneDX 1.6), lọc cảnh báo giả OpenVEX, ký số Sigstore Cosign và chặn triển khai bằng Kyverno Admission Controller.
- 1. Giải phẫu Bề mặt Tấn công Chuỗi cung ứng Container (OCI Image Supply Chain) năm 2026
- 1.1. Ma trận rủi ro từ Base Image nguyên khối, Transitive Dependencies và rò rỉ Secret giữa các Layer
- 1.2. Mô hình Phòng thủ 3 Tầng theo chuẩn NIST SP 800-190: Pre-Commit/CI Gate, Registry Continuous Scan và Runtime Admission
- 2. Đặt lên bàn cân Kiến trúc: Aqua Security Trivy v0.58+ vs Quay Clair v4.8+
- 2.1. Kiến trúc Stateless CLI Đa năng của Trivy: Quét CVE, IaC Misconfig, Secret Leak và Khởi tạo SBOM
- 2.2. Kiến trúc Vi dịch vụ hướng Sự kiện của Clair v4 (Indexer, Matcher, Notifier) cho Container Registry quy mô lớn
- 3. Hardening Container từ Gốc và Triển khai Trivy chặn Lỗ hổng CRITICAL/HIGH trên CI/CD
- 3.1. Tối ưu hóa Base Image: Loại bỏ >90% CVE từ gốc bằng Multi-Stage Build với Distroless / Chainguard Wolfi và Non-Root UID 65532
- 3.2. Thiết lập cổng chặn Trivy trên GitHub Actions / GitLab CI và quản lý False Positives bằng chuẩn OpenVEX (--vex)
- 4. Triển khai Clair v4 / Harbor Quét Liên tục và Khởi tạo SBOM (CycloneDX 1.6) kèm Chữ ký Số Cosign
- 4.1. Cấu hình Clair v4.8+ (config.yaml) tích hợp cơ sở dữ liệu PostgreSQL 17 và Webhook cảnh báo lỗ hổng mới
- 4.2. Chuỗi cung ứng chống giả mạo (SLSA Level 3): Xuất SBOM CycloneDX 1.6 và Ký số Keyless OIDC với Sigstore Cosign
- 5. Bảo vệ Tầng Runtime Kubernetes v1.32+ với trivy-operator, Kyverno và SecurityContext Nghiêm ngặt
- 5.1. Chặn đứng Image chưa quét hoặc chưa ký bằng Kyverno Admission Controller (verifyImages)
- 5.2. Giám sát liên tục trong cụm với trivy-operator và Khóa chặt Pod securityContext
- 6. Checklist Kiểm toán Bảo mật Container DevSecOps & Tài liệu Tham khảo Chuẩn Kỹ thuật
- 6.1. Bảng Checklist 8 Bước Nghiệm thu Bảo mật Chuỗi cung ứng Container trước khi lên Production
- 6.2. Chiến lược Xử lý Khẩn cấp khi Phát hiện Lỗ hổng Zero-Day trên Môi trường Production
- 6.3. Tài liệu Tham khảo & Nguồn Chuẩn Kỹ thuật (Primary Technical References)
1. Giải phẫu Bề mặt Tấn công Chuỗi cung ứng Container (OCI Image Supply Chain) năm 2026
1.1. Ma trận rủi ro từ Base Image nguyên khối, Transitive Dependencies và rò rỉ Secret giữa các Layer
Để hiểu tại sao một container tưởng chừng vô hại lại trở thành bàn đạp cho kẻ tấn công chiếm quyền điều khiển máy chủ vật lý, chúng ta cần nhìn vào cấu trúc lưu trữ của một ảnh chuẩn OCI (Open Container Initiative). Mỗi chỉ thị FROM, RUN, COPY, ADD trong Dockerfile tạo ra một tầng hệ thống tệp chỉ đọc (Immutable Tarball Layer) được định danh bằng mã băm mật mã sha256 và xếp chồng lên nhau thông qua trình điều khiển OverlayFS.
Cấu trúc phân lớp này tạo ra 3 bề mặt tấn công đặc thù trong chuỗi cung ứng phần mềm:
- Di sản lỗ hổng từ Base Image đa năng (
debian,ubuntu,node:latest): Các Base Image tiêu chuẩn đi kèm hàng trăm tiện ích hệ thống không cần thiết cho môi trường Production như trình biên dịchgcc, trình tải tệpcurl/wget, trình thông dịch/bin/bashvà các thư viện hệ thống lâu ngày chưa vá. Khi ứng dụng web bị khai thác lỗ hổng thực thi lệnh từ xa (RCE), kẻ tấn công tận dụng ngay/bin/shvàcurlcó sẵn trong container để tải mã độc đào tiền ảo hoặc công cụ rà quét mạng nội bộ (Living-off-the-Land). - Lỗ hổng ẩn sâu trong Cây phụ thuộc chuyển tiếp (Transitive Dependencies): Một dịch vụ Python FastAPI hoặc Node.js chỉ khai báo trực tiếp 15 thư viện trong
pyproject.tomlhoặcpackage.json, nhưng cây phụ thuộc thực tế tronguv.lockhoặcpnpm-lock.yamlcó thể kéo theo hơn 400 gói phụ trợ cấp 2, cấp 3 chứa các lỗ hổng thực thi mã tùy ý đã được công bố mã định danh CVE (Common Vulnerabilities and Exposures). - Ảo tưởng xóa tệp nhạy cảm giữa các Layer (
Layer Secret Persistence): Một sai lầm kinh điển là sao chép khóa SSH bí mật (id_ed25519), tệp.npmrchoặc.envvào container ở lệnhRUNthứ nhất để tải gói phần mềm nội bộ, sau đó chạyRUN rm -f /root/.ssh/id_ed25519ở tầng tiếp theo. Trong kiến trúc OverlayFS, lệnhrmchỉ tạo ra một tệp đánh dấu ẩn (Whiteout File.wh.id_ed25519) ở tầng trên cùng, trong khi toàn bộ nội dung khóa bí mật vẫn nằm nguyên vẹn dưới dạng văn bản rõ trong tệp.tar.gzcủa tầng bên dưới và có thể bị trích xuất chỉ bằng một lệnhdocker savehoặctrivy image --scanners secret.
1.2. Mô hình Phòng thủ 3 Tầng theo chuẩn NIST SP 800-190: Pre-Commit/CI Gate, Registry Continuous Scan và Runtime Admission
Một lỗ hổng CVE mới có thể được công bố vào lúc 2 giờ sáng — tức là 3 tuần sau khi container image đã vượt qua bài kiểm tra CI/CD và đang chạy trên Production. Do đó, tiêu chuẩn NIST SP 800-190 (Application Container Security Guide) khẳng định việc quét lỗ hổng tại một điểm duy nhất là không bao giờ đủ. Hệ thống bảo mật container và quét lỗ hổng với Trivy Clair phải được thiết kế thành 3 lớp phòng thủ liên hoàn:
- Tầng 1 — Chốt chặn Build & CI/CD Gate (Shift-Left với Trivy CLI): Quét trực tiếp
Dockerfile, tệp khóa phụ thuộc (go.sum,Cargo.lock,uv.lock), rò rỉ Secret và toàn bộ OCI Image vừa đóng gói ngay trên GitHub Actions / GitLab CI. Nếu phát hiện lỗ hổng mứcCRITICALhoặcHIGHđã có bản vá (--ignore-unfixed), pipeline lập tức trả về mã lỗi khác0và hủy bỏ quá trình đẩy ảnh lên Registry. - Tầng 2 — Giám sát Liên tục tại Kho lưu trữ (Registry Indexing với Clair v4 / Harbor): Lưu trữ biểu đồ thành phần của toàn bộ các ảnh trong kho lưu trữ doanh nghiệp (Quay, Harbor) vào cơ sở dữ liệu PostgreSQL và đối chiếu tự động mỗi khi cơ sở dữ liệu lỗ hổng toàn cầu (NVD, Red Hat OVAL, Debian Security Tracker, GitHub Advisory) cập nhật CVE mới, ngay cả khi không có bất kỳ lệnh build mới nào diễn ra.
- Tầng 3 — Kiểm soát Triển khai & Giám sát Runtime trên Kubernetes (Kyverno +
trivy-operator): Xác minh chữ ký số Sigstore Cosign và chứng nhận SBOM Attestation tại cổng Admission Webhook trước khi cho phép khởi tạo Pod, đồng thời dùngtrivy-operatorquét định kỳ các workload đang chạy thực tế trên cụm.
Sơ đồ dưới đây minh họa kiến trúc phòng thủ chuỗi cung ứng Container 3 tầng tích hợp Trivy, Clair v4, Cosign và Kyverno:
flowchart LR
subgraph Tier1["Tầng 1: Shift-Left CI/CD Gate (Trivy v0.58+)"]
Code["Mã nguồn + Dockerfile (Multi-Stage Distroless/Wolfi)"]
TrivyCI["Trivy CLI Scanner (CVE + Secret + Misconfig + OpenVEX)"]
CosignSign["Sigstore Cosign OIDC (Ký số Ảnh + Đính kèm SBOM CycloneDX 1.6)"]
Code --> TrivyCI
TrivyCI -->|"Pass (0 Critical/High)"| CosignSign
end
subgraph Tier2["Tầng 2: Registry Continuous Scan (Clair v4.8+)"]
Registry["Enterprise OCI Registry (Harbor / Red Hat Quay)"]
ClairIdx["Clair v4 Indexer (Giải nén Layer -> IndexManifest)"]
ClairMatch["Clair v4 Matcher & Notifier (Cập nhật NVD/OVAL Liên tục -> Webhook)"]
CosignSign -->|"Push Image + .sig + .att"| Registry
Registry --> ClairIdx
ClairIdx --> ClairMatch
end
subgraph Tier3["Tầng 3: Kubernetes v1.32+ Runtime Protection"]
Kyverno["Kyverno Admission Controller (Xác minh Chữ ký Cosign & SBOM)"]
K8sCluster["Pod Thực thi An toàn (Non-Root 65532 + ReadOnlyRootFS)"]
TrivyOp["Trivy Operator In-Cluster (Xuất CRD VulnerabilityReport Liên tục)"]
Registry -->|"Pull Image qua Digest"| Kyverno
Kyverno -->|"Chữ ký Hợp lệ"| K8sCluster
K8sCluster --> TrivyOp
end
2. Đặt lên bàn cân Kiến trúc: Aqua Security Trivy v0.58+ vs Quay Clair v4.8+
2.1. Kiến trúc Stateless CLI Đa năng của Trivy: Quét CVE, IaC Misconfig, Secret Leak và Khởi tạo SBOM
Trivy (do Aqua Security phát triển và duy trì mã nguồn mở) được thiết kế theo triết lý một tệp nhị phân đơn lẻ (Single Stateless Binary), không yêu cầu cài đặt cơ sở dữ liệu ngoài hay dịch vụ nền phức tạp khi chạy trên máy trạm của kỹ sư hoặc trong các runner tạm thời của CI/CD. Ở phiên bản Trivy v0.58+, công cụ này hoạt động bằng cách tải về một gói cơ sở dữ liệu lỗ hổng đã được biên dịch và nén tối ưu (trivy-db định dạng BoltDB lưu trên OCI Registry) chỉ mất vài giây, sau đó thực hiện 4 bộ quét (Scanners) trong cùng một lần duyệt hệ thống tệp:
vuln(Vulnerability Scanner): Nhận diện chính xác hệ điều hành cơ sở (Alpineapk, Debian/Ubuntudpkg, RHEL/Rockyrpm, Chainguard Wolfi) và các trình quản lý gói ngôn ngữ lập trình (pip/uv,npm/pnpm/yarn,Gobinary metadata,Cargo,Composer,Jar/War).misconfig(IaC & Configuration Scanner): Tích hợp bộ quy tắc kiểm tra lỗi cấu hình bảo mật trênDockerfile, Kubernetes YAML manifests, Helm Charts và Terraform HCL (dựa trên bộ máy chính sách Rego).secret(Secret Detection): Rà quét toàn bộ các layer của container image để phát hiện khóa AWS IAM, GitHub Personal Access Token, khóa riêng RSA/Ed25519 hoặc chuỗi kết nối cơ sở dữ liệu bị bỏ quên.license& SBOM Generator: Phân tích rủi ro bản quyền phần mềm (GPL/AGPL) và xuất trực tiếp danh mục thành phần phần mềm theo chuẩn CycloneDX1.6hoặc SPDX2.3.
2.2. Kiến trúc Vi dịch vụ hướng Sự kiện của Clair v4 (Indexer, Matcher, Notifier) cho Container Registry quy mô lớn
Ngược lại với mô hình dòng lệnh linh hoạt của Trivy, Clair v4.8+ (được phát triển bởi dự án Quay / Red Hat) là một hệ thống dịch vụ phân tán chuyên dụng để gắn kết sâu vào các hệ thống Enterprise Container Registry lưu trữ hàng trăm ngàn container image. Thay vì tải lại và giải nén toàn bộ các layer của ảnh mỗi khi cần kiểm tra lỗ hổng mới, Clair v4 chia kiến trúc thành 3 dịch vụ độc lập giao tiếp qua cơ sở dữ liệu PostgreSQL 17:
Indexer(Trình Lập chỉ mục): Khi một container image mới được đẩy lên Registry,Indexerchỉ tải các layer chưa từng xuất hiện (nhờ cơ chế chống trùng lặp theo mã bămsha256của layer), trích xuất danh sách gói phần mềm, thư viện và tệp phân phối, sau đó đóng gói thành một bản ghiIndexReportbất biến lưu vào PostgreSQL. Quá trình nặng nề này chỉ diễn ra đúng một lần duy nhất cho mỗi image digest.Matcher(Trình Đối chiếu Lỗ hổng): Chạy các trình cập nhật nền (Updaters) để đồng bộ liên tục dữ liệu lỗ hổng từ Red Hat Security Data (OVAL v2), Debian, Ubuntu, Alpine, AWS ALAS, Oracle Linux và NVD. Khi người dùng hoặc hệ thống gọi API kiểm tra một ảnh,Matcherchỉ cần thực hiện phép kết nối dữ liệu (SQL Join) tốc độ cao giữaIndexReportđã lưu sẵn và bảng lỗ hổng mới nhất để sinh raVulnerabilityReporttrong vài chục mili-giây mà không cần chạm lại vào tệp ảnh gốc.Notifier(Trình Thông báo Sự kiện): Theo dõi sự thay đổi giữa các lần cập nhật cơ sở dữ liệu CVE; nếu một CVE nghiêm trọng vừa được công bố làm ảnh hưởng tới bất kỳIndexReportnào đang lưu trong Registry,Notifiertự động bắn cảnh báo qua Webhook, AMQP hoặc STOMP tới hệ thống SIEM/Jira của đội ngũ bảo mật.
Bảng dưới đây tổng hợp tiêu chí lựa chọn và phối hợp giữa Trivy v0.58+ và Clair v4.8+ trong kiến trúc thực tế:
| Tiêu chí Kỹ thuật | Aqua Security Trivy (v0.58+) |
Red Hat / Quay Clair (v4.8+) |
|---|---|---|
| Mô hình Kiến trúc | CLI độc lập (Stateless) + Chế độ Client/Server + Kubernetes Operator (trivy-operator). |
Hệ thống Microservices có trạng thái (Indexer, Matcher, Notifier) + PostgreSQL Backend. |
| Vị trí Tối ưu trong Pipeline | Máy trạm Developer, chốt chặn CI/CD Pipeline Gate và quét Runtime trong cụm Kubernetes. | Tích hợp lõi cho Enterprise Container Registry (Red Hat Quay, Harbor) quản lý hàng vạn ảnh. |
| Phạm vi Quét Bảo mật | Toàn diện: OS CVEs, Language Packages, IaC Misconfigurations, Hardcoded Secrets, Licenses. | Chuyên sâu: OS Packages và Language Dependencies thông qua kiến trúc lưu trữ IndexReport. |
| Khởi tạo SBOM & Lọc VEX | Hỗ trợ xuất trực tiếp CycloneDX 1.6 / SPDX 2.3 và lọc cảnh báo giả bằng OpenVEX (--vex). |
Nhận diện thành phần qua IndexReport; thường kết hợp công cụ ngoài để ký SBOM Attestation. |
| Chi phí Vận hành Hạ tầng | Cực thấp (Chạy ngay trong job CI hoặc cài đặt qua 1 Helm Chart trên Kubernetes). | Trung bình – Cao (Cần vận hành cụm PostgreSQL HA và quản lý kết nối API với Registry). |
3. Hardening Container từ Gốc và Triển khai Trivy chặn Lỗ hổng CRITICAL/HIGH trên CI/CD
3.1. Tối ưu hóa Base Image: Loại bỏ >90% CVE từ gốc bằng Multi-Stage Build với Distroless / Chainguard Wolfi và Non-Root UID 65532
Cách hiệu quả nhất để xử lý lỗ hổng bảo mật trong container không phải là tốn hàng giờ vá từng gói hệ điều hành thừa thãi, mà là loại bỏ hoàn toàn hệ điều hành cơ sở và trình quản lý gói khỏi ảnh Runtime cuối cùng. Bằng cách áp dụng kỹ thuật đóng gói đa tầng — nguyên lý nền tảng đã được phân tích chi tiết trong bài viết tối ưu hóa Docker Image với Multi-Stage Build và Alpine Linux — kết hợp với ảnh Google Distroless (gcr.io/distroless/static-debian12:nonroot) hoặc Chainguard Wolfi (cgr.dev/chainguard/static:latest), chúng ta thu được một container chỉ chứa đúng tệp nhị phân đã biên dịch tĩnh, chứng chỉ gốc CA (ca-certificates) và dữ liệu múi giờ (tzdata).
Khi không còn /bin/sh, /bin/bash, apt, apk hay curl, bề mặt tấn công hệ điều hành giảm hơn 90%, đồng thời mọi nỗ lực khởi tạo Reverse Shell của kẻ tấn công đều thất bại ngay lập tức với lỗi exec: "/bin/sh": stat /bin/sh: no such file or directory.
Dưới đây là mẫu Dockerfile chuẩn DevSecOps 2026 sử dụng ghim mã băm bất biến (@sha256:...), cờ biên dịch chống tràn bộ nhớ và chạy dưới quyền người dùng không có đặc quyền USER 65532:65532 (nonroot):
# syntax=docker/dockerfile:1.10
# ==============================================================================
# STAGE 1: Builder — Biên dịch tĩnh mã nguồn trong môi trường cô lập
# Ghim chặt cả Tag và SHA-256 Digest để chống tấn công Tag Mutation trên Registry
# ==============================================================================
FROM golang:1.24.1-alpine3.21@sha256:4a9f9b3c8d1e2f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a AS builder
WORKDIR /build
# Chỉ sao chép tệp định nghĩa phụ thuộc trước để tận dụng bộ nhớ đệm BuildKit an toàn
COPY go.mod go.sum ./
RUN go mod download && go mod verify
COPY . .
# Biên dịch nhị phân tĩnh hoàn toàn (CGO_ENABLED=0), xóa bảng ký hiệu gỡ lỗi (-s -w)
# và nhúng thông tin Build VCS để Trivy có thể kiểm tra chính xác phiên bản Go module
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -trimpath -ldflags="-s -w -extldflags '-static'" \
-o /out/payment-authorizer ./cmd/authorizer
# ==============================================================================
# STAGE 2: Hardened Runtime — Sử dụng Distroless Non-Root (Không Shell, Không Package Manager)
# ==============================================================================
FROM gcr.io/distroless/static-debian12:nonroot@sha256:9f8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2c1b0a9f8e
WORKDIR /app
# Sao chép tệp thực thi với quyền chỉ đọc (0550) thuộc sở hữu của nonroot (65532:65532)
COPY --from=builder --chown=65532:65532 --chmod=0550 /out/payment-authorizer /app/payment-authorizer
# Bắt buộc thực thi bằng định danh số UID:GID 65532 (Phù hợp với runAsNonRoot: true trên K8s)
USER 65532:65532
EXPOSE 8443
ENTRYPOINT ["/app/payment-authorizer"]
3.2. Thiết lập cổng chặn Trivy trên GitHub Actions / GitLab CI và quản lý False Positives bằng chuẩn OpenVEX (--vex)
Khi tích hợp bước quét lỗ hổng vào quy trình tự động hóa — tương tự luồng xây dựng CI/CD Pipeline với GitHub Actions và Docker — thách thức lớn nhất mà các đội ngũ kỹ thuật gặp phải là hiện tượng Mệt mỏi vì cảnh báo (Alert Fatigue): một thư viện phụ thuộc có thể chứa một hàm bị lỗi CVE mức HIGH, nhưng ứng dụng của bạn hoàn toàn không bao giờ gọi tới hàm đó (Vulnerable Code Not in Execute Path).
Thay vì tắt toàn bộ công cụ quét hoặc thêm mã CVE vào tệp .trivyignore thiếu ngữ cảnh kiểm toán, chuẩn công nghiệp năm 2026 sử dụng đặc tả OpenVEX (Vulnerability Exploitability eXchange). Tệp tài liệu .openvex.json cho phép kỹ sư bảo mật ghi nhận trạng thái not_affected kèm lý do kỹ thuật chuẩn hóa (vulnerable_code_not_in_execute_path hoặc inline_mitigations_already_exist). Khi chạy lệnh trivy image --vex security/payment-authorizer.openvex.json, Trivy sẽ tự động loại trừ các CVE đã được xác minh không thể khai thác mà vẫn giữ nguyên tính nghiêm ngặt cho mọi lỗ hổng mới phát sinh.
Dưới đây là cấu hình GitHub Actions hoàn chỉnh thực thi kiểm tra Dockerfile (trivy config), quét lỗ hổng ảnh + Secret (trivy image), xuất danh mục SBOM CycloneDX 1.6 và ký số không cần khóa tĩnh (Keyless OIDC Signing) bằng Sigstore Cosign:
# File: .github/workflows/container-secops-gate.yml
# Pipeline DevSecOps: Build -> Trivy Scan (CVE + Secret + OpenVEX) -> CycloneDX 1.6 SBOM -> Cosign OIDC Sign
name: Container Supply Chain Security Gate
on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
permissions:
contents: read
packages: write
security-events: write
id-token: write # Bắt buộc để Sigstore Cosign xin cấp chứng chỉ ngắn hạn qua OIDC
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}/payment-authorizer
jobs:
build-scan-sign:
runs-on: ubuntu-24.04
steps:
- name: Checkout Source Code
uses: actions/checkout@v4
- name: 1. Quét lỗi cấu hình bảo mật trên Dockerfile & K8s Manifests (Trivy Config)
uses: aquasecurity/[email protected]
with:
scan-type: "config"
scan-ref: "."
severity: "CRITICAL,HIGH"
exit-code: "1"
- name: 2. Đóng gói Container Image chuẩn OCI
run: |
docker build --tag "${REGISTRY}/${IMAGE_NAME}:${GITHUB_SHA}" .
- name: 3. Quét CVE & Secret Leak với bộ lọc OpenVEX (Chặn đứng Build nếu có lỗi chưa vá)
uses: aquasecurity/[email protected]
with:
image-ref: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}"
scanners: "vuln,secret,misconfig"
severity: "CRITICAL,HIGH"
ignore-unfixed: true
vex: "security/payment-authorizer.openvex.json"
format: "sarif"
output: "trivy-results.sarif"
exit-code: "1"
- name: 4. Khởi tạo danh mục thành phần phần mềm SBOM chuẩn CycloneDX v1.6
uses: aquasecurity/[email protected]
with:
image-ref: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}"
format: "cyclonedx"
output: "sbom-cyclonedx-1.6.json"
- name: 5. Đẩy Image lên Registry và Ký số Keyless OIDC + Đính kèm SBOM bằng Cosign
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | docker login "${REGISTRY}" -u "${{ github.actor }}" --password-stdin
docker push "${REGISTRY}/${IMAGE_NAME}:${GITHUB_SHA}"
IMAGE_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "${REGISTRY}/${IMAGE_NAME}:${GITHUB_SHA}")
# Ký số ảnh bằng danh tính OIDC của GitHub Actions (ghi nhật ký bất biến lên Rekor Transparency Log)
cosign sign --yes "${IMAGE_DIGEST}"
# Đính kèm chứng nhận SBOM CycloneDX 1.6 vào đúng mã băm SHA-256 của Image
cosign attest --yes --predicate sbom-cyclonedx-1.6.json --type cyclonedx "${IMAGE_DIGEST}"
4. Triển khai Clair v4 / Harbor Quét Liên tục và Khởi tạo SBOM (CycloneDX 1.6) kèm Chữ ký Số Cosign
4.1. Cấu hình Clair v4.8+ (config.yaml) tích hợp cơ sở dữ liệu PostgreSQL 17 và Webhook cảnh báo lỗ hổng mới
Khi ảnh container đã vượt qua cổng CI/CD và được lưu trữ tại kho Registry nội bộ (như Red Hat Quay hoặc CNCF Harbor), Clair v4.8+ đảm nhận vai trò canh gác 24/7 trước các lỗ hổng Zero-Day hoặc các CVE mới được công bố sau thời điểm đóng gói ảnh.
Trong môi trường Production, Clair v4 nên được triển khai với xác thực token đối xứng/bất đối xứng (psk hoặc keyserver) giữa Registry và Clair API, sử dụng cơ sở dữ liệu PostgreSQL 17 tách biệt cho Indexer, Matcher và Notifier, đồng thời cấu hình chu kỳ đồng bộ dữ liệu CVE (updater_sets) mỗi 2 giờ. Dưới đây là tệp cấu hình /etc/clair/config.yaml chuẩn Production cho Clair v4.8+:
# File: /etc/clair/config.yaml
# Cấu hình triển khai Quay Clair v4.8+ ở chế độ Combo (Indexer + Matcher + Notifier) trên Production
http_listen_addr: "0.0.0.0:6060"
introspection_addr: "0.0.0.0:8089" # Cổng xuất Prometheus Metrics (/metrics) và Healthz (/healthz)
log_level: "info"
# 1. Cấu hình Dịch vụ Indexer: Bóc tách Layer và lưu trữ IndexReport vào PostgreSQL 17
indexer:
connstring: "host=pg-clair-prod.infoteck.internal port=5432 dbname=clair_indexer user=clair_idx sslmode=verify-full"
scanlock_retry: 10
layer_scan_concurrency: 8
migrations: true
airgap: false
# 2. Cấu hình Dịch vụ Matcher: Đồng bộ nguồn dữ liệu CVE toàn cầu và đối chiếu tốc độ cao
matcher:
connstring: "host=pg-clair-prod.infoteck.internal port=5432 dbname=clair_matcher user=clair_match sslmode=verify-full"
max_conn_pool: 50
migrations: true
indexer_addr: "https://clair-indexer.infoteck.internal:6060"
period: "2h0m0s" # Chu kỳ tải bản cập nhật cơ sở dữ liệu lỗ hổng mới
disable_updaters: false
updater_sets:
- "rhel"
- "debian"
- "ubuntu"
- "alpine"
- "osv" # Bao gồm Go, PyPI, npm, Rust Cargo, Maven từ cơ sở dữ liệu OSV
- "wolfi" # Nguồn dữ liệu bảo mật cho Chainguard Wolfi OS
# 3. Cấu hình Dịch vụ Notifier: Bắn Webhook tức thì sang SIEM/SecOps khi phát hiện CVE mới
notifier:
connstring: "host=pg-clair-prod.infoteck.internal port=5432 dbname=clair_notifier user=clair_notify sslmode=verify-full"
migrations: true
indexer_addr: "https://clair-indexer.infoteck.internal:6060"
matcher_addr: "https://clair-matcher.infoteck.internal:6060"
poll_interval: "15m0s"
delivery_interval: "1m0s"
webhook:
target: "https://secops-webhook.infoteck.internal/v1/alerts/clair-cve"
callback: "https://clair.infoteck.internal:6060/notifier/api/v1/notifications/"
headers:
X-SecOps-Source: ["clair-v4-production"]
# 4. Xác thực API nội bộ giữa Container Registry (Quay/Harbor) và cụm Clair v4
auth:
psk:
key: "${CLAIR_REGISTRY_SHARED_BASE64_KEY}"
iss:
- "quay-enterprise-registry"
- "harbor-core-scanner"
4.2. Chuỗi cung ứng chống giả mạo (SLSA Level 3): Xuất SBOM CycloneDX 1.6 và Ký số Keyless OIDC với Sigstore Cosign
Theo khung tiêu chuẩn bảo mật chuỗi cung ứng SLSA (Supply-chain Levels for Software Artifacts) v1.0 và sắc lệnh an ninh mạng quốc gia Hoa Kỳ, mọi gói phần mềm triển khai vào hạ tầng trọng yếu đều phải đi kèm một bảng kê khai nguyên vật liệu phần mềm (SBOM — Software Bill of Materials) ở định dạng máy đọc được (CycloneDX 1.6) và được ký số mật mã không thể chối bỏ.
Trước đây, việc ký container image bằng Docker Content Trust (Notary v1) rất phức tạp vì đội ngũ DevOps phải tự lưu trữ, bảo vệ và xoay vòng các khóa riêng dài hạn. Năm 2026, bộ công cụ Sigstore (Cosign + Fulcio CA + Rekor Transparency Log) đã cách mạng hóa quy trình này bằng cơ chế Keyless OIDC Signing:
- Khi job CI/CD trên GitHub Actions hoặc GitLab CI hoàn tất bước quét Trivy,
cosigntạo một cặp khóa bất đối xứng tạm thời (Ephemeral Keypair) chỉ tồn tại trong bộ nhớ RAM và gửi kèm mã định danh OIDC Token của CI Runner tới tổ chức cấp phát chứng chỉ gốc Fulcio. - Fulcio xác minh danh tính của workflow (đúng kho mã nguồn, đúng nhánh
main, đúng commit SHA) và cấp một chứng chỉ X.509 có thời hạn sống chỉ 10 phút. cosignký lên mã bămsha256của Container Image cùng tệp đính kèm SBOM CycloneDX 1.6, ghi dấu thời gian xác thực vào sổ cái minh bạch công khai Rekor, sau đó xóa hủy ngay lập tức khóa riêng tạm thời trong RAM. Nhờ đó, không có bất kỳ khóa bí mật dài hạn nào có thể bị kẻ tấn công đánh cắp!
5. Bảo vệ Tầng Runtime Kubernetes v1.32+ với trivy-operator, Kyverno và SecurityContext Nghiêm ngặt
5.1. Chặn đứng Image chưa quét hoặc chưa ký bằng Kyverno Admission Controller (verifyImages)
Mọi công sức quét lỗ hổng trên CI/CD và Registry sẽ trở nên vô nghĩa nếu một quản trị viên vô tình (hoặc kẻ tấn công có quyền kubectl) chạy lệnh kubectl run debug --image=ubuntu:latest để kéo một ảnh chưa kiểm duyệt trực tiếp lên cụm Kubernetes Production — đặc biệt là trên các hạ tầng triển khai cụm Kubernetes High Availability trên Bare-Metal hoặc một nền tảng triển khai kiến trúc Zero Trust Security trong doanh nghiệp.
Để đóng sập cánh cửa này, chúng ta triển khai Kyverno Admission Controller ở chế độ Enforce. Sơ đồ tuần tự dưới đây minh họa toàn bộ vòng đời từ lúc kiểm duyệt trên CI/CD cho đến khi Kyverno xác minh chữ ký số và SBOM trước khi cho phép Kubelet khởi tạo Pod:
sequenceDiagram
autonumber
participant CIPipeline as GitHub Actions CI Runner
participant TrivyCLI as Trivy v0.58+ Scanner
participant OCIRegistry as Harbor / Quay Registry (Clair v4)
participant CosignRekor as Sigstore Fulcio & Rekor Log
participant KyvernoWebhook as K8s Kyverno Admission Webhook
CIPipeline->>TrivyCLI: 1. Quét Dockerfile, CVE (Critical/High), Secret & Xuất SBOM CycloneDX 1.6
Note over TrivyCLI: Áp dụng bộ lọc OpenVEX — Kết quả: 0 Critical/High Unfixed -> PASS
TrivyCLI-->>CIPipeline: 2. Trả mã thoát 0 + Tệp sbom-cyclonedx-1.6.json
CIPipeline->>OCIRegistry: 3. Push OCI Image và lấy mã băm bất biến (@sha256:...)
CIPipeline->>CosignRekor: 4. Ký số Keyless OIDC lên Image Digest & Đính kèm SBOM Attestation
CosignRekor-->>OCIRegistry: 5. Lưu trữ chữ ký (.sig) và chứng nhận SBOM (.att) cùng Image
Note over OCIRegistry: Clair v4 Indexer giải nén Layer và giám sát CVE mới liên tục 24/7
CIPipeline->>KyvernoWebhook: 6. Yêu cầu triển khai Pod (kubectl apply / ArgoCD Sync)
KyvernoWebhook->>OCIRegistry: 7. Kiểm tra chữ ký Cosign OIDC & Xác minh tồn tại SBOM CycloneDX
OCIRegistry-->>KyvernoWebhook: 8. Xác nhận Chữ ký & SBOM Hợp lệ -> Cho phép khởi tạo Pod
5.2. Giám sát liên tục trong cụm với trivy-operator và Khóa chặt Pod securityContext
Dưới đây là cấu hình hoàn chỉnh gồm hai phần: (1) Chính sách ClusterPolicy của Kyverno ép buộc mọi Pod trong các namespace sản xuất phải được ký bởi đúng workflow CI/CD của tổ chức kèm chứng nhận SBOM, và (2) Manifest Deployment áp dụng chuẩn Pod Security Standards (PSS) mức Restricted (runAsNonRoot: true, readOnlyRootFilesystem: true, allowPrivilegeEscalation: false, capabilities.drop: ["ALL"], seccompProfile: RuntimeDefault):
# File: k8s-kyverno-cosign-and-hardened-deployment.yaml
# 1. Chính sách Kyverno Admission Controller: Chặn mọi Image chưa ký số Cosign hoặc thiếu SBOM
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: enforce-signed-and-scanned-images
spec:
validationFailureAction: Enforce
background: false
webhookTimeoutSeconds: 15
rules:
- name: verify-cosign-oidc-signature-and-sbom
match:
any:
- resources:
kinds: ["Pod"]
namespaces: ["checkout", "payments", "production"]
verifyImages:
- imageReferences:
- "ghcr.io/infoteck-org/*"
mutateDigest: true # Tự động chuyển đổi Tag thành mã băm @sha256 bất biến
verifyDigest: true
required: true
attestors:
- entries:
- keyless:
issuer: "https://token.actions.githubusercontent.com"
subject: "https://github.com/infoteck-org/payment-service/.github/workflows/container-secops-gate.yml@refs/heads/main"
rekor:
url: "https://rekor.sigstore.dev"
attestations:
- type: "https://cyclonedx.org/bom"
conditions:
- all:
- key: "{{ bomFormat }}"
operator: Equals
value: "CycloneDX"
---
# 2. Deployment thực thi chuẩn bảo mật Pod Security Standards (PSS) mức Restricted
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-authorizer
namespace: payments
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: payment-authorizer
template:
metadata:
labels:
app.kubernetes.io/name: payment-authorizer
spec:
automountServiceAccountToken: false # Tắt tự động gắn K8s Token nếu Pod không gọi K8s API
securityContext:
runAsNonRoot: true
runAsUser: 65532
runAsGroup: 65532
fsGroup: 65532
seccompProfile:
type: RuntimeDefault # Chặn các lời gọi hệ thống (syscalls) nguy hiểm của Linux Kernel
containers:
- name: authorizer
image: ghcr.io/infoteck-org/payment-service/payment-authorizer@sha256:4b8e9a1c2d3f4e5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f90
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true # Ngăn chặn tuyệt đối việc ghi mã độc lên hệ thống tệp của Container
capabilities:
drop:
- ALL
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1000m"
memory: "512Mi"
volumeMounts:
- name: tmp-scratch
mountPath: /tmp
volumes:
- name: tmp-scratch
emptyDir:
medium: Memory
sizeLimit: "64Mi"
Song song với Kyverno ở cổng vào, việc cài đặt trivy-operator trực tiếp vào cụm Kubernetes giúp đội ngũ SRE tự động hóa hoàn toàn việc kiểm toán các Pod đang chạy thông qua các Custom Resource Definitions (VulnerabilityReport, ConfigAuditReport, ExposedSecretReport, SbomReport) và xuất số liệu trực tiếp ra Prometheus:
#!/usr/bin/env bash
# File: install-and-query-trivy-operator.sh
# Triển khai trivy-operator trên Kubernetes v1.32+ và truy vấn báo cáo lỗ hổng thời gian thực
set -Eeuo pipefail
# 1. Cài đặt Aqua Security trivy-operator qua Helm với tính năng xuất Metrics cho Prometheus
helm repo add aqua https://aquasecurity.github.io/helm-charts/
helm repo update
helm upgrade --install trivy-operator aqua/trivy-operator \
--namespace trivy-system \
--create-namespace \
--version 0.25.0 \
--set="trivy.ignoreUnfixed=true" \
--set="trivy.severity=CRITICAL\,HIGH" \
--set="serviceMonitor.enabled=true" \
--set="operator.sbomGenerationEnabled=true"
# 2. Kiểm tra tổng hợp số lượng CVE mức CRITICAL và HIGH của các Workload trong namespace 'payments'
kubectl get vulnerabilityreports -n payments -o wide
# 3. Trích xuất danh sách chi tiết các gói bị lỗi CRITICAL từ CRD VulnerabilityReport bằng jq
kubectl get vulnerabilityreports -n payments -o json \
| jq -r '.items[] | .metadata.name as $rpt | .report.vulnerabilities[] | select(.severity=="CRITICAL") | "\($rpt): \(.vulnerabilityID) (\(.resource) installed=\(.installedVersion) fixed=\(.fixedVersion))"'
6. Checklist Kiểm toán Bảo mật Container DevSecOps & Tài liệu Tham khảo Chuẩn Kỹ thuật
6.1. Bảng Checklist 8 Bước Nghiệm thu Bảo mật Chuỗi cung ứng Container trước khi lên Production
Trước khi phê duyệt bất kỳ dịch vụ container hóa nào đi vào môi trường Production, kỹ sư DevSecOps cần đối chiếu danh sách kiểm tra 8 điểm sau:
- Loại bỏ Shell và Package Manager ở tầng Runtime: Đã chuyển sang sử dụng Multi-Stage Build với ảnh đích là Distroless (
static/base-debian12:nonroot) hoặc Chainguard Wolfi chưa? - Ghim chặt Image Digest (
@sha256:...): Mọi chỉ thịFROMtrongDockerfilevà trườngimage:trong Kubernetes Manifest đã được khóa bằng mã băm SHA-256 thay vì dùng nhãn động:latestchưa? - Cổng chặn Trivy trên CI/CD (
exit-code: 1): Đường ống CI/CD đã cấu hình chặn tự động các bản build chứa lỗ hổngCRITICAL/HIGHđã có bản vá (--ignore-unfixed) và rò rỉ khóa bí mật (--scanners vuln,secret,misconfig) chưa? - Quản lý cảnh báo giả minh bạch với OpenVEX: Mọi ngoại lệ CVE đã được ghi nhận có thời hạn và lý do kỹ thuật rõ ràng trong tệp
.openvex.jsonthay vì bỏ qua mù quáng chưa? - Khởi tạo và lưu trữ SBOM CycloneDX 1.6: Mỗi bản phát hành đã đính kèm tệp danh mục thành phần phần mềm chuẩn CycloneDX
1.6để sẵn sàng truy vết trong 60 giây khi có cảnh báo Zero-Day mới chưa? - Quét liên tục tại Registry bằng Clair v4: Kho lưu trữ ảnh nội bộ (Quay/Harbor) đã bật trình đối chiếu liên tục của Clair
v4.8+kết nối Webhook cảnh báo về SIEM chưa? - Ký số Cosign OIDC và Xác minh tại Kyverno: Cụm Kubernetes đã bật
ClusterPolicycủa Kyverno/Connaisseur để từ chối mọi container image không có chữ ký số hợp lệ từ đường ống CI/CD chưa? - Thực thi Pod Security Standards
Restricted: Toàn bộ Pod đã bậtrunAsNonRoot: true(UID 65532),readOnlyRootFilesystem: true,allowPrivilegeEscalation: false,drop: ["ALL"]vàseccompProfile: RuntimeDefaultchưa?
6.2. Chiến lược Xử lý Khẩn cấp khi Phát hiện Lỗ hổng Zero-Day trên Môi trường Production
Khi hệ thống Notifier của Clair v4 hoặc trivy-operator phát cảnh báo về một lỗ hổng Zero-Day mức CRITICAL (điểm CVSS v4.0 $\ge 9.0$) vừa xuất hiện trên một thư viện đang chạy trong cụm:
- Bước 1 (Trong 15 phút đầu): Truy vấn ngay các tài nguyên
SbomReportvàVulnerabilityReporttrên cụm Kubernetes (hoặc cơ sở dữ liệuIndexReportcủa Clair v4) để lập danh sách chính xác 100% các Pod và Namespace chứa phiên bản thư viện bị ảnh hưởng mà không cần phải quét lại từ đầu. - Bước 2 (Trong 30 phút tiếp theo): Đánh giá khả năng khai thác thực tế. Nếu hàm lỗi không nằm trên đường dẫn thực thi hoặc đã bị chặn bởi
readOnlyRootFilesystemvàCiliumNetworkPolicy, phát hành ngay bản cập nhật OpenVEX tạm thời trong khi chờ bản vá chính thức. Nếu lỗ hổng có thể bị khai thác từ xa và đã có bản vá thượng nguồn, kích hoạt pipeline CI/CD xây dựng lại ảnh mới, ký số Cosign và cuộn bản cập nhật (Rolling Update) qua ArgoCD.
6.3. Tài liệu Tham khảo & Nguồn Chuẩn Kỹ thuật (Primary Technical References)
Các cấu hình, thông số kiến trúc và tiêu chuẩn bảo mật container trong bài viết này được trích dẫn và kiểm chứng từ các nguồn tài liệu gốc dưới đây:
- Aqua Security Trivy Official Documentation — Comprehensive Container, Secret, IaC & SBOM Vulnerability Scanner (v0.58+)
- Quay Clair v4 Official Documentation — Enterprise Container Vulnerability Indexing & Matching Architecture (
Indexer,Matcher,Notifier) - NIST Special Publication 800-190 — Application Container Security Guide (National Institute of Standards and Technology)
- OWASP Docker Security Cheat Sheet — Container Hardening, Non-Root Execution & Capability Dropping
- OWASP CycloneDX v1.6 Specification — Standard for Software Bill of Materials (SBOM) & Vulnerability Exploitability
- Sigstore Cosign Official Documentation — Keyless OIDC Container Signing, Fulcio CA & Rekor Transparency Log
- Kyverno Official Documentation — Kubernetes Admission Control & Container Image Signature Verification (
verifyImages)