สวัสดีค่าา EP สุดท้ายของซีรี่ส์มาถึงแล้ว!

ก่อนจะจบ ขอเล่าให้ฟังก่อนนะ ตอนที่เตรียม HYROX ช่วงสุดท้ายก่อนแข่ง โค้ชทีนเตือนเรื่องนึงเสมอคือ "อย่าประมาทตรงที่คิดว่าตัวเองถนัด" เพราะ station ที่เราคิดว่าง่ายที่สุดอย่าง rowing มักเป็นจุดที่เสียเวลามากที่สุดเพราะไม่ได้เตรียมจริงจัง

Security ในโลก DevOps ก็เหมือนกันค่ะ คนมักมองข้ามเพราะคิดว่า "ยังเล็กอยู่ ยังไม่โดนหรอก" จนกว่าจะโดนจริงๆ แล้วก็สาย


DevSecOps คืออะไร

DevSecOps คือการนำ Security เข้ามาเป็นส่วนหนึ่งของ DevOps pipeline ตั้งแต่ต้น แทนที่จะเอา security มา check ตอนใกล้ release หรือหลัง incident เกิดขึ้นแล้ว

แนวคิดคือ Shift Left ขยับ security check ให้เร็วขึ้นในวงจรการพัฒนา เพราะยิ่ง detect ช้า ยิ่ง fix แพง

เก่า: Plan → Code → Build → Test → Release → [Security Check] → Deploy ↑ ช้าเกินไปแล้ว DevSecOps (Shift Left): Plan → [Threat Model] → Code → [SAST] → Build → [SCA] → Test → [DAST] → Deploy ↑ ↑ ↑ ↑ คิดก่อน scan code scan deps test runtime

Secret Management ไม่มี credential ใน code

กฎข้อแรกของ security คือ ห้าม hardcode secret ใน code เด็ดขาด ไม่ว่าจะเป็น API key, database password, SSH key อะไรก็ตาม

# แบบนี้ ห้ามทำ!!!!
DB_PASSWORD = "super_secret_password_123"
AWS_SECRET_KEY = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

# แบบนี้ถูกต้อง อ่านจาก environment variable
DB_PASSWORD = os.environ.get("DB_PASSWORD")
AWS_SECRET_KEY = os.environ.get("AWS_SECRET_KEY")

HashiCorp Vault

Vault คือ secrets management tool ที่ให้ app ดึง secret มาใช้ตอน runtime แทนที่จะเก็บไว้ใน environment variable โดยตรง

# ดึง secret จาก Vault ใน Python
import hvac

client = hvac.Client(url='https://vault.example.com')
client.auth.approle.login(role_id=ROLE_ID, secret_id=SECRET_ID)

secret = client.secrets.kv.read_secret_version(
    path='my-app/database'
)
db_password = secret['data']['data']['password']

AWS Secrets Manager

ถ้าอยู่บน AWS แล้ว AWS Secrets Manager เป็นทางเลือกที่ง่ายกว่าในการ rotate และ access secrets

import boto3
import json

client = boto3.client('secretsmanager', region_name='ap-southeast-1')

response = client.get_secret_value(SecretId='my-app/db-password')
secret = json.loads(response['SecretString'])
db_password = secret['password']

Security Scanning ใน CI/CD Pipeline

SAST (Static Application Security Testing)

Scan source code หา vulnerability โดยไม่ต้องรันโปรแกรม เหมือนอ่านโค้ดแล้ว flag สิ่งที่น่าสงสัย

# GitHub Actions ตัวอย่าง รัน Bandit สำหรับ Python
- name: Run SAST scan
  run: |
    pip install bandit
    bandit -r ./src/ -f json -o bandit-report.json

- name: Upload scan results
  uses: actions/upload-artifact@v4
  with:
    name: bandit-report
    path: bandit-report.json

SCA (Software Composition Analysis)

Scan dependencies หา known vulnerabilities ใน library ที่เราใช้ เพราะ library ที่ใช้อยู่อาจมีช่องโหว่ที่ถูก discover ทีหลัง

# รัน Safety สำหรับ Python dependencies
pip install safety
safety check -r requirements.txt

# หรือใช้ GitHub Dependabot ซึ่ง built-in อยู่แล้ว
# แค่เปิด .github/dependabot.yml ก็พอ

Container Image Scanning

Scan Docker image หา vulnerability ก่อน push ขึ้น registry

