Docker Security Best Practices ป้องกัน Container จาก Exploit

ทำไม Docker Security ถึงสำคัญ?

Container ที่ตั้งค่าไม่ดีอาจเป็นช่องโหว่ให้ Attacker โจมตี Server ได้ Docker Security ไม่ใช่เรื่องน่ากลัวแต่เป็นสิ่งที่ต้องใส่ใจจริงๆ

1. ไม่รัน Container ในฐานะ root

# สร้าง User ใน Dockerfile
FROM node:20-alpine

RUN addgroup -g 1001 appgroup && \
    adduser -u 1001 -G appgroup -s /bin/sh -D appuser

WORKDIR /app
COPY --chown=appuser:appgroup . .

USER appuser

EXPOSE 3000
CMD ["node", "index.js"]

2. ใช้ Official Image และ Pin Version

# สิ้นเปลือง
 FROM node:latest  # ไม่บอกเวอร์ชัน
FROM node  # ไม่ระบุเวอร์ชัน

# ดีกว่า
FROM node:20.11.0-alpine3.19  # Pin เวอร์ชันครั้งเดียว

# หรือใช้ image digest
FROM node@sha256:abc123...

3. Scan Image หาช่องโหว่

# ด้วย Docker Scout
docker scout cves myapp:latest

# ด้วย Trivy (อิสระ เปิดซอร์ส)
trivy image myapp:latest

# ติดตั้ง Trivy
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh

4. Read-Only Filesystem

docker run --read-only \
  --tmpfs /tmp \
  --tmpfs /var/run \
  myapp:latest
# ใน Docker Compose
services:
  app:
    image: myapp:latest
    read_only: true
    tmpfs:
      - /tmp
      - /var/run

5. จำกัด Capabilities

# ลบ Capabilities ทั้งหมดแล้วเพิ่มเฉพาะที่จำเป็น
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp:latest

# ใน Docker Compose
services:
  app:
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE

6. ไม่ Mount Docker Socket ใน Container

# อันตราย! ใครที่เข้าถึง Container นี้จะคุม Docker daemon ได้
volumes:
  - /var/run/docker.sock:/var/run/docker.sock  # หลีกเลี่ยงเว้นมีเหตุผลจำเป็น!

7. ใช้ Secrets แทน Environment Variables

# Docker Secrets (สำหรับ Docker Swarm)
echo "mysecretpassword" | docker secret create db_password -

# ใน Docker Compose (ไม่ใช้เนื้อหาสำหรับไฟล์ .env)
# สร้างไฟล์ .env และไม่commit เข้า git
DB_PASSWORD=securepassword

8. Resource Limits

services:
  app:
    image: myapp:latest
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

9. Network Isolation

services:
  frontend:
    networks:
      - public_net
      - internal_net
  
  backend:
    networks:
      - internal_net
  
  database:
    networks:
      - internal_net

networks:
  public_net:
  internal_net:
    internal: true  # ไม่เชื่อมต่อสู่ภายนอก

10. Security Scanning ใน CI/CD

# GitHub Actions
- name: Scan Image
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: myapp:${{ github.sha }}
    format: 'table'
    exit-code: '1'
    severity: 'CRITICAL,HIGH'

สรุป Checklist

  • ✅ รันด้วย non-root user
  • ✅ Pin version ของ base image
  • ✅ Scan หา CVE สม่ำเสมอ
  • ✅ Read-only filesystem ถ้าเป็นไปได้
  • ✅ จำกัด Capabilities
  • ✅ Resource Limits
  • ✅ Network Isolation
  • ✅ ไม่ Mount Docker Socket