บทนำ: ทำไมความปลอดภัยของซัพพลายเชนซอฟต์แวร์จึงสำคัญขนาดนี้ในปี 2026
ถ้าคุณยังคิดว่าแอปพลิเคชันของคุณถูกเขียนขึ้นมา "จากศูนย์" ล่ะก็ ลองมองให้ดีอีกทีนะครับ ในโลกของการพัฒนาซอฟต์แวร์สมัยใหม่ ทุกระบบล้วนพึ่งพาไลบรารีโอเพนซอร์ส เครื่องมือบิลด์ ระบบ CI/CD และ container images จากบุคคลที่สาม ความซับซ้อนตรงนี้แหละที่กลายเป็นช่องทางให้ผู้โจมตีแทรกซึมระบบขนาดใหญ่ได้โดยที่องค์กรไม่รู้ตัวเลย
ลองนึกถึงเหตุการณ์สำคัญที่เปลี่ยนมุมมองของอุตสาหกรรมต่อ supply chain security ดูครับ การโจมตี SolarWinds ในปี 2020 ผู้โจมตีฝัง backdoor ลงในซอฟต์แวร์ Orion ก่อนที่จะถูกส่งไปยังลูกค้ากว่า 18,000 ราย รวมถึงหน่วยงานรัฐบาลสหรัฐระดับสูงสุด ต่อมาในปี 2021 ช่องโหว่ Log4Shell ใน Apache Log4j เผยให้เห็นว่าไลบรารีขนาดเล็กที่ฝังอยู่ในระบบนับล้านสามารถกลายเป็นระเบิดเวลาได้อย่างไร
และที่น่ากลัวที่สุด? เหตุการณ์ XZ Utils backdoor ในปี 2024 ที่ผู้โจมตีอดทนสร้างความน่าเชื่อถือในโปรเจกต์โอเพนซอร์สนานกว่า 2 ปี เพื่อแทรก backdoor ลงใน SSH daemon อันนี้พูดตรงๆ เลยว่าน่าขนลุกมาก
ในปี 2026 แนวโน้มได้เปลี่ยนจาก "ตั้งรับเมื่อถูกโจมตี" (reactive) ไปสู่ "ป้องกันเชิงรุก" (proactive) อย่างชัดเจน คำสั่ง EO 14028 ของสหรัฐอเมริกากำหนดให้หน่วยงานรัฐต้องใช้ Software Bill of Materials (SBOM) สำหรับซอฟต์แวร์ทุกชิ้น กรอบงาน SLSA กลายเป็นมาตรฐานอุตสาหกรรม และ Sigstore ก็ได้รับการยอมรับอย่างกว้างขวางในฐานะโครงสร้างพื้นฐานสำหรับการลงนามซอฟต์แวร์แบบ keyless
มาเลยครับ บทความนี้จะพาคุณผ่านทุกแง่มุมของ Linux Software Supply Chain Security อย่างละเอียด ตั้งแต่การสร้าง SBOM ด้วย Syft ไปจนถึงการสร้าง DevSecOps pipeline ที่ครบวงจร
ทำความเข้าใจ SBOM: รากฐานของความปลอดภัยซัพพลายเชน
SBOM คืออะไร
Software Bill of Materials (SBOM) พูดง่ายๆ ก็คือ "รายการส่วนผสม" ของซอฟต์แวร์ คล้ายกับฉลากบนกล่องอาหารที่บอกว่ามีอะไรบ้างอยู่ข้างใน SBOM ที่ดีจะประกอบด้วยข้อมูลเหล่านี้สำหรับแต่ละ component:
- ชื่อและเวอร์ชันของ package/library
- ผู้ผลิต (supplier) และผู้เขียน (author)
- ใบอนุญาตการใช้งาน (license)
- hash ของไฟล์ (checksums)
- ความสัมพันธ์กับ component อื่น (dependencies)
- ข้อมูล vulnerability ที่ทราบ
SPDX เทียบกับ CycloneDX
มาตรฐาน SBOM ที่ได้รับการยอมรับตอนนี้มีสองรูปแบบหลักครับ
SPDX (Software Package Data Exchange) เป็นมาตรฐาน ISO/IEC 5962:2021 พัฒนาโดย Linux Foundation ออกแบบมาเพื่อการแชร์ข้อมูล license และ compliance เป็นหลัก รองรับรูปแบบ tag-value, JSON, YAML, RDF และ spreadsheet โดย SPDX 2.3 เพิ่มการรองรับ security vulnerabilities และ SBOM relationships อย่างครบครัน
CycloneDX พัฒนาโดย OWASP มุ่งเน้นด้าน security โดยเฉพาะ มี VEX (Vulnerability Exploitability eXchange) ในตัว เหมาะมากสำหรับ DevSecOps pipeline มีโครงสร้าง JSON/XML ที่กระชับ แถม tool ecosystem ยังหลากหลายอีกด้วย
ในทางปฏิบัติสำหรับปี 2026 ต้องบอกว่า CycloneDX ได้รับความนิยมมากกว่าในกระบวนการ DevSecOps เนื่องจาก tooling ที่สมบูรณ์กว่า ส่วน SPDX มักถูกใช้เวลาต้องรายงานต่อหน่วยงานรัฐบาล
ทำไม SBOM จึงกลายเป็นข้อบังคับ
ตัวเลขนี้น่าสนใจมากครับ ตามการศึกษาของ Ponemon Institute ที่เผยแพร่ในปี 2025 องค์กรที่ใช้ SBOM อย่างเป็นระบบมี Mean Time to Remediate (MTTR) สำหรับช่องโหว่ใน dependencies สั้นกว่าองค์กรที่ไม่มี SBOM ถึง 264 วัน เลยทีเดียว เมื่อเกิดช่องโหว่อย่าง Log4Shell องค์กรที่มี SBOM พร้อมสามารถระบุได้ภายในชั่วโมงว่าระบบใดบ้างที่โดน ขณะที่องค์กรที่ไม่มีต้องใช้เวลาเป็นสัปดาห์หรือเดือนในการสำรวจ
นอกจากคำสั่ง EO 14028 ของสหรัฐฯ แล้ว สหภาพยุโรปยังกำหนดผ่าน Cyber Resilience Act ให้ผู้ผลิตซอฟต์แวร์ต้องจัดทำ SBOM สำหรับผลิตภัณฑ์ทุกชิ้นที่วางจำหน่ายในตลาด EU ภาคเอกชนเองก็เริ่มกำหนดให้ vendor ต้องส่งมอบ SBOM เป็นส่วนหนึ่งของสัญญาจัดซื้อจัดจ้างแล้ว
การสร้าง SBOM ด้วย Syft
การติดตั้ง Syft บน Linux
Syft เป็นเครื่องมือโอเพนซอร์สจาก Anchore สำหรับสร้าง SBOM รองรับ filesystems, container images, archives และ directories ได้ครบ ติดตั้งง่ายมากครับ ทำได้หลายวิธี:
# ติดตั้งผ่าน installation script (แนะนำ)
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
# ตรวจสอบเวอร์ชัน
syft version
# ติดตั้งผ่าน package manager บน Ubuntu/Debian
wget https://github.com/anchore/syft/releases/download/v1.19.0/syft_1.19.0_linux_amd64.deb
sudo dpkg -i syft_1.19.0_linux_amd64.deb
# ติดตั้งผ่าน Homebrew (บน Linux ที่มี Linuxbrew)
brew install syft
การสร้าง SBOM จาก Filesystem
การสร้าง SBOM จากไดเรกทอรีของโปรเจกต์ทำได้ตรงไปตรงมามาก:
# สร้าง SBOM จาก directory ปัจจุบัน (รูปแบบ table สำหรับดูทั่วไป)
syft dir:/path/to/your/project
# สร้าง SBOM รูปแบบ JSON
syft dir:/path/to/your/project -o json > sbom.json
# สร้าง SBOM รูปแบบ SPDX JSON
syft dir:/path/to/your/project -o spdx-json > sbom.spdx.json
# สร้าง SBOM รูปแบบ CycloneDX JSON (แนะนำสำหรับ DevSecOps)
syft dir:/path/to/your/project -o cyclonedx-json > sbom.cdx.json
# สร้าง SBOM รูปแบบ CycloneDX XML
syft dir:/path/to/your/project -o cyclonedx-xml > sbom.cdx.xml
# สร้าง SBOM พร้อมระบุ version ของแอปพลิเคชัน
syft dir:/path/to/your/project -o cyclonedx-json \
--source-name "my-application" \
--source-version "v2.3.1" \
> sbom.cdx.json
การสร้าง SBOM จาก Container Image
ส่วนนี้สำคัญมากในกระบวนการ DevSecOps เพราะ container image คือสิ่งที่ถูก deploy จริงๆ:
# สร้าง SBOM จาก container image บน Docker Hub
syft ubuntu:22.04 -o cyclonedx-json > ubuntu-sbom.cdx.json
# สร้าง SBOM จาก image ใน local Docker daemon
syft docker:my-app:latest -o cyclonedx-json > my-app-sbom.cdx.json
# สร้าง SBOM จาก image ใน OCI registry
syft registry:ghcr.io/myorg/my-app:v1.2.3 -o cyclonedx-json > my-app-sbom.cdx.json
# สร้าง SBOM จาก image tar archive
syft docker-archive:my-image.tar -o spdx-json > sbom.spdx.json
# สร้าง SBOM พร้อม output หลายรูปแบบพร้อมกัน
syft registry:ghcr.io/myorg/my-app:v1.2.3 \
-o cyclonedx-json=sbom.cdx.json \
-o spdx-json=sbom.spdx.json \
-o syft-json=sbom.syft.json
การกำหนดค่า Syft ด้วยไฟล์ config
สำหรับการใช้งานใน CI/CD pipeline ผมแนะนำให้สร้างไฟล์ config เพื่อความสม่ำเสมอ แบบนี้ทุกคนในทีมก็จะได้ SBOM ออกมาในรูปแบบเดียวกัน:
# .syft.yaml
output:
- "cyclonedx-json"
- "spdx-json"
file:
metadata:
digests:
- "sha256"
- "sha512"
package:
search-unindexed-archives: true
search-indexed-archives: true
catalogers:
enabled:
- dpkgdb
- rpm
- go-module-binary
- python
- javascript-package
- javascript-lock
- java-archive
- rust-cargo-lock
- ruby-gemfile
การสแกนช่องโหว่ด้วย Grype
การติดตั้งและทำความเข้าใจ Grype
Grype เป็นเครื่องมือสแกนช่องโหว่จาก Anchore เช่นกัน ทำงานร่วมกับ Syft ได้อย่างราบรื่นมาก (ไม่น่าแปลกใจเลยเพราะมาจากทีมเดียวกัน) สามารถสแกนทั้ง SBOM files และ container images โดยตรง โดยฐานข้อมูลช่องโหว่รวบรวมมาจากหลายแหล่ง ได้แก่ NVD, GitHub Security Advisories, Red Hat, Debian, Ubuntu และอื่นๆ
# ติดตั้ง Grype
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
# ตรวจสอบเวอร์ชันและอัปเดต vulnerability database
grype version
grype db update
# ดูข้อมูล database ปัจจุบัน
grype db status
การสแกน SBOM และ Container Images
# สแกนจาก SBOM file ที่สร้างไว้แล้ว (เร็วที่สุด ไม่ต้องวิเคราะห์ซ้ำ)
grype sbom:./sbom.cdx.json
# สแกน container image โดยตรง
grype ubuntu:22.04
# สแกน image จาก registry
grype registry:ghcr.io/myorg/my-app:v1.2.3
# สแกนและแสดงเฉพาะ High และ Critical severity
grype sbom:./sbom.cdx.json --fail-on high
# สแกนและ output เป็น JSON สำหรับ automated processing
grype sbom:./sbom.cdx.json -o json > vulnerabilities.json
# สแกนและ output เป็น table (อ่านง่ายกว่า)
grype sbom:./sbom.cdx.json -o table
# สแกนพร้อมกำหนด severity threshold (pipeline จะ fail ถ้าเจอ critical)
grype sbom:./sbom.cdx.json --fail-on critical
echo "Exit code: $?"
การตีความผลลัพธ์และการจัดการ False Positives
เรื่องนี้สำคัญมากครับ Grype รองรับการสร้าง ignore rules เพื่อจัดการกับ false positives หรือช่องโหว่ที่ยังไม่มี fix ไม่งั้น pipeline คุณจะ fail ตลอดเวลาโดยไม่จำเป็น:
# .grype.yaml - ไฟล์ config สำหรับ Grype
ignore:
# ละเว้น CVE ที่ทราบว่าไม่ส่งผลกระทบต่อระบบของเรา
- vulnerability: CVE-2023-44487
reason: "HTTP/2 rapid reset attack - mitigated by load balancer"
# ละเว้นตาม package และ version range
- package:
name: openssl
version: "< 3.0.0"
type: rpm
reason: "Legacy system - scheduled for upgrade Q2 2026"
# ละเว้น vulnerability ที่ fix ยังไม่พร้อมใช้งาน
- vulnerability: CVE-2024-12345
fix-state: "not-fixed"
# กำหนด severity ที่ต้องการ fail
fail-on-severity: high
# อัปเดต database อัตโนมัติ
db:
auto-update: true
การผสาน Grype เข้ากับ CI/CD
นี่คือ script ที่ใช้งานจริงได้เลยใน CI/CD pipeline ครับ:
#!/bin/bash
# scan-and-gate.sh - Script สำหรับใช้ใน CI/CD pipeline
set -euo pipefail
IMAGE_NAME="${1:-}"
SBOM_FILE="${2:-sbom.cdx.json}"
SEVERITY_THRESHOLD="${3:-high}"
echo "=== Linux Secure Ops: Vulnerability Gate ==="
echo "Image: ${IMAGE_NAME}"
echo "Severity Threshold: ${SEVERITY_THRESHOLD}"
# อัปเดต database ล่าสุด
grype db update
# สแกนและบันทึกผลลัพธ์
SCAN_FAILED=0
grype sbom:"${SBOM_FILE}" \
-o json \
--fail-on "${SEVERITY_THRESHOLD}" \
> scan-results.json 2>&1 || SCAN_FAILED=$?
# แสดงสรุปผล
jq -r '
.matches |
group_by(.vulnerability.severity) |
.[] |
"\(.[0].vulnerability.severity): \(length) vulnerabilities"
' scan-results.json
if [ "${SCAN_FAILED}" -ne 0 ]; then
echo "FAILED: Found vulnerabilities at or above ${SEVERITY_THRESHOLD} severity"
echo "Pipeline blocked - review and remediate before deployment"
exit 1
fi
echo "PASSED: No blocking vulnerabilities found"
การลงนามและยืนยันด้วย Sigstore
ภาพรวมของระบบนิเวศ Sigstore
Sigstore เป็นโครงการโอเพนซอร์สที่มีเป้าหมายทำให้การลงนามซอฟต์แวร์เป็นเรื่องง่าย โดยไม่ต้องจัดการ private key อย่างซับซ้อน (ซึ่งพูดตามตรงคือปวดหัวมากสำหรับหลายๆ ทีม) ประกอบด้วยสามส่วนหลัก:
- Cosign - เครื่องมือ command-line สำหรับลงนามและตรวจสอบ container images, artifacts และ attestations
- Fulcio - Certificate Authority (CA) ที่ออก short-lived certificates โดยยืนยันตัวตนผ่าน OIDC จาก identity provider เช่น GitHub, Google, Microsoft
- Rekor - Transparency log ที่บันทึกการลงนามทุกครั้งแบบ immutable คล้ายกับ Certificate Transparency log สำหรับ TLS certificates
กระบวนการ "keyless signing" ทำงานแบบนี้ครับ: นักพัฒนายืนยันตัวตนผ่าน OIDC จากนั้น Fulcio ออก short-lived certificate (อายุแค่ 10 นาที) แล้ว Cosign ก็ลงนาม artifact ด้วย private key ชั่วคราว บันทึก signature ลงใน Rekor แล้วก็ทิ้ง private key ไปเลย ทั้งหมดนี้เกิดขึ้นโดยอัตโนมัติ เจ๋งมากจริงๆ
การติดตั้งและใช้งาน Cosign
# ติดตั้ง Cosign บน Linux
curl -O -L https://github.com/sigstore/cosign/releases/download/v2.4.1/cosign-linux-amd64
chmod +x cosign-linux-amd64
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
# ตรวจสอบการติดตั้ง
cosign version
# ติดตั้งผ่าน Go (สำหรับนักพัฒนา)
go install github.com/sigstore/cosign/v2/cmd/cosign@latest
Keyless Signing ด้วย OIDC
# ลงนาม container image แบบ keyless (ต้องการ OIDC token)
# ในสภาพแวดล้อม CI/CD เช่น GitHub Actions จะใช้ OIDC token อัตโนมัติ
cosign sign --yes ghcr.io/myorg/my-app:v1.2.3
# ลงนามพร้อมระบุ annotations เพิ่มเติม
cosign sign --yes \
--annotations "git-commit=$(git rev-parse HEAD)" \
--annotations "build-date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--annotations "repo=https://github.com/myorg/my-app" \
ghcr.io/myorg/my-app:v1.2.3
# ลงนามแบบใช้ key-pair (สำหรับกรณีที่ต้องการจัดการ key เอง)
# สร้าง key pair
cosign generate-key-pair
# ลงนามด้วย private key
cosign sign --key cosign.key ghcr.io/myorg/my-app:v1.2.3
การตรวจสอบ Signature
# ตรวจสอบ signature แบบ keyless (ระบุ OIDC issuer และ identity)
cosign verify \
--certificate-identity "https://github.com/myorg/my-app/.github/workflows/release.yml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/myorg/my-app:v1.2.3
# ตรวจสอบและแสดงผลในรูปแบบ JSON
cosign verify \
--certificate-identity "https://github.com/myorg/my-app/.github/workflows/release.yml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/myorg/my-app:v1.2.3 \
-o json | jq .
# ตรวจสอบด้วย public key
cosign verify --key cosign.pub ghcr.io/myorg/my-app:v1.2.3
การแนบและตรวจสอบ SBOM Attestation
นอกจากลงนาม image แล้ว Cosign ยังรองรับการแนบ attestations ด้วย ซึ่งก็คือข้อมูลที่ลงนามแล้วผูกติดกับ image เช่น SBOM หรือ SLSA provenance:
# แนบ SBOM เข้ากับ image ในรูปแบบ attestation
cosign attest --yes \
--predicate sbom.cdx.json \
--type cyclonedx \
ghcr.io/myorg/my-app:v1.2.3
# แนบ SPDX SBOM
cosign attest --yes \
--predicate sbom.spdx.json \
--type spdxjson \
ghcr.io/myorg/my-app:v1.2.3
# ตรวจสอบและดึง SBOM attestation
cosign verify-attestation \
--certificate-identity "https://github.com/myorg/my-app/.github/workflows/release.yml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--type cyclonedx \
ghcr.io/myorg/my-app:v1.2.3 \
| jq -r '.payload | @base64d | fromjson | .predicate'
เฟรมเวิร์ก SLSA: มาตรฐานการรับประกันคุณภาพซอฟต์แวร์
SLSA คืออะไรและทำไมจึงสำคัญ
SLSA (Supply-chain Levels for Software Artifacts) ออกเสียงว่า "salsa" เหมือนซอสเม็กซิกันนั่นแหละครับ เป็นกรอบงานที่พัฒนาโดย Google และปัจจุบันดูแลโดย OpenSSF SLSA ให้คะแนน "ระดับความน่าเชื่อถือ" ของกระบวนการ build ตั้งแต่ L0 ถึง L3:
- SLSA L0 (No guarantees) - ไม่มีการรับประกันใดๆ เป็นจุดเริ่มต้นสำหรับทุกโปรเจกต์
- SLSA L1 (Provenance exists) - มี provenance document แม้จะยังไม่ได้รับการยืนยันจากระบบอิสระ ต้องใช้ scripted build process ที่ทำซ้ำได้
- SLSA L2 (Hosted build, signed provenance) - Build ทำบน hosted CI/CD system และ provenance ถูกลงนามโดย build service อัตโนมัติ ผู้ใช้ตรวจสอบย้อนกลับได้ว่า artifact มาจากที่ไหน
- SLSA L3 (Hardened build, non-falsifiable provenance) - ระดับสูงสุด Build environment ถูก harden อย่างเต็มที่ provenance ไม่สามารถถูกปลอมแปลงได้แม้แต่โดย build service เอง
Build Provenance คืออะไร
Provenance คือเอกสารที่ระบุว่า artifact ถูกสร้างมาจากอะไร อย่างไร ที่ไหน โดยมีการลงนามจาก build platform ประกอบด้วย:
- Source code ที่ใช้ (commit hash, repository URL)
- Builder ที่ใช้ (เช่น GitHub Actions runner)
- Build instructions (workflow file)
- Dependencies ที่ใช้ในการ build
- Timestamp และข้อมูล environment
การบรรลุ SLSA Level 2 และ 3 ด้วย GitHub Actions
โปรเจกต์ slsa-framework/slsa-github-generator ให้ reusable workflows ที่สร้าง SLSA provenance ระดับ L3 ได้เลย:
# ติดตั้ง slsa-verifier สำหรับตรวจสอบ provenance
curl -O -L https://github.com/slsa-framework/slsa-verifier/releases/download/v2.7.0/slsa-verifier-linux-amd64
chmod +x slsa-verifier-linux-amd64
sudo mv slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier
# ตรวจสอบ provenance ของ artifact
slsa-verifier verify-artifact \
--provenance-path provenance.intoto.jsonl \
--source-uri github.com/myorg/my-app \
--source-tag v1.2.3 \
my-app-linux-amd64
# ตรวจสอบ container image provenance
slsa-verifier verify-image \
--source-uri github.com/myorg/my-app \
ghcr.io/myorg/my-app:v1.2.3
สำหรับ Go binary สามารถใช้ slsa-github-generator ร่วมกับ GitHub Actions ได้ดังนี้:
# .github/workflows/slsa-go-release.yml
name: SLSA Go Release
on:
push:
tags:
- 'v*'
permissions: read-all
jobs:
build:
permissions:
id-token: write
contents: write
actions: read
uses: slsa-framework/slsa-github-generator/.github/workflows/[email protected]
with:
go-version: "1.23"
config-file: ".slsa-goreleaser.yml"
in-toto Attestation Framework: รักษาความปลอดภัยทั้ง Pipeline
ภาพรวมของ in-toto
in-toto เป็น framework ที่ออกแบบมาเพื่อปกป้องกระบวนการ software supply chain ทั้งสาย ตั้งแต่ source code จนถึง deployment แนวคิดหลักคือการกำหนด "layout" ที่ระบุว่าใคร (functionaries) สามารถทำอะไร (steps) ในกระบวนการ build และทุก step ต้องมีหลักฐานที่ลงนามแล้ว
in-toto ทำงานร่วมกับ SLSA โดยเป็นส่วนหนึ่งของ attestation specification ที่ SLSA ใช้ Predicate types ที่รองรับมีหลายแบบ:
- SLSA Provenance - ข้อมูลการ build ระบุที่มาของ artifact
- CycloneDX/SPDX - SBOM ของซอฟต์แวร์
- Vulnerability Scan - ผลการสแกนช่องโหว่
- Test Results - ผลการทดสอบ
- Code Review - หลักฐานการ review โค้ด
โครงสร้างของ in-toto Attestation
in-toto attestation ใช้รูปแบบ DSSE (Dead Simple Signing Envelope) ที่ห่อหุ้ม statement ข้างในจะมี subject (สิ่งที่ attestation อ้างถึง) และ predicate (เนื้อหาจริงๆ) มาดูตัวอย่างกันครับ:
{
"_type": "https://in-toto.io/Statement/v1",
"predicateType": "https://slsa.dev/provenance/v1",
"subject": [
{
"name": "my-app-linux-amd64",
"digest": {
"sha256": "a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4"
}
}
],
"predicate": {
"buildDefinition": {
"buildType": "https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1",
"externalParameters": {
"workflow": {
"ref": "refs/tags/v1.2.3",
"repository": "https://github.com/myorg/my-app",
"path": ".github/workflows/release.yml"
}
},
"resolvedDependencies": [
{
"uri": "git+https://github.com/myorg/my-app@refs/tags/v1.2.3",
"digest": {
"gitCommit": "abc123def456789"
}
}
]
},
"runDetails": {
"builder": {
"id": "https://github.com/actions/runner/github-hosted"
},
"metadata": {
"invocationId": "https://github.com/myorg/my-app/actions/runs/123456789",
"startedOn": "2026-02-17T10:00:00Z",
"finishedOn": "2026-02-17T10:05:30Z"
}
}
}
}
การใช้ in-toto ร่วมกับ Cosign
Cosign รองรับ in-toto attestation โดยตรง ทำให้แนบ attestation หลายประเภทเข้ากับ container image เดียวกันได้สบายๆ:
# สร้าง in-toto attestation สำหรับ vulnerability scan
cat > vuln-attestation.json << 'ATTESTATION'
{
"_type": "https://in-toto.io/Statement/v1",
"predicateType": "https://cosign.sigstore.dev/attestation/vuln/v1",
"subject": [
{
"name": "ghcr.io/myorg/my-app",
"digest": {
"sha256": "abc123..."
}
}
],
"predicate": {
"scanner": {
"uri": "pkg:github/anchore/[email protected]",
"version": "0.88.0",
"result": {
"critical": 0,
"high": 2,
"medium": 5,
"low": 12
}
},
"metadata": {
"scanStartedOn": "2026-02-17T10:03:00Z",
"scanFinishedOn": "2026-02-17T10:03:45Z"
}
}
}
ATTESTATION
# แนบ attestation เข้ากับ image
cosign attest --yes \
--predicate vuln-attestation.json \
--type vuln \
ghcr.io/myorg/my-app:v1.2.3
การสร้าง DevSecOps Pipeline ที่สมบูรณ์
ภาพรวมของ Pipeline
ถึงตรงนี้เราได้เรียนรู้เครื่องมือแต่ละตัวแล้ว ทีนี้มาดูกันว่าจะรวมทุกอย่างเข้าด้วยกันเป็น pipeline ที่สมบูรณ์ได้ยังไง ลำดับขั้นตอนควรเป็นแบบนี้ครับ:
- Source code checkout พร้อม commit verification
- Dependency audit และ license compliance check
- Build application ด้วย hermetic build environment
- สร้าง container image
- สร้าง SBOM ด้วย Syft
- สแกนช่องโหว่ด้วย Grype
- ลงนาม image ด้วย Cosign (keyless)
- แนบ SBOM เป็น attestation
- สร้าง SLSA provenance
- Push ไปยัง registry
- ตรวจสอบ signature และ provenance ก่อน deploy
GitHub Actions Workflow ที่สมบูรณ์
นี่คือ GitHub Actions workflow ที่ผสานรวมทุกเครื่องมือเข้าด้วยกัน ค่อนข้างยาวหน่อยนะครับ แต่ทุก step มีเหตุผลทั้งหมด:
# .github/workflows/secure-release.yml
name: Secure Supply Chain Release
on:
push:
tags:
- 'v*.*.*'
permissions:
contents: read
packages: write
id-token: write
attestations: write
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
GO_VERSION: "1.23"
jobs:
# ===== Job 1: Build and Test =====
build:
name: Build Application
runs-on: ubuntu-24.04
outputs:
image-digest: ${{ steps.build.outputs.digest }}
image-tags: ${{ steps.meta.outputs.tags }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Run dependency audit
run: |
go mod verify
go list -m all | \
grep -v "^$(go list -m)" | \
sort > dependency-list.txt
echo "Dependencies verified successfully"
- name: Run tests
run: |
go test -v -race -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=sha-
- name: Build and push container image
id: build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: true
sbom: false
# ===== Job 2: SBOM Generation and Vulnerability Scanning =====
sbom-scan:
name: SBOM and Vulnerability Scan
runs-on: ubuntu-24.04
needs: build
steps:
- name: Install Syft
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh \
| sh -s -- -b /usr/local/bin v1.19.0
- name: Install Grype
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh \
| sh -s -- -b /usr/local/bin v0.88.0
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate SBOM (CycloneDX and SPDX)
run: |
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
DIGEST="${{ needs.build.outputs.image-digest }}"
syft "${IMAGE}@${DIGEST}" \
-o cyclonedx-json=sbom.cdx.json \
-o spdx-json=sbom.spdx.json \
--source-name "${{ github.repository }}" \
--source-version "${{ github.ref_name }}"
echo "SBOM generated successfully"
echo "Components found: $(jq '.components | length' sbom.cdx.json)"
- name: Scan for vulnerabilities
id: vulnerability-scan
run: |
grype db update
grype sbom:./sbom.cdx.json \
-o json \
> vulnerability-report.json
echo "=== Vulnerability Summary ==="
jq -r '.matches | group_by(.vulnerability.severity) | .[] |
"\(.[0].vulnerability.severity): \(length)"' \
vulnerability-report.json
CRITICAL_COUNT=$(jq '[.matches[] |
select(.vulnerability.severity == "Critical")] | length' \
vulnerability-report.json)
if [ "${CRITICAL_COUNT}" -gt 0 ]; then
echo "FAILED: Found ${CRITICAL_COUNT} Critical vulnerabilities"
exit 1
fi
echo "PASSED: No Critical vulnerabilities found"
- name: Upload SBOM artifacts
uses: actions/upload-artifact@v4
with:
name: sbom-files
path: |
sbom.cdx.json
sbom.spdx.json
vulnerability-report.json
# ===== Job 3: Sign and Attest =====
sign-attest:
name: Sign Image and Create Attestations
runs-on: ubuntu-24.04
needs: [build, sbom-scan]
steps:
- name: Install Cosign
uses: sigstore/cosign-installer@v3
with:
cosign-release: 'v2.4.1'
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Download SBOM artifacts
uses: actions/download-artifact@v4
with:
name: sbom-files
- name: Sign container image (keyless)
run: |
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
DIGEST="${{ needs.build.outputs.image-digest }}"
cosign sign --yes \
--annotations "repo=${{ github.server_url }}/${{ github.repository }}" \
--annotations "git-commit=${{ github.sha }}" \
--annotations "git-tag=${{ github.ref_name }}" \
--annotations "build-date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--annotations "workflow=${{ github.workflow }}" \
"${IMAGE}@${DIGEST}"
echo "Image signed successfully"
- name: Attach SBOM attestation
run: |
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
DIGEST="${{ needs.build.outputs.image-digest }}"
cosign attest --yes \
--predicate sbom.cdx.json \
--type cyclonedx \
"${IMAGE}@${DIGEST}"
echo "SBOM attestation attached successfully"
- name: Attach vulnerability scan attestation
run: |
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
DIGEST="${{ needs.build.outputs.image-digest }}"
cosign attest --yes \
--predicate vulnerability-report.json \
--type vuln \
"${IMAGE}@${DIGEST}"
- name: Generate GitHub Attestation (SLSA Provenance)
uses: actions/attest-build-provenance@v2
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
subject-digest: ${{ needs.build.outputs.image-digest }}
push-to-registry: true
# ===== Job 4: Deployment Verification =====
deploy-verify:
name: Verify Before Deploy
runs-on: ubuntu-24.04
needs: [build, sign-attest]
environment: production
steps:
- name: Install verification tools
run: |
curl -O -L https://github.com/sigstore/cosign/releases/download/v2.4.1/cosign-linux-amd64
chmod +x cosign-linux-amd64
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
curl -O -L https://github.com/slsa-framework/slsa-verifier/releases/download/v2.7.0/slsa-verifier-linux-amd64
chmod +x slsa-verifier-linux-amd64
sudo mv slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Verify image signature
run: |
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
DIGEST="${{ needs.build.outputs.image-digest }}"
WORKFLOW_REF="${{ github.server_url }}/${{ github.repository }}/.github/workflows/secure-release.yml@${{ github.ref }}"
cosign verify \
--certificate-identity "${WORKFLOW_REF}" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"${IMAGE}@${DIGEST}"
echo "Signature verified successfully"
- name: Verify SLSA provenance
run: |
IMAGE="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
DIGEST="${{ needs.build.outputs.image-digest }}"
slsa-verifier verify-image \
--source-uri "github.com/${{ github.repository }}" \
--source-tag "${{ github.ref_name }}" \
"${IMAGE}@${DIGEST}"
echo "SLSA provenance verified successfully"
- name: Deploy to production
run: |
echo "All security checks passed - proceeding with deployment"
# kubectl set image deployment/my-app \
# my-app="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ needs.build.outputs.image-digest }}"
GitLab CI Pipeline ทางเลือก
สำหรับทีมที่ใช้ GitLab CI/CD ก็ไม่ต้องน้อยใจนะครับ สามารถสร้าง pipeline เทียบเท่าได้เลย:
# .gitlab-ci.yml
stages:
- build
- sbom
- scan
- sign
- deploy
variables:
REGISTRY: registry.gitlab.com
IMAGE_PATH: ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}
COSIGN_VERSION: "v2.4.1"
SYFT_VERSION: "v1.19.0"
GRYPE_VERSION: "v0.88.0"
build-image:
stage: build
image: docker:26
services:
- docker:26-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t ${IMAGE_PATH} .
- docker push ${IMAGE_PATH}
- docker inspect --format='{{index .RepoDigests 0}}' ${IMAGE_PATH} > image-digest.txt
artifacts:
paths:
- image-digest.txt
only:
- tags
generate-sbom:
stage: sbom
image: anchore/syft:latest
script:
- IMAGE_DIGEST=$(cat image-digest.txt)
- syft ${IMAGE_DIGEST} -o cyclonedx-json=sbom.cdx.json -o spdx-json=sbom.spdx.json
- echo "Components found $(jq '.components | length' sbom.cdx.json)"
artifacts:
paths:
- sbom.cdx.json
- sbom.spdx.json
only:
- tags
vulnerability-scan:
stage: scan
image: anchore/grype:latest
script:
- grype db update
- grype sbom:./sbom.cdx.json -o json > vulnerability-report.json
- CRITICAL=$(jq '[.matches[] | select(.vulnerability.severity=="Critical")] | length' vulnerability-report.json)
- HIGH=$(jq '[.matches[] | select(.vulnerability.severity=="High")] | length' vulnerability-report.json)
- echo "Critical ${CRITICAL} - High ${HIGH}"
- if [ "$CRITICAL" -gt 0 ]; then echo "FAILED - Critical vulnerabilities found"; exit 1; fi
artifacts:
paths:
- vulnerability-report.json
reports:
cyclonedx: vulnerability-report.json
only:
- tags
sign-image:
stage: sign
image: ubuntu:24.04
id_tokens:
SIGSTORE_ID_TOKEN:
aud: sigstore
script:
- apt-get update && apt-get install -y curl jq
- curl -O -L https://github.com/sigstore/cosign/releases/download/${COSIGN_VERSION}/cosign-linux-amd64
- chmod +x cosign-linux-amd64 && mv cosign-linux-amd64 /usr/local/bin/cosign
- IMAGE_DIGEST=$(cat image-digest.txt)
- cosign sign --yes --identity-token=${SIGSTORE_ID_TOKEN} ${IMAGE_DIGEST}
- cosign attest --yes --identity-token=${SIGSTORE_ID_TOKEN} --predicate sbom.cdx.json --type cyclonedx ${IMAGE_DIGEST}
- echo "Image signed and SBOM attested successfully"
only:
- tags
deploy-production:
stage: deploy
image: bitnami/kubectl:latest
environment:
name: production
script:
- IMAGE_DIGEST=$(cat image-digest.txt)
- echo "Deploying verified image ${IMAGE_DIGEST}"
# - kubectl set image deployment/my-app my-app=${IMAGE_DIGEST}
when: manual
only:
- tags
แนวปฏิบัติที่ดีที่สุดสำหรับ Linux Supply Chain Security
1. การจัดเก็บ SBOM แบบรวมศูนย์
การมี SBOM อย่างเดียวยังไม่พอครับ ต้องจัดการให้ดีด้วย ผมแนะนำให้ใช้ระบบจัดเก็บ SBOM แบบรวมศูนย์อย่าง Dependency-Track ซึ่งเป็นแพลตฟอร์มโอเพนซอร์สจาก OWASP รองรับทั้ง CycloneDX และ SPDX แสดงผลช่องโหว่แบบ real-time และที่สำคัญคือแจ้งเตือนเมื่อมี CVE ใหม่ที่กระทบ component ที่คุณใช้อยู่:
# ติดตั้ง Dependency-Track ด้วย Docker Compose
cat > docker-compose-dt.yml << 'EOF'
version: '3'
services:
dtrack-apiserver:
image: dependencytrack/apiserver:4.11.7
environment:
- ALPINE_DATABASE_MODE=external
- ALPINE_DATABASE_URL=jdbc:postgresql://postgres:5432/dtrack
- ALPINE_DATABASE_DRIVER=org.postgresql.Driver
- ALPINE_DATABASE_USERNAME=dtrack
- ALPINE_DATABASE_PASSWORD=changeme
ports:
- "8080:8080"
depends_on:
- postgres
dtrack-frontend:
image: dependencytrack/frontend:4.11.7
environment:
- API_BASE_URL=http://localhost:8080
ports:
- "8081:8080"
postgres:
image: postgres:16-alpine
environment:
- POSTGRES_DB=dtrack
- POSTGRES_USER=dtrack
- POSTGRES_PASSWORD=changeme
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
EOF
docker compose -f docker-compose-dt.yml up -d
# อัปโหลด SBOM ไปยัง Dependency-Track ผ่าน API
curl -X PUT \
"http://localhost:8080/api/v1/bom" \
-H "X-Api-Key: ${DT_API_KEY}" \
-H "Content-Type: application/json" \
-d "{
\"projectName\": \"my-app\",
\"projectVersion\": \"v1.2.3\",
\"autoCreate\": true,
\"bom\": \"$(base64 -w 0 sbom.cdx.json)\"
}"
2. Policy Enforcement ด้วย Kyverno บน Kubernetes
ตรงนี้สำคัญมากครับ ถ้าคุณใช้ Kubernetes อยู่ คุณต้องมั่นใจว่า image ที่ไม่ได้รับการยืนยันจะไม่สามารถ deploy ได้เด็ดขาด Kyverno เป็น policy engine แบบ Kubernetes-native ที่รองรับ image verification ด้วย Cosign โดยตรง:
# kyverno-policy-verify-image.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signature
annotations:
policies.kyverno.io/title: Verify Image Signature
policies.kyverno.io/description: >-
Images must be signed by our CI/CD pipeline using Sigstore keyless signing.
Only signed and attested images are allowed in production.
spec:
validationFailureAction: Enforce
background: false
rules:
- name: check-image-signature
match:
any:
- resources:
kinds:
- Pod
namespaces:
- production
- staging
verifyImages:
- imageReferences:
- "ghcr.io/myorg/*"
attestors:
- entries:
- keyless:
subject: "https://github.com/myorg/*/.github/workflows/secure-release.yml@*"
issuer: "https://token.actions.githubusercontent.com"
rekor:
url: https://rekor.sigstore.dev
attestations:
- predicateType: https://cyclonedx.org/bom/v1.4
conditions:
- all:
- key: "{{ components | length(@) }}"
operator: GreaterThan
value: "0"
3. Dependency Update Automation ด้วย Renovate
การอัปเดต dependency อัตโนมัติเป็นอีกเรื่องที่หลายทีมมองข้าม แต่จริงๆ แล้วสำคัญมากในการรักษา supply chain security เครื่องมืออย่าง Renovate จะคอยตรวจจับ dependency ที่ล้าสมัยหรือมีช่องโหว่ แล้วสร้าง pull request อัปเดตให้อัตโนมัติ:
// renovate.json
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
":dependencyDashboard",
"security:openssf-scorecard"
],
"vulnerabilityAlerts": {
"enabled": true,
"labels": ["security", "dependencies"],
"automerge": false
},
"osvVulnerabilityAlerts": true,
"packageRules": [
{
"matchDepTypes": ["dependencies"],
"matchUpdateTypes": ["patch"],
"automerge": true,
"automergeType": "pr"
},
{
"matchPackagePatterns": ["*"],
"matchUpdateTypes": ["major"],
"labels": ["major-update"],
"reviewers": ["security-team"]
}
],
"schedule": ["before 6am on monday"],
"prHourlyLimit": 5,
"prConcurrentLimit": 10
}
4. Supply Chain Threat Modeling
การทำ threat modeling สำหรับ supply chain ควรพิจารณาจุดเสี่ยงหลักเหล่านี้ครับ (จากประสบการณ์ บอกได้เลยว่าหลายข้อเกิดขึ้นจริงบ่อยกว่าที่คิด):
- Dependency Confusion Attack - ผู้โจมตีสร้าง package ชื่อเดียวกับ internal package บน public registry ป้องกันได้โดยใช้
--require-hashesใน pip,npm ciแทนnpm installและกำหนด registry scope อย่างชัดเจน - Typosquatting - Package ที่ชื่อคล้ายกับ popular package แต่แอบฝัง malicious code ควรตรวจสอบชื่อ package อย่างระมัดระวัง และใช้ allowlist สำหรับ approved packages
- Build System Compromise - CI/CD runner ถูก compromise ป้องกันด้วย ephemeral runners, least privilege และ hermetic builds
- Maintainer Account Takeover - บัญชีผู้ดูแล package ถูกยึด ควรใช้ 2FA/MFA เสมอ และติดตาม release patterns ที่ผิดปกติ
- Malicious Pull Request - PR ที่แอบแฝง malicious code ต้องมี code review process ที่เข้มงวดและใช้ automated security scanning ทุก PR
5. การตรวจสอบ OpenSSF Scorecard
OpenSSF Scorecard เป็นเครื่องมือที่ช่วยประเมินความปลอดภัยของ project โอเพนซอร์สที่คุณใช้เป็น dependency ก่อนจะเพิ่ม dependency ใหม่ ลองเช็ค scorecard ก่อนก็ดีครับ:
# ติดตั้ง scorecard
curl -O -L https://github.com/ossf/scorecard/releases/download/v5.1.0/scorecard-linux-amd64
chmod +x scorecard-linux-amd64
sudo mv scorecard-linux-amd64 /usr/local/bin/scorecard
# ตรวจสอบคะแนนความปลอดภัยของ dependency
export GITHUB_AUTH_TOKEN=ghp_your_token_here
scorecard --repo=github.com/anchore/syft --format=json | \
jq '.checks[] | {name: .name, score: .score, reason: .reason}'
# ตรวจสอบ project ของตัวเอง
scorecard --repo=github.com/myorg/my-app --format=json > scorecard-report.json
# แสดงเฉพาะ checks ที่ score ต่ำกว่า 5 (ต้องปรับปรุง)
jq '.checks[] | select(.score < 5) | {name: .name, score: .score}' scorecard-report.json
6. Hermetic Builds และ Distroless Images
Hermetic build คือการ build ที่ผลลัพธ์ออกมาเหมือนกันทุกครั้ง ไม่ว่าจะ build ที่ไหน ช่วยป้องกันปัญหา "ของผมมัน run ได้นะ" และลดความเสี่ยงจาก dependency substitution attacks ส่วน distroless image ก็ช่วยลด attack surface ได้เยอะมาก:
# Dockerfile สำหรับ hermetic build
# ใช้ digest แทน tag เพื่อป้องกัน tag mutation
FROM golang:1.23.6@sha256:927112936cd3a7de2b2b5c337d0a8b3e6f1f1e6c94a7d4c14d36cf1c4e3ab12 AS builder
WORKDIR /app
# Copy go module files ก่อน (layer caching)
COPY go.mod go.sum ./
# Download dependencies พร้อม verification
RUN go mod download -x && go mod verify
# Copy source code
COPY . .
# Build แบบ static binary พร้อม hardening flags
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build \
-trimpath \
-ldflags="-w -s -X main.version=${VERSION} -X main.commit=${COMMIT}" \
-o /app/my-app \
./cmd/my-app
# ใช้ distroless base image (ไม่มี shell ลด attack surface)
FROM gcr.io/distroless/static-debian12:nonroot@sha256:3ae7f0201fee13b777a3e1abe5e7e5ef4c9d4e3d1d6a35d04e7f3c7d67b2e9a
COPY --from=builder /app/my-app /my-app
USER nonroot:nonroot
ENTRYPOINT ["/my-app"]
7. การตรวจสอบ Container Image ด้วย Trivy
นอกจาก Grype แล้ว Trivy จาก Aqua Security ก็เป็นตัวเลือกยอดนิยมอีกตัวครับ จริงๆ แล้วหลายทีมใช้ทั้งสองตัวร่วมกันเพื่อลด false negatives เพราะแต่ละเครื่องมือก็มีจุดแข็งต่างกัน:
# ติดตั้ง Trivy บน Linux
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin v0.58.1
# สแกน container image
trivy image --severity HIGH,CRITICAL ghcr.io/myorg/my-app:v1.2.3
# สร้าง SBOM ด้วย Trivy (รูปแบบ CycloneDX)
trivy image --format cyclonedx --output trivy-sbom.cdx.json ghcr.io/myorg/my-app:v1.2.3
# สแกนและ output เป็น SARIF สำหรับ GitHub Security tab
trivy image --format sarif --output trivy-results.sarif ghcr.io/myorg/my-app:v1.2.3
# สแกน filesystem สำหรับ secrets และ misconfigurations
trivy fs --security-checks vuln,secret,config /path/to/project
สรุป: ก้าวสู่อนาคตของ Linux Supply Chain Security
ถ้าอ่านมาถึงตรงนี้ได้ ขอบอกเลยว่าคุณเอาจริงเรื่อง supply chain security แล้วครับ ความปลอดภัยของ software supply chain ไม่ใช่เรื่อง "nice to have" อีกต่อไป แต่เป็นส่วนสำคัญของกระบวนการพัฒนาซอฟต์แวร์ที่รับผิดชอบ ในปี 2026 เครื่องมืออย่าง Syft, Grype, Cosign/Sigstore, SLSA และ in-toto ได้กลายเป็น standard stack ที่องค์กรชั้นนำทั่วโลกนำมาใช้แล้ว
สิ่งที่ควรเริ่มทำทันทีครับ:
- เริ่มสร้าง SBOM ในทุก build - ไม่ว่าจะใช้ Syft หรือเครื่องมืออื่น การมี inventory ของ software components คือพื้นฐานของทุกอย่าง เมื่อเกิดช่องโหว่ใหม่ คุณจะระบุผลกระทบได้ภายในนาทีแทนที่จะเป็นสัปดาห์
- ผสาน vulnerability scanning เข้าใน CI/CD - ด้วย Grype หรือ Trivy กำหนด policy ที่ชัดเจนว่า severity level ไหนที่จะ block การ deploy
- เปิดใช้งาน keyless signing - ด้วย Cosign เพื่อให้ทุก artifact มี cryptographic proof ของแหล่งที่มา ยืนยันได้ว่าใครสร้างและมาจากไหน
- มุ่งสู่ SLSA Level 2 ในระยะสั้น - แล้วค่อยๆ ไต่ขึ้นสู่ Level 3 ในระยะยาว การมี build provenance ที่น่าเชื่อถือช่วยสร้างความมั่นใจให้ผู้ใช้ได้เยอะมาก
- บังคับใช้ policy ใน runtime - ใน Kubernetes ด้วย Kyverno หรือ OPA/Gatekeeper เพื่อให้มั่นใจว่ามีเพียง verified images เท่านั้นที่ถูก deploy
แนวโน้มที่น่าจับตาในอนาคตอันใกล้ก็มีเช่น การขยายตัวของ Sigstore ไปสู่ภาษาโปรแกรมมิ่งอื่นๆ อย่าง Python PyPI และ Rust crates.io ที่เริ่มรองรับ Sigstore signing แล้ว รวมถึงการพัฒนา VEX ให้สมบูรณ์ขึ้นเพื่อลด noise จาก false positives และการนำ AI/ML มาช่วย threat detection ใน build pipelines
สำหรับทีมที่เพิ่งเริ่ม การเริ่มต้นอาจดูซับซ้อนหน่อยครับ แต่ขอให้จำไว้ว่า supply chain attack ที่ประสบความสำเร็จนั้นมีต้นทุนที่สูงกว่าการลงทุนป้องกันมากมายนัก ตัวอย่างจาก SolarWinds แสดงให้เห็นว่าผลกระทบสามารถส่งผลต่อลูกค้าหลายหมื่นรายและใช้เวลาเป็นปีในการฟื้นตัว ในขณะที่เครื่องมือทั้งหมดที่กล่าวถึงในบทความนี้เป็นโอเพนซอร์สและเริ่มต้นได้ภายในวันเดียว
เส้นทางสู่ secure software supply chain ไม่ใช่จุดหมายปลายทาง แต่เป็นการเดินทางอย่างต่อเนื่อง เริ่มจากการทำ inventory ของ software components วัดระดับความปลอดภัยปัจจุบัน แล้วค่อยๆ ยกระดับตาม SLSA framework ได้เลยครับ
โลกของ Linux supply chain security กำลังพัฒนาอย่างรวดเร็ว การติดตามข่าวสารจาก OpenSSF, CNCF Security TAG และ NIST SSDF จะช่วยให้ทีมของคุณก้าวทันภัยคุกคามและแนวปฏิบัติที่ดีที่สุดในยุค DevSecOps อยู่เสมอครับ