# ใช้ Trivy scan image
trivy image my-app:1.0

# ใน GitHub Actions
- name: Scan Docker image
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: 'my-app:${{ github.sha }}'
    exit-code: '1'    # fail build ถ้าเจอ critical vulnerability

Principle of Least Privilege

ให้ permission เท่าที่จำเป็นจริงๆ เท่านั้น อย่าให้ admin access กับทุกอย่าง

เปรียบเหมือนยิมที่เราไป ไม่ใช่ทุกคนจะเข้าห้อง trainer ได้ คนที่เข้าได้มีแค่ trainer และ manager เท่านั้น member ทั่วไปเข้าได้แค่พื้นที่ออกกำลังกาย แบบนี้แหละที่ควรจะเป็น

# IAM Policy ที่ดี: ให้ read-only access แค่ S3 bucket เดียว
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:ListBucket"],
      "Resource": [
        "arn:aws:s3:::my-specific-bucket",
        "arn:aws:s3:::my-specific-bucket/*"
      ]
    }
  ]
}

# แบบนี้ไม่ดี: ให้ full access ทุกอย่าง
{
  "Effect": "Allow",
  "Action": "*",
  "Resource": "*"
}

Network Security

Zero Trust Network

แนวคิด Zero Trust คือ "never trust, always verify" ไม่ว่าจะอยู่ใน network ไหน จะ internal หรือ external ก็ต้อง authenticate และ authorize ก่อนเสมอ ต่างจากแนวคิดเก่าที่ "ถ้าอยู่ใน network วงในแล้วเชื่อใจได้"

Security Groups และ Network Policies

ใน K8s ใช้ Network Policy ควบคุมว่า Pod ไหนคุยกับ Pod ไหนได้บ้าง แทนที่จะให้ทุก Pod คุยกันได้หมดโดย default

# k8s NetworkPolicy: อนุญาตเฉพาะ frontend คุยกับ backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-only
spec:
  podSelector:
    matchLabels:
      app: backend
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend    # แค่ frontend เท่านั้น

Security Checklist ก่อน Deploy Production

checklist นี้ไม่ครบ 100% แต่เป็นจุดเริ่มต้นที่ดี

หมวดรายการ
Secretsไม่มี secret hardcode ในโค้ดหรือ Dockerfile
Secretsใช้ secrets manager หรือ environment variables
Dependenciesscan dependencies หา known CVE ก่อน deploy
Containerไม่ run container ด้วย root user
Containerใช้ base image ที่ minimal และ updated
Networkเปิด port แค่ที่จำเป็น ปิดที่เหลือ
Accessทุก IAM role ให้ least privilege เสมอ
Monitoringมี alert สำหรับ suspicious activity
Auditเปิด audit log ทุก API call ที่สำคัญ

สรุป EP.10 และสรุปซีรี่ส์

  • DevSecOps คือการ shift security check ให้เร็วขึ้นใน pipeline
  • ห้าม hardcode secret ในโค้ดเด็ดขาด ใช้ secrets manager
  • Scan code, dependencies, และ container image อัตโนมัติใน CI/CD
  • Principle of least privilege ให้ permission เท่าที่จำเป็นเสมอ
  • Network policy ควบคุม traffic ระหว่าง services

🎉 จบซีรี่ส์ DevOps พังแล้วพังอีกพังต่อ แล้ว!

ผ่านมาทั้ง 10 EP เราคุยกันมาเยอะมากนะ ตั้งแต่ DevOps คืออะไร ไปจนถึง Linux, Git, Networking, Cloud, Docker, CI/CD, Kubernetes, IaC, Monitoring และ Security

ถ้าถามว่าควรเรียนต่อยังไงหลังจากนี้ คำตอบคือ ลงมือทำ ค่ะ อ่านแค่ concept ไม่พอ ต้อง break ของด้วยตัวเองบ้าง ตั้ง server, deploy app, ดู log, แก้ error จริงๆ ถึงจะซึมซับเข้าไปจริงๆ

เหมือนการยกน้ำหนักเลย ไม่มีทางรู้ว่า 100kg หนักแค่ไหน จนกว่าจะจับบาร์แล้วรู้สึกด้วยตัวเอง 5555

ขอบคุณที่ติดตามมาจนถึง EP.10 นะคะ แล้วเจอกันในซีรี่ส์ต่อไปค่ะ 👋