ยกระดับความปลอดภัยให้เป็นส่วนหนึ่งของดีเอ็นเอในการพัฒนาซอฟต์แวร์ และเรียนรู้วิธีปฏิบัติที่เป็นเลิศ
สัปดาห์ที่แล้วเราเรียนรู้เกี่ยวกับการเฝ้าระวังขั้นสูง และการจัดการกับปัญหา (Incident)
การใช้ Node Exporter และ Blackbox Exporter เพื่อดึง Metrics จากระบบที่ไม่ได้ออกแบบมาเพื่อ Prometheus โดยตรง
การทำความเข้าใจ SLI (ตัวชี้วัด), SLO (เป้าหมาย), และ Error Budgets (โควตาความผิดพลาด)
การใช้ USE Method สำหรับทรัพยากรฮาร์ดแวร์ และ RED Method สำหรับ Microservices
การวิเคราะห์สาเหตุของปัญหา (Root Cause) โดยไม่กล่าวโทษบุคคล แต่เน้นปรับปรุงกระบวนการ
DevSecOps (Development, Security, and Operations) คือการบูรณาการความปลอดภัย (Security) เข้าไปในทุกขั้นตอนของกระบวนการพัฒนาซอฟต์แวร์ (SDLC)
ในอดีต ทีม Security จะทำการตรวจสอบ (Audit หรือ Penetration Test) ในช่วงท้ายของโปรเจกต์ก่อนขึ้น Production
Shift-Left คือการ "เลื่อน" กระบวนการตรวจสอบและคิดเรื่องความปลอดภัยไปทาง "ซ้าย" (ช่วงเริ่มต้น) ของ Pipeline ให้เร็วที่สุดเท่าที่จะทำได้
ต้นทุนและเวลาในการแก้ไขช่องโหว่จะเพิ่มขึ้นทวีคูณ หากเราพบมันช้าลง
การสร้าง DevSecOps Pipeline คือการเพิ่ม Gate การตรวจสอบความปลอดภัยในทุกจุด
Pre-commit Hooks
IDE Security Plugins
Secret Scanning
SAST
SCA
Unit Tests
DAST
Container Scan
IaC Scan
Runtime Protection
Monitoring & Alerts
Penetration Test
SAST คือการสแกน Source Code หรือ Bytecode เพื่อหาจุดบกพร่องด้านความปลอดภัย "โดยไม่ต้องรันโปรแกรม" (White-box testing)
DAST คือการสแกนความปลอดภัย "ขณะที่แอปพลิเคชันกำลังทำงานอยู่ (Runtime)" โดยการจำลองการโจมตีจากภายนอก (Black-box testing)
| คุณสมบัติ | SAST (Static) | DAST (Dynamic) |
|---|---|---|
| วิธีการสแกน | วิเคราะห์ Source Code (White-box) | ยิง Request โจมตีระบบที่รันอยู่ (Black-box) |
| ช่วงเวลา (Pipeline) | ทำได้ทันทีในขั้นตอน Build หรือ PR | ต้องรอแอป Deploy ลง Staging ก่อน |
| สิ่งที่ค้นพบ | บอกได้ถึงระดับบรรทัดโค้ด | บอกช่องโหว่ของ HTTP/API, รหัสผ่านหลุดรอด |
| จุดอ่อน | อาจเจอ False Positives เยอะ และไม่เห็นคอนฟิกตอนรัน | ใช้เวลาสแกนนาน หาต้นตอในโค้ดยาก |
แอปพลิเคชันยุคใหม่มักมีโค้ดที่เราเขียนเองเพียง 10-20% ที่เหลือคือ 3rd Party Libraries (Open Source)
SCA คือเครื่องมือวิเคราะห์และสแกน Dependency เหล่านี้ (เช่น ไฟล์ package.json , requirements.txt ) เพื่อตรวจสอบว่า:
*SCA เป็นปราการด่านสำคัญในการป้องกัน Supply Chain Attacks
CI/CD Server (เช่น Jenkins) มีสิทธิ์ในการดึง Source Code และมีรหัสผ่านในการเข้าถึง Production Server หาก CI/CD โดนแฮก ระบบทั้งหมดก็จะโดนยึด!
ถึงแม้ Container จะให้ความสามารถในการแยกส่วน (Isolation) แต่มันไม่ได้ปลอดภัย 100% โดยธรรมชาติ เพราะมันยังใช้ Kernel เดียวกับเครื่องโฮสต์ (Host OS)
ความปลอดภัยของ Container (Container Security) แบ่งออกเป็น 2 ส่วนหลักๆ คือ:
ก่อนที่จะนำ Image ขึ้นไปรันบน K8s เราต้องสแกนหาช่องโหว่ใน OS packages และไลบรารีที่ฝังอยู่ข้างในเสียก่อน
# ตัวอย่างการใช้ Trivy สแกน image
$ trivy image nginx:latest
Total: 45 (UNKNOWN: 0, LOW: 10, MEDIUM: 25, HIGH: 8, CRITICAL: 2)
*เครื่องมือยอดนิยม: Trivy, Clair, Anchore
เมื่อ Build และ Scan Image เสร็จแล้ว เราจะรู้ได้อย่างไรว่า Image ตัวนี้ไม่ได้ถูกแฮกเกอร์แอบสับเปลี่ยนระหว่างทางก่อนนำไป Deploy?
เมื่อ Container กำลังทำงานอยู่ เราต้องเฝ้าระวังพฤติกรรมที่ผิดปกติ (Anomalies)
*เครื่องมืออย่าง Falco (eBPF-based) สามารถตรวจจับและบล็อกพฤติกรรมเหล่านี้ได้แบบ Real-time
Container ไม่ควรถูกแก้ไขขณะรันไทม์ ห้ามใช้คำสั่ง apt-get ติดตั้งของเพิ่ม ห้ามแก้ไขไฟล์โค้ดข้างใน
Best Practice: กำหนดให้ Filesystem เป็นแบบ Read-only (Read-only root filesystem) เพื่อป้องกันแฮกเกอร์ฝังมัลแวร์
อย่ารัน Container ด้วยสิทธิ์ root เด็ดขาด! เพราะถ้าหลุดออกจาก Container ได้ (Container Breakout) จะกลายเป็น root ของเครื่องโฮสต์ทันที
Best Practice: สร้าง non-root user ใน Dockerfile เสมอ (เช่น USER 1000)
ช่องโหว่จำนวนมากเกิดจากการ "ตั้งค่าผิด (Misconfigurations)" ไม่ใช่เพราะเขียนโค้ดแย่
กฎเหล็ก: "ห้าม Hardcode ข้อมูลความลับ (Secrets) ลงใน Source Code เด็ดขาด!"
Secrets ได้แก่ รหัสผ่าน Database, API Keys, SSH Keys, SSL Certificates หากหลุดเข้าไปใน Git Repository ต่อให้เป็น Private Repo ก็มีความเสี่ยงสูงที่จะโดนขโมย และจะอยู่ใน History ตลอดไป
# ตัวอย่างสิ่งที่ห้ามทำ (Anti-Pattern)
DB_PASSWORD = "mySuperSecretPassword123!"
AWS_ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE"
แล้วเราควรเก็บ Secrets ไว้ที่ไหน?
ใช้ระบบจัดเก็บความลับโดยเฉพาะ เช่น HashiCorp Vault, AWS Secrets Manager, หรือ Azure Key Vault ระบบเหล่านี้จะทำการเข้ารหัส และสามารถหมุนเวียนรหัส (Rotate) ได้อัตโนมัติ
แอปพลิเคชันควรอ่าน Secrets จาก Environment Variables ณ ตอนรันไทม์ โดยดึงค่ามาจาก Vault อีกที
ตั้งค่า CI/CD ให้มีเครื่องมือดักจับ Secrets (เช่น git-secrets, TruffleHog, Gitleaks) เพื่อตรวจหา API Key ก่อนที่จะถูก Commit
"ทำ DevOps อย่างไรให้ประสบความสำเร็จและยั่งยืน"
Anti-Patterns คือรูปแบบการปฏิบัติหรือวิธีแก้ปัญหาที่ "ดูเหมือนจะเป็นความคิดที่ดีในตอนแรก" แต่สุดท้ายกลับสร้างปัญหาหรือทำให้ระบบแย่ลงในระยะยาว
การนำ DevOps หรือ เครื่องมือ CI/CD มาใช้ ไม่ได้หมายความว่าคุณกำลังทำ DevOps ที่ถูกต้อง หากคุณยังมีพฤติกรรมแบบ Anti-patterns เหล่านี้
ปัญหา: ถึงแม้จะมีเครื่องมือ CI/CD แต่ทีมพัฒนากับทีมดูแลระบบยังทำงานแยกกัน โยนโค้ดข้ามกำแพงให้กัน หากระบบพัง ก็ชี้นิ้วโทษกัน (Blame game)
วิธีแก้: สร้างวัฒนธรรมการทำงานร่วมกัน (Collaboration) ให้ Dev รับผิดชอบสิ่งที่ตัวเองรัน (You build it, you run it) และ Ops ช่วยสร้าง Platform ให้ Dev ทำงานง่ายขึ้น
การใช้อีเมลส่วนกลางหรือ User เดียว (เช่น admin/admin) ล็อกอินเข้าระบบ CI Server (เช่น Jenkins) หรือ Version Control ร่วมกันทั้งทีม
ทำให้ไม่สามารถตรวจสอบได้เลยว่าใครเป็นคนกดยกเลิก Build หรือใครเป็นคนแอบเปลี่ยนค่า Configuration (สูญเสียความสามารถในการ Audit)
บัญชีผู้ใช้ต้องเป็นรายบุคคลเสมอ! เพื่อให้ระบบสามารถบันทึก Log และ Audit ได้อย่างชัดเจน
และใช้ระบบ Role-Based Access Control (RBAC) ให้อำนาจเฉพาะสิทธิ์ที่จำเป็นตามตำแหน่งหน้าที่ (Least Privilege)
ปัญหา: ทีม Security สร้างกฎที่เข้มงวดและต้องมารออนุมัติแบบ Manual (Manual Approval)
เมื่อมีเครื่องมือสแกน (เช่น SAST/DAST) แต่ไม่มีคนคอยปรับจูน ปล่อยให้มันแจ้งเตือนผิดพลาด (False Positives) เยอะๆ ทำให้นักพัฒนาเกิดอาการ "Alert Fatigue" หรือความเหนื่อยล้าจากการแจ้งเตือน สุดท้ายก็จะเพิกเฉยต่อการแจ้งเตือนนั้นไปเลย
วิธีแก้:
บูรณาการเครื่องมืออัตโนมัติเข้ากับ Pipeline (DevSecOps) คัดกรอง Alert เฉพาะที่สำคัญจริงๆ (User Impact) และส่งเสริมให้ Security เป็น "ผู้สนับสนุน" ไม่ใช่ "ตำรวจ"
People, Process, and Technology
"เทคโนโลยีและเครื่องมือที่ดี ไม่สามารถอุดช่องโหว่ได้ทั้งหมด หากปราศจากกระบวนการที่ถูกต้องและวัฒนธรรมทีมที่ดี"
"Hire the right people and treat them right."
DevSecOps ที่แท้จริงคือการสร้างวัฒนธรรมที่พนักงานทุกคน (Dev, Ops, Sec) มีความรู้ความเข้าใจ ตระหนักถึงความเสี่ยง และทำงานร่วมกันในกระบวนการที่โปร่งใสและตรวจสอบได้ (Blameless Culture)
ในส่วนปฏิบัติการของสัปดาห์นี้ เราจะมาทดลองทำหน้าที่ตรวจประเมินความปลอดภัยของแอปพลิเคชันที่เราสร้างขึ้นมา
ค้นหาช่องโหว่ที่ซ่อนอยู่ใน Docker Image ของคุณ และเรียนรู้วิธีการอุดรอยรั่วก่อนนำไปใช้งานจริง
ใน Lab นี้เราจะโฟกัสที่ 2 เครื่องมือยอดนิยมสำหรับการสแกนหาช่องโหว่ (Software Composition Analysis - SCA)
ฟีเจอร์ที่ถูกผนวกเข้ามาใน Docker Desktop โดยตรง ช่วยวิเคราะห์ Supply Chain และให้คำแนะนำในการแก้ไข (Remediation) ทันที
ใช้งานผ่าน GUI ของ Docker Desktop หรือคำสั่ง:
$ docker scout cves <image>
เครื่องมือ Open-source ยอดนิยมอันดับ 1 สำหรับ CI/CD ใช้งานง่าย สแกนได้ทั้ง OS packages และไลบรารีภาษาต่างๆ (npm, pip, requirements.txt)
ใช้งานผ่าน CLI:
$ trivy image <image>
เพื่อให้เห็นภาพชัดเจน เราจะจงใจดาวน์โหลด Base Image เวอร์ชันเก่าที่ตกรุ่นไปแล้ว ซึ่งมักจะเต็มไปด้วยช่องโหว่
# 1. Pull Nginx เวอร์ชัน 1.14 (เก่าหลายปีแล้ว)
$ docker pull nginx:1.14
1.14: Pulling from library/nginx
Digest: sha256:485b610fefec7ff6c463ffcd3edef...
# 2. ตรวจสอบว่า Image ถูกโหลดมาเรียบร้อย
$ docker images | grep nginx
nginx 1.14 ... 109MB
nginx:1.14$ docker scout cves nginx:1.14
... Analyzing image...
✗ CRITICAL: 15
✗ HIGH: 48
✗ MEDIUM: 70
What's Next? View base image update recommendations with:
docker scout recommendations nginx:1.14
หากคุณไม่ได้ติดตั้ง Trivy ไว้ในเครื่อง สามารถใช้ Docker มารันตัว Trivy Container เพื่อสแกน Image ในเครื่องเราได้เลย!
# รัน Trivy ผ่าน Docker โดยทำการ Mount docker.sock เพื่อให้ Trivy มองเห็น Image ในเครื่องเรา
$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy image nginx:1.14
2026-04-09T10:00:00Z INFO Need to update DB
2026-04-09T10:00:05Z INFO Vulnerability scanning...
nginx:1.14 (debian 9.8)
=========================
Total: 250 (UNKNOWN: 0, LOW: 90, MEDIUM: 100, HIGH: 45, CRITICAL: 15)
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED | FIXED IN |
|---|---|---|---|---|
| apt | CVE-2020-3810 | HIGH | 1.4.9 | 1.4.10 |
| openssl | CVE-2021-3711 | CRITICAL | 1.1.0j | 1.1.1l |
apt-get upgrade ทีละแพ็กเกจใน Dockerfile ของเราหรือไม่?เราจะเปลี่ยนไปใช้ Base Image ที่มีขนาดเล็กที่สุด (Minimal Base Image) และเป็นเวอร์ชันใหม่ เพื่อลดพื้นที่โจมตี
# 1. ลอง Pull image nginx รุ่น Alpine (เล็กและใหม่)
$ docker pull nginx:alpine
# 2. นำภาพใหม่ไปสแกนด้วย Trivy
$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy image nginx:alpine
nginx:alpine (alpine 3.18)
=========================
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
🎉 สังเกตว่า Vulnerabilities กลายเป็น 0 ทันที เพียงแค่เราเปลี่ยน Base Image!
หลีกเลี่ยง Image ที่พ่วง OS เต็มรูปแบบ (เช่น Ubuntu เต็ม) เปลี่ยนไปใช้ Alpine หรือ Distroless เพื่อลดของที่ไม่จำเป็นทิ้ง (ลด Attack Surface)
ห้ามรันคอนเทนเนอร์ด้วยสิทธิ์ Root กำหนด USER 1000 หรือ USER node ไว้เสมอ เพื่อป้องกัน Container Breakout
ผูกคำสั่ง Trivy ไว้ใน GitHub Actions หรือ GitLab CI และสั่งให้หยุดกระบวนการ Deploy ทันที (Fail the build) หากพบช่องโหว่ Critical/High
เซ็นชื่อกำกับ Image (เช่นใช้ Cosign/Sigstore) และตรวจสอบ Signature ก่อนรันใน Production ป้องกัน Supply Chain Attack
ภาพ Terminal ที่รันคำสั่ง trivy หรือ docker scout กับ nginx:1.14 โดยโชว์ให้เห็นจำนวน CRITICAL และ HIGH ที่พบ
ภาพ Terminal ที่รันสแกนกับ nginx:alpine ซึ่งแสดงผลลัพธ์ว่าปราศจากช่องโหว่ (Total: 0)
สรุปด้วยภาษาของคุณเองว่า "ทำไมการเปลี่ยน Base Image ถึงเป็นวิธีแก้ปัญหาช่องโหว่ที่ดีกว่าการพยายามรัน apt-get update ภายใน Container"
docker rmi nginx:1.14 เพื่อประหยัดพื้นที่ดิสก์!