Home > Blog > tech

Kubernetes Security คืออะไร? Best Practices รักษาความปลอดภัย K8s สำหรับ Production 2026

kubernetes security best practices
Kubernetes Security Best Practices 2026
2026-04-09 | tech | 3600 words

Kubernetes ได้กลายเป็นมาตรฐานในการ Deploy และจัดการ Container Applications ในระดับ Production แต่ด้วยความซับซ้อนของ K8s ทำให้พื้นผิวการโจมตี (Attack Surface) กว้างขึ้นอย่างมาก ในปี 2026 เราเห็นเหตุการณ์ด้านความปลอดภัยที่เกี่ยวข้องกับ Kubernetes เพิ่มขึ้นอย่างต่อเนื่อง ตั้งแต่การเข้าถึง Cluster โดยไม่ได้รับอนุญาต การรั่วไหลของ Secrets ไปจนถึง Supply Chain Attacks ผ่าน Container Images

บทความนี้จะครอบคลุมทุกด้านของ Kubernetes Security ตั้งแต่การทำความเข้าใจ Attack Surface การตั้งค่า RBAC Pod Security Standards Network Policies Secrets Management Image Security Admission Controllers Runtime Security จนถึง Supply Chain Security และ Incident Response พร้อม Best Practices ที่ใช้ได้จริงในสภาพแวดล้อม Production

K8s Attack Surface — พื้นผิวการโจมตี

การรักษาความปลอดภัย Kubernetes ต้องเริ่มจากการเข้าใจว่ามีจุดใดบ้างที่อาจถูกโจมตี Kubernetes มี Component หลายตัวที่ทำงานร่วมกัน และแต่ละตัวมีช่องทางที่อาจถูกเจาะได้

Componentความเสี่ยงการป้องกัน
API Serverเข้าถึงโดยไม่ได้รับอนุญาตRBAC, Authentication, Audit Log
kubeletNode-level access, container escapeปิด anonymous auth, ใช้ certificate
etcdข้อมูลทั้งหมดของ Cluster อยู่ที่นี่Encryption at rest, mTLS, network isolation
Container RuntimeContainer escape, privilege escalationPod Security Standards, seccomp, AppArmor
NetworkPod-to-Pod ไม่มี restrictionNetwork Policies, service mesh
Container ImagesVulnerabilities, malwareImage scanning, signing, minimal base images
Supply ChainCompromised dependenciesSBOM, SLSA, verified publishers
# ตรวจสอบ API Server เบื้องต้น
# ดูว่า anonymous access เปิดอยู่หรือไม่
kubectl auth can-i --list --as=system:anonymous

# ดู RBAC bindings ทั้งหมด
kubectl get clusterrolebindings -o wide
kubectl get rolebindings --all-namespaces -o wide

# ตรวจสอบ kubelet configuration
ssh node1 "cat /var/lib/kubelet/config.yaml | grep -A5 authentication"

# ดู etcd encryption status
kubectl -n kube-system get cm kubeadm-config -o yaml | grep -A10 encryption

RBAC Deep Dive — Role-Based Access Control

RBAC เป็นกลไกหลักในการควบคุมสิทธิ์การเข้าถึง Kubernetes API ทำงานบนหลักการ Least Privilege คือให้สิทธิ์น้อยที่สุดเท่าที่จำเป็น RBAC มี 4 Resources หลัก ได้แก่ Role ClusterRole RoleBinding และ ClusterRoleBinding

Role และ ClusterRole

# Role — สิทธิ์ภายใน Namespace เดียว
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: pod-reader
rules:
- apiGroups: [""]          # core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
- apiGroups: [""]
  resources: ["pods/log"]
  verbs: ["get"]

---
# ClusterRole — สิทธิ์ทั้ง Cluster
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-viewer
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "watch", "list"]
- apiGroups: ["metrics.k8s.io"]
  resources: ["nodes", "pods"]
  verbs: ["get", "list"]

---
# ClusterRole สำหรับ Developer — จำกัดสิทธิ์ชัดเจน
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: developer
rules:
- apiGroups: ["", "apps", "batch"]
  resources: ["pods", "deployments", "services", "configmaps", "jobs", "cronjobs"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list"]        # อ่านได้ แต่แก้ไขไม่ได้
  resourceNames: ["app-config"] # จำกัดเฉพาะ Secret ที่ระบุ
- apiGroups: [""]
  resources: ["pods/exec", "pods/portforward"]
  verbs: ["create"]             # debug ได้

RoleBinding และ ClusterRoleBinding

# RoleBinding — ผูก Role กับ User ใน Namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods-binding
  namespace: production
subjects:
- kind: User
  name: developer@company.com
  apiGroup: rbac.authorization.k8s.io
- kind: Group
  name: dev-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

---
# Service Account — สำหรับ Application
apiVersion: v1
kind: ServiceAccount
metadata:
  name: monitoring-sa
  namespace: monitoring
automountServiceAccountToken: false  # ปิด auto-mount token

---
# ผูก ClusterRole กับ ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: monitoring-binding
subjects:
- kind: ServiceAccount
  name: monitoring-sa
  namespace: monitoring
roleRef:
  kind: ClusterRole
  name: node-viewer
  apiGroup: rbac.authorization.k8s.io
RBAC Best Practices: 1) อย่าใช้ cluster-admin นอกจากจำเป็นจริงๆ 2) ใช้ Service Account แยกต่างหากสำหรับแต่ละ Application 3) ตั้ง automountServiceAccountToken: false เป็น Default 4) ตรวจสอบ RBAC Permissions อย่างสม่ำเสมอ 5) ใช้ Group แทน User สำหรับทีม
# คำสั่งตรวจสอบ RBAC
# ดูว่า User มีสิทธิ์อะไรบ้าง
kubectl auth can-i --list --as=developer@company.com
kubectl auth can-i create pods --as=developer@company.com -n production

# ดู ServiceAccount ที่มี cluster-admin
kubectl get clusterrolebindings -o json | jq '.items[] | select(.roleRef.name=="cluster-admin") | .subjects'

# ตรวจจับ RBAC ที่ให้สิทธิ์มากเกินไป
# ดู wildcards (*) ใน verbs หรือ resources
kubectl get clusterroles -o json | jq '.items[] | select(.rules[]?.verbs[]? == "*") | .metadata.name'

Pod Security Standards — มาตรฐานความปลอดภัย Pod

Pod Security Standards (PSS) เป็นมาตรฐานที่ Kubernetes กำหนดไว้ 3 ระดับ เพื่อควบคุมความปลอดภัยของ Pod ตั้งแต่ Kubernetes 1.25 ใช้ Pod Security Admission (PSA) แทน PodSecurityPolicy (PSP) ที่ถูก Deprecate ไปแล้ว

ระดับความเข้มงวดเหมาะกับ
Privilegedไม่มีข้อจำกัดSystem-level workloads (CNI, storage drivers)
Baselineป้องกัน Privilege Escalation พื้นฐานApplication ทั่วไป
Restrictedเข้มงวดสูงสุด ตามมาตรฐาน HardeningSecurity-critical workloads
# เปิดใช้ Pod Security Standards ผ่าน Namespace Labels
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    # enforce = บังคับ (reject Pod ที่ไม่ผ่าน)
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    # warn = แสดงคำเตือน (แต่ยังอนุญาต)
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/warn-version: latest
    # audit = บันทึกลง Audit Log
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/audit-version: latest

---
# Namespace สำหรับ system workloads
apiVersion: v1
kind: Namespace
metadata:
  name: kube-system
  labels:
    pod-security.kubernetes.io/enforce: privileged

SecurityContext — ตั้งค่าความปลอดภัย Pod/Container

# Pod ที่ผ่าน Restricted level
apiVersion: apps/v1
kind: Deployment
metadata:
  name: secure-app
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: secure-app
  template:
    metadata:
      labels:
        app: secure-app
    spec:
      securityContext:
        runAsNonRoot: true           # ห้ามรันเป็น root
        runAsUser: 1000              # ระบุ UID
        runAsGroup: 1000             # ระบุ GID
        fsGroup: 1000                # Group สำหรับ Volume
        seccompProfile:
          type: RuntimeDefault       # เปิด seccomp
      automountServiceAccountToken: false  # ปิด SA token auto-mount
      containers:
      - name: app
        image: myregistry.com/app:v1.2.3@sha256:abc123...  # ใช้ digest
        securityContext:
          allowPrivilegeEscalation: false  # ห้าม escalate
          readOnlyRootFilesystem: true     # Filesystem อ่านอย่างเดียว
          capabilities:
            drop: ["ALL"]                  # ลบ capabilities ทั้งหมด
          runAsNonRoot: true
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 256Mi
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: cache
          mountPath: /app/cache
      volumes:
      - name: tmp
        emptyDir: {}   # writable /tmp
      - name: cache
        emptyDir:
          sizeLimit: 100Mi
สำคัญ: readOnlyRootFilesystem: true บังคับให้ Container ไม่สามารถเขียนไฟล์บน Root Filesystem ได้ ถ้า Application ต้องเขียนไฟล์ ให้ Mount emptyDir volume เฉพาะ Directory ที่ต้องการ เช่น /tmp หรือ /app/cache

Network Policies — ควบคุมการสื่อสาร Pod

โดย Default Kubernetes อนุญาตให้ Pod ทุกตัวสื่อสารกันได้หมด ซึ่งอันตรายมากใน Production เพราะถ้า Attacker เจาะ Pod หนึ่งได้ จะสามารถเข้าถึง Pod อื่นได้ทั้งหมด Network Policies ช่วยจำกัดการสื่อสารตามหลัก Zero Trust

# Default Deny All — กฎข้อแรกที่ต้องตั้ง
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}    # เลือกทุก Pod ใน Namespace
  policyTypes:
  - Ingress
  - Egress

---
# อนุญาต DNS (จำเป็นสำหรับ Service Discovery)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to: []
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53

---
# Frontend -> Backend: อนุญาตเฉพาะที่จำเป็น
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-allow-from-frontend
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080

---
# Backend -> Database: จำกัดเฉพาะ port 5432
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database-allow-from-backend
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: database
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: backend
    ports:
    - protocol: TCP
      port: 5432

---
# อนุญาต Backend เข้าถึง External API เฉพาะ IP ที่ระบุ
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-egress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/8    # Internal services
    - podSelector:
        matchLabels:
          app: database
    ports:
    - protocol: TCP
      port: 5432
  - to:
    - ipBlock:
        cidr: 203.0.113.0/24  # External API IP range
    ports:
    - protocol: TCP
      port: 443

Secrets Management — จัดการข้อมูลลับ

Kubernetes Secrets โดย Default เก็บข้อมูลแบบ Base64 encoded (ไม่ได้เข้ารหัส) ใน etcd ซึ่งไม่ปลอดภัยเพียงพอสำหรับ Production ต้องใช้วิธีเพิ่มเติมในการปกป้อง Secrets

etcd Encryption at Rest

# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
  - secrets
  - configmaps
  providers:
  - aescbc:
      keys:
      - name: key1
        secret: 
  - identity: {}  # fallback สำหรับอ่าน secrets เก่า

# เพิ่มใน API Server flags:
# --encryption-provider-config=/etc/kubernetes/encryption-config.yaml

# ตรวจสอบว่า Encryption ทำงาน
kubectl get secret test-secret -o yaml
# ถ้า annotated ว่า encrypted = ทำงานถูกต้อง

# Re-encrypt secrets ที่มีอยู่
kubectl get secrets --all-namespaces -o json | kubectl replace -f -

External Secrets Operator

# ใช้ External Secrets Operator ดึง Secrets จาก Vault/AWS/GCP
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault-backend
  namespace: production
spec:
  provider:
    vault:
      server: "https://vault.company.com"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "production-app"
          serviceAccountRef:
            name: vault-auth-sa

---
# ExternalSecret — ดึง Secret จาก Vault อัตโนมัติ
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: app-secrets
  namespace: production
spec:
  refreshInterval: 1h          # Sync ทุก 1 ชั่วโมง
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: app-secrets           # K8s Secret ที่จะสร้าง
    creationPolicy: Owner
  data:
  - secretKey: database-url
    remoteRef:
      key: production/database
      property: url
  - secretKey: api-key
    remoteRef:
      key: production/api
      property: key

---
# AWS Secrets Manager
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: aws-secrets
spec:
  provider:
    aws:
      service: SecretsManager
      region: ap-southeast-1
      auth:
        jwt:
          serviceAccountRef:
            name: aws-sa

SOPS — Encrypted Secrets ใน Git

# ใช้ Mozilla SOPS เข้ารหัส Secrets ก่อนเก็บใน Git
# ติดตั้ง: brew install sops

# สร้าง .sops.yaml ใน root ของ repo
creation_rules:
  - path_regex: .*secrets.*\.yaml$
    encrypted_regex: ^(data|stringData)$
    kms: arn:aws:kms:ap-southeast-1:123456:key/abc-def
    # หรือใช้ age: age1...

# เข้ารหัส
sops --encrypt secrets.yaml > secrets.enc.yaml

# แก้ไข (จะ decrypt ให้อัตโนมัติใน editor)
sops secrets.enc.yaml

# ใช้กับ Flux CD / ArgoCD
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: app
spec:
  decryption:
    provider: sops
    secretRef:
      name: sops-age-key

Image Security — ความปลอดภัยของ Container Image

Vulnerability Scanning ด้วย Trivy

# Scan Image เพื่อหา Vulnerabilities
trivy image myapp:latest

# Scan เฉพาะ HIGH และ CRITICAL
trivy image --severity HIGH,CRITICAL myapp:latest

# Scan ใน CI/CD Pipeline — Fail ถ้าพบ CRITICAL
trivy image --exit-code 1 --severity CRITICAL myapp:latest

# Scan Kubernetes Cluster ทั้งหมด
trivy k8s --report summary cluster

# Scan SBOM (Software Bill of Materials)
trivy image --format spdx-json -o sbom.json myapp:latest

# ใช้ Trivy Operator — Scan อัตโนมัติใน Cluster
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/trivy-operator/main/deploy/static/trivy-operator.yaml

# ดูผล VulnerabilityReport
kubectl get vulnerabilityreports -A -o wide

Image Signing ด้วย cosign/Sigstore

# ติดตั้ง cosign
# brew install cosign

# สร้าง Keypair
cosign generate-key-pair

# Sign Image
cosign sign --key cosign.key myregistry.com/app:v1.0.0

# Verify Image
cosign verify --key cosign.pub myregistry.com/app:v1.0.0

# Keyless Signing (ใช้ OIDC identity - แนะนำ)
cosign sign myregistry.com/app:v1.0.0
# จะเปิด Browser ให้ Login ด้วย Google/GitHub

# Verify Keyless
cosign verify \
  --certificate-identity=ci@company.com \
  --certificate-oidc-issuer=https://accounts.google.com \
  myregistry.com/app:v1.0.0

Dockerfile Best Practices สำหรับ Security

# ใช้ Minimal Base Image
FROM cgr.dev/chainguard/python:latest-dev AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Multi-stage: Final image ไม่มี build tools
FROM cgr.dev/chainguard/python:latest
WORKDIR /app
COPY --from=builder /app /app
COPY . .

# รันเป็น Non-root user
USER 65534:65534

# ใช้ ENTRYPOINT แทน CMD
ENTRYPOINT ["python", "app.py"]

# อย่า COPY . . ก่อน RUN pip install (cache layer)
# อย่าเก็บ secrets ใน image
# อย่าใช้ :latest tag ใน production
# ใช้ image digest แทน tag สำหรับ deterministic builds

Admission Controllers — Policy Enforcement

Admission Controllers ทำหน้าที่ตรวจสอบและบังคับ Policy ก่อนที่ Resource จะถูกสร้างใน Cluster เปรียบเหมือน Gatekeeper ที่ยืนหน้าประตู ตรวจสอบว่า Resource ที่จะเข้ามาเป็นไปตามกฎหรือไม่

Kyverno — Policy Engine ที่ใช้งานง่าย

# ติดตั้ง Kyverno
helm install kyverno kyverno/kyverno -n kyverno --create-namespace

---
# Policy: บังคับให้ทุก Pod ต้องไม่รันเป็น root
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-run-as-nonroot
spec:
  validationFailureAction: Enforce  # Enforce = block, Audit = log only
  rules:
  - name: run-as-non-root
    match:
      any:
      - resources:
          kinds: ["Pod"]
    validate:
      message: "Running as root is not allowed."
      pattern:
        spec:
          securityContext:
            runAsNonRoot: true
          containers:
          - securityContext:
              runAsNonRoot: true

---
# Policy: บังคับ Resource Limits
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
spec:
  validationFailureAction: Enforce
  rules:
  - name: check-limits
    match:
      any:
      - resources:
          kinds: ["Pod"]
    validate:
      message: "CPU and memory limits are required."
      pattern:
        spec:
          containers:
          - resources:
              limits:
                cpu: "?*"
                memory: "?*"

---
# Policy: ห้ามใช้ :latest tag
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-latest-tag
spec:
  validationFailureAction: Enforce
  rules:
  - name: no-latest
    match:
      any:
      - resources:
          kinds: ["Pod"]
    validate:
      message: "Using ':latest' tag is not allowed."
      pattern:
        spec:
          containers:
          - image: "!*:latest"

---
# Policy: Auto-add labels ให้ทุก Pod
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-default-labels
spec:
  rules:
  - name: add-labels
    match:
      any:
      - resources:
          kinds: ["Pod"]
    mutate:
      patchStrategicMerge:
        metadata:
          labels:
            managed-by: kyverno
            security-scan: required

OPA/Gatekeeper

# ConstraintTemplate — กำหนดรูปแบบ Policy
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
  - target: admission.k8s.gatekeeper.sh
    rego: |
      package k8srequiredlabels
      violation[{"msg": msg}] {
        provided := {label | input.review.object.metadata.labels[label]}
        required := {label | label := input.parameters.labels[_]}
        missing := required - provided
        count(missing) > 0
        msg := sprintf("Missing required labels: %v", [missing])
      }

---
# Constraint — ใช้ Template บังคับ labels
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: require-team-label
spec:
  match:
    kinds:
    - apiGroups: [""]
      kinds: ["Namespace"]
  parameters:
    labels: ["team", "environment", "cost-center"]

Runtime Security — ตรวจจับภัยคุกคามขณะรัน

Falco — Runtime Threat Detection

# ติดตั้ง Falco ด้วย Helm
helm install falco falcosecurity/falco \
  --namespace falco --create-namespace \
  --set falcosidekick.enabled=true \
  --set falcosidekick.config.slack.webhookurl="https://hooks.slack.com/..."

# Falco Rules ตัวอย่าง
- rule: Terminal shell in container
  desc: ตรวจจับการเปิด shell ใน Container
  condition: >
    spawned_process and container
    and shell_procs and proc.tty != 0
    and container_entrypoint
  output: >
    Shell opened in container
    (user=%user.name container=%container.name
    shell=%proc.name parent=%proc.pname)
  priority: WARNING
  tags: [container, shell, mitre_execution]

- rule: Read sensitive file in container
  desc: ตรวจจับการอ่านไฟล์ sensitive
  condition: >
    open_read and container
    and (fd.name startswith /etc/shadow or
         fd.name startswith /etc/passwd or
         fd.name contains private_key)
  output: >
    Sensitive file read (file=%fd.name container=%container.name)
  priority: CRITICAL

- rule: Outbound connection to suspicious IP
  desc: ตรวจจับ Connection ไปยัง IP ที่น่าสงสัย
  condition: >
    outbound and container
    and fd.sip.name in (crypto_mining_pools)
  output: >
    Suspicious outbound connection
    (container=%container.name ip=%fd.sip)
  priority: CRITICAL

Tetragon — eBPF-based Security Observability

# ติดตั้ง Tetragon
helm install tetragon cilium/tetragon -n kube-system

# TracingPolicy — Monitor file access
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
  name: monitor-sensitive-files
spec:
  kprobes:
  - call: "security_file_open"
    syscall: false
    args:
    - index: 0
      type: "file"
    selectors:
    - matchArgs:
      - index: 0
        operator: "Prefix"
        values:
        - "/etc/shadow"
        - "/etc/passwd"
        - "/root/.ssh"

# ดู Events
kubectl logs -n kube-system ds/tetragon -f | tetra getevents

Supply Chain Security — ความปลอดภัย Software Supply Chain

SBOM — Software Bill of Materials

# สร้าง SBOM ด้วย Syft
syft myregistry.com/app:v1.0.0 -o spdx-json > sbom.json

# Scan SBOM เพื่อหา Vulnerabilities
grype sbom:sbom.json

# Attach SBOM กับ Image ด้วย cosign
cosign attach sbom --sbom sbom.json myregistry.com/app:v1.0.0

SLSA — Supply-chain Levels for Software Artifacts

# GitHub Actions workflow สำหรับ SLSA Level 3
name: Build and Attest
on:
  push:
    tags: ['v*']

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      id-token: write    # สำหรับ keyless signing
      contents: read
      packages: write
    steps:
    - uses: actions/checkout@v4

    - name: Build Image
      run: docker build -t myregistry.com/app:${GITHUB_REF_NAME} .

    - name: Generate SBOM
      uses: anchore/sbom-action@v0
      with:
        image: myregistry.com/app:${GITHUB_REF_NAME}

    - name: Sign Image (Keyless)
      run: cosign sign myregistry.com/app:${GITHUB_REF_NAME}

    - name: Generate SLSA Provenance
      uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1
      with:
        image: myregistry.com/app
        digest: ${steps.build.outputs.digest}

Audit Logging — บันทึกการเข้าถึง

# Audit Policy — กำหนดว่าจะ Log อะไรบ้าง
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Log ทุกการเปลี่ยนแปลง Secrets (RequestResponse level)
- level: RequestResponse
  resources:
  - group: ""
    resources: ["secrets"]

# Log การสร้าง/ลบ resources ที่สำคัญ
- level: RequestResponse
  resources:
  - group: ""
    resources: ["pods", "services"]
  - group: "apps"
    resources: ["deployments", "statefulsets"]
  - group: "rbac.authorization.k8s.io"
    resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
  verbs: ["create", "update", "patch", "delete"]

# Log kubectl exec/attach (ใครเข้าไปใน Pod)
- level: RequestResponse
  resources:
  - group: ""
    resources: ["pods/exec", "pods/attach", "pods/portforward"]

# Skip logging health checks
- level: None
  users: ["system:kube-proxy"]
  verbs: ["watch"]

# Default: log metadata ของทุกอย่าง
- level: Metadata

# ใช้กับ API Server:
# --audit-policy-file=/etc/kubernetes/audit-policy.yaml
# --audit-log-path=/var/log/kubernetes/audit.log
# --audit-log-maxage=30
# --audit-log-maxbackup=10
# --audit-log-maxsize=100

CIS Kubernetes Benchmark

CIS (Center for Internet Security) มี Benchmark สำหรับ Kubernetes ที่เป็นมาตรฐานอุตสาหกรรม ครอบคลุมการตั้งค่าทุกส่วนของ Cluster

# ใช้ kube-bench ตรวจสอบ CIS Benchmark
# ติดตั้งและรัน
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro \
  -t aquasec/kube-bench:latest run --targets=master

# หรือรันเป็น Job ใน Cluster
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
kubectl logs job/kube-bench

# ตัวอย่าง Output:
# [PASS] 1.1.1 Ensure API server pod specification file permissions
# [FAIL] 1.1.2 Ensure API server pod specification file ownership
# [WARN] 1.1.3 Ensure controller manager pod specification
# ...
# == Summary master ==
# 42 checks PASS
# 8 checks FAIL
# 11 checks WARN

# Checklist สำคัญ:
# - API Server: เปิด RBAC, ปิด anonymous auth, ตั้ง audit logging
# - etcd: เข้ารหัส at rest, ใช้ TLS, จำกัด access
# - kubelet: ปิด anonymous auth, เปิด certificate rotation
# - Network: ตั้ง Network Policies, ใช้ encrypted communication

Multi-tenancy Security — หลายทีมใช้ Cluster เดียว

# Namespace Isolation สำหรับแต่ละทีม
apiVersion: v1
kind: Namespace
metadata:
  name: team-alpha
  labels:
    team: alpha
    pod-security.kubernetes.io/enforce: restricted

---
# ResourceQuota — จำกัด Resources ต่อ Namespace
apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-alpha-quota
  namespace: team-alpha
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    pods: "50"
    services: "20"
    secrets: "30"
    persistentvolumeclaims: "10"

---
# LimitRange — กำหนด Default Limits
apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: team-alpha
spec:
  limits:
  - default:
      cpu: 500m
      memory: 256Mi
    defaultRequest:
      cpu: 100m
      memory: 128Mi
    max:
      cpu: "2"
      memory: 2Gi
    min:
      cpu: 50m
      memory: 64Mi
    type: Container

---
# Network Policy — Isolation ระหว่าง Namespaces
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-from-other-namespaces
  namespace: team-alpha
spec:
  podSelector: {}
  ingress:
  - from:
    - podSelector: {}  # อนุญาตเฉพาะภายใน Namespace เดียวกัน

Zero Trust ใน Kubernetes

Zero Trust หมายความว่า "ไม่ไว้ใจใครเลย แม้แต่ภายใน Cluster" ทุกการสื่อสารต้องผ่านการตรวจสอบและเข้ารหัส

# Service Mesh (Istio) — mTLS ระหว่าง Services ทั้งหมด
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: strict-mtls
  namespace: production
spec:
  mtls:
    mode: STRICT    # บังคับ mTLS ทุก connection

---
# Authorization Policy — ใครเข้าถึง Service ใดได้
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: backend-policy
  namespace: production
spec:
  selector:
    matchLabels:
      app: backend
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/production/sa/frontend-sa"]
    to:
    - operation:
        methods: ["GET", "POST"]
        paths: ["/api/*"]

---
# Deny ทั้งหมดที่ไม่ match กฎ
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: deny-all
  namespace: production
spec:
  {}  # Empty spec = deny all

Security Monitoring และ Incident Response

# Prometheus Alerts สำหรับ Security Events
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: security-alerts
spec:
  groups:
  - name: kubernetes-security
    rules:
    - alert: PrivilegedContainerDetected
      expr: |
        kube_pod_container_status_running{} * on(pod, namespace)
        group_left() kube_pod_spec_containers_security_context_privileged{} == 1
      for: 1m
      labels:
        severity: critical
      annotations:
        summary: "Privileged container detected: {{ $labels.pod }}"

    - alert: PodRunningAsRoot
      expr: |
        kube_pod_container_status_running{} * on(pod, namespace)
        group_left() (kube_pod_spec_containers_security_context_run_as_user{} == 0)
      for: 1m
      labels:
        severity: warning
      annotations:
        summary: "Container running as root: {{ $labels.pod }}"

    - alert: UnauthorizedAPIAccess
      expr: |
        sum(rate(apiserver_audit_event_total{verb=~"create|update|delete",
        user_agent!~".*kube.*"}[5m])) by (user) > 100
      for: 5m
      labels:
        severity: warning

# Incident Response Checklist:
# 1. ตรวจจับ: Falco alert, Audit log, Prometheus alert
# 2. กักกัน: NetworkPolicy deny-all, cordon node
# 3. สืบสวน: kubectl logs, audit logs, Falco events
# 4. กู้คืน: Redeploy from clean image, rotate secrets
# 5. ป้องกัน: Update policies, patch vulnerabilities
# Incident Response Commands
# 1. กักกัน Pod ที่ถูกเจาะ (ตัด Network ทันที)
kubectl label pod compromised-pod quarantine=true
# + NetworkPolicy ที่ deny traffic จาก label quarantine=true

# 2. เก็บ Evidence ก่อนลบ
kubectl logs compromised-pod > /evidence/pod-logs.txt
kubectl describe pod compromised-pod > /evidence/pod-describe.txt
kubectl get pod compromised-pod -o yaml > /evidence/pod-yaml.txt

# 3. ดู Audit Log ว่าใครทำอะไร
cat /var/log/kubernetes/audit.log | jq 'select(.user.username=="suspicious-user")'

# 4. Cordon Node ที่มีปัญหา
kubectl cordon affected-node
kubectl drain affected-node --ignore-daemonsets

# 5. Rotate Secrets ที่อาจถูกเข้าถึง
kubectl delete secret compromised-secret -n production
kubectl create secret generic compromised-secret --from-literal=key=NEW_VALUE

# 6. ตรวจสอบ Image ที่ใช้
trivy image affected-image:tag --severity CRITICAL,HIGH

Security Checklist สำหรับ Production K8s

หมวดรายการตรวจสอบสถานะ
RBACไม่มี User/SA ที่มี cluster-admin โดยไม่จำเป็นตรวจสอบ
RBACautomountServiceAccountToken: false เป็น Defaultตรวจสอบ
Pod SecurityNamespace ทุกอันมี PSS Label (Restricted)ตรวจสอบ
Pod SecurityrunAsNonRoot: true ทุก Containerตรวจสอบ
Pod SecurityreadOnlyRootFilesystem: trueตรวจสอบ
Pod Securitydrop ALL capabilitiesตรวจสอบ
NetworkDefault Deny NetworkPolicy ทุก Namespaceตรวจสอบ
Secretsetcd Encryption at Rest เปิดตรวจสอบ
Secretsใช้ External Secrets (Vault/AWS SM)ตรวจสอบ
ImagesScan ทุก Image ใน CI/CDตรวจสอบ
Imagesใช้ Image Digest แทน Tagตรวจสอบ
ImagesSign Image ด้วย cosignตรวจสอบ
AdmissionKyverno/OPA Gatekeeper ติดตั้งแล้วตรวจสอบ
RuntimeFalco/Tetragon สำหรับ Runtime Detectionตรวจสอบ
AuditAudit Logging เปิดและส่งไป SIEMตรวจสอบ
CISkube-bench ผ่านทุกข้อ CRITICALตรวจสอบ

สรุป

Kubernetes Security ไม่ใช่สิ่งที่ตั้งค่าครั้งเดียวแล้วจบ แต่เป็นกระบวนการต่อเนื่องที่ต้องดูแลและปรับปรุงอยู่เสมอ การรักษาความปลอดภัย K8s ที่ดีต้องครอบคลุมทุกชั้น ตั้งแต่ Infrastructure ไปจนถึง Application และ Supply Chain

เริ่มต้นจากสิ่งที่สำคัญที่สุดก่อน ได้แก่ RBAC ที่เข้มงวด Pod Security Standards ระดับ Restricted Network Policies แบบ Default Deny และ Secrets ที่เข้ารหัส จากนั้นค่อยเพิ่ม Admission Controllers Image Scanning Runtime Security และ Audit Logging ทีละขั้น อย่าลืมรัน CIS Benchmark เป็นประจำเพื่อตรวจสอบว่า Cluster ของคุณเป็นไปตามมาตรฐาน และเตรียม Incident Response Plan ไว้เสมอ เพราะคำถามไม่ใช่ว่า "จะถูกโจมตีหรือไม่" แต่คือ "จะถูกโจมตีเมื่อไหร่" การเตรียมพร้อมจะทำให้คุณรับมือได้อย่างมีประสิทธิภาพ


Back to Blog | iCafe Forex | SiamLanCard | Siam2R