Private Docs

IMPL PLAN 09 — Infra & Observability Hardening

6 งานที่ผู้ตรวจถามแน่: non-root container, NetworkPolicy, ingress TLS, ForwardedHeaders, log retention/WORM, security alerting

อัปเดต: 2026-07-07

IMPL PLAN 09 — Infra & Observability Hardening (K8s · Audit Log · Alerting)

วันที่: 07/07/2026 · สถานะ: ⏳ รอ verify · Priority: 🟡 Phase 3 (ยกเว้น 9.5 ForwardedHeaders — ควรทำคู่ rate limiter Phase 1) อ้างอิง: DISCUSSION หมวด 9 · SG-07/17/18/21/25/26 จาก COMPLIANCE

สรุป

6 งาน infra/observability ที่ผู้ตรวจถามแน่: non-root container · NetworkPolicy · ingress TLS · ForwardedHeaders · log retention/tamper-proof · security alerting


งาน 9.1 — Non-Root Container (SG-17)

#ไฟล์Action
1Dockerfile.* ทุก service (src/{Prefix}01.API/Docker/)เพิ่ม USER app (.NET base image 8+ มี user app uid 1654 ในตัว) — ทำที่ Backend_Template ก่อน แล้วไล่ตาม
2Deployment manifests (Backend_Iac/src/yamls/{env}/superapp/deployments/)เพิ่ม securityContext: runAsNonRoot: true, allowPrivilegeEscalation: false, readOnlyRootFilesystem: true (+ emptyDir mount สำหรับ path ที่ต้องเขียน เช่น /tmp, log dir)

⚠️ เช็คก่อน: service ที่เขียนไฟล์ log ลง logs/ (เช่น UserService FileSettings.Path="logs/app-.log") ต้องมี volume เขียนได้ หรือปิด file log บน cluster (มี stdout + collector แล้ว)

งาน 9.2 — NetworkPolicy (SG-18)

ปัจจุบัน: pod ใดๆ คุยกับ pod ใดก็ได้ทั้ง cluster = ทะลุ 1 pod ไปได้ทุก service (ขัด Zero Trust B4)

# Backend_Iac/src/yamls/{env}/superapp/network-policies/default-deny.yaml — ตัวอย่างโครง
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: default-deny-ingress, namespace: superappdev }
spec: { podSelector: {}, policyTypes: [Ingress] }
---
# จากนั้น allow รายเส้นตาม matrix: ingress-nginx → ทุก service (port 8080),
# sentinel → redis, services → postgres/redis/service bus, APIM subnet → sentinel internal

ขั้นตอน: (1) วาด traffic matrix จาก IaC + observability ก่อน (2) apply แบบ audit/dry-run บน dev (3) default-deny + allow ทีละเส้น (4) เฝ้า 1 สัปดาห์ก่อน SIT — ห้าม apply default-deny โดยไม่มี allow ครบ = ล่มทั้ง namespace

งาน 9.3 — Ingress TLS (SG-21)

Ingress manifests ไม่มี tls: block → เพิ่ม cert (cert-manager หรือ KV CSI sync เป็น k8s secret) + ssl-redirect: "true" — ต่อ env ใน Backend_Iac/src/yamls/{env}/superapp/ingresses/

งาน 9.4 — mTLS in-cluster (SG-13) — ประเมิน ไม่บังคับ

ทางเลือก: (ก) NetworkPolicy อย่างเดียว (9.2) = พอสำหรับ compliance ส่วนใหญ่ (ข) service mesh (Istio ambient / Linkerd) = mTLS อัตโนมัติแต่ operational cost สูง — เสนอ: ทำ 9.2 ก่อน แล้ว re-assess (decision ที่ประชุม)

งาน 9.5 — ForwardedHeaders (SG-07) — ⚠️ ทำก่อน/คู่ rate limiter

ปัจจุบัน: UserService Program.cs L88-93 — KnownNetworks.Clear(); KnownProxies.Clear() = เชื่อ X-Forwarded-For จากทุก proxy → client spoof IP ได้ → rate limit per-IP + audit log เพี้ยน

#จุดAction
1helper กลางใน Package (ForwardedHeadersExtensions.cs ใหม่)ตั้ง KnownNetworks = CIDR ของ ingress/APIM subnet (จาก config ต่อ env) แทนการ Clear ทิ้ง
2ทุก service ผ่าน Template + rolloutแทน block เดิมใน Program.cs
3IaC config ต่อ envเพิ่ม ForwardedHeaders:KnownNetworks: ["10.x.x.0/24"] (subnet จริงของแต่ละ env)

งาน 9.6 — Audit Log Retention + Tamper-Proof + Alerting (SG-25/26)

sequenceDiagram
    autonumber
    participant Svc as Services (Serilog + [Audit])
    participant LAW as Log Analytics Workspace
    participant SA as Storage (immutable/WORM)
    participant AL as Azure Monitor Alerts
    participant Team as ทีม (Teams channel)

    Svc->>LAW: structured logs + audit events (มีอยู่แล้ว)
    LAW->>SA: export → container ที่เปิด immutability policy (WORM, ≥90 วัน แก้/ลบไม่ได้)
    Note over LAW: ตั้ง retention ≥ 90 วัน (ตาม API-GL-001 หมวด 6)
    LAW->>AL: scheduled KQL rules
    Note over AL: R1: auth failure > N ครั้ง/5 นาที/บัญชี (brute-force)<br/>R2: 401/403 spike ต่อ service<br/>R3: login จาก pattern ผิดปกติ<br/>R4: SignatureValid=false ถี่ (มีใน log context แล้ว)<br/>R5: 429 spike (โดนยิง หรือ limit แน่นไป)
    AL->>Team: alert + runbook link
#งานจุด
1ตั้ง retention LAW ≥ 90 วัน ทุก env ที่ audit ครอบAzure portal/IaC — snapshot config เป็นหลักฐาน
2Export ไป Storage immutable (WORM) สำหรับ audit eventStorage lifecycle + immutability policy
3Alert rules R1-R5Backend_Iac (ถ้า IaC ครอบ monitor) หรือ portal + export definition เข้า git
4Runbook ตอบสนองต่อ alert (ใครทำอะไรเมื่อเด้ง)docs สั้นๆ ต่อ rule — มาตรฐานสั่ง “ตรวจจับ แจ้งเตือน ตอบสนอง

Verify

  • kubectl exec ... -- whoami ≠ root ทุก pod + pod security admission ตั้ง restricted (dev ก่อน)
  • จาก pod service A: curl ไป service B ที่ไม่อยู่ใน allow matrix → timeout/refused
  • curl http:// → 308 redirect https + cert ถูกต้อง
  • ส่ง X-Forwarded-For: 1.2.3.4 จากนอก KnownNetworks → ระบบไม่เชื่อ (log ยัง IP จริง)
  • KQL query log ย้อน 90 วันได้ + ลอง delete audit blob → ถูกปฏิเสธ (immutable)
  • จำลอง brute-force บน dev → alert เด้งใน Teams

⚠️ ข้อควรระวัง

  1. readOnlyRootFilesystem + file log = pod crash — จัด volume/ปิด file log ก่อน
  2. NetworkPolicy ต้องมี CNI ที่ enforce (Azure CNI / Cilium) — ตรวจ cluster config ก่อนเขียน manifest ไม่งั้น apply แล้วเงียบ (ไม่ enforce = ความมั่นใจปลอม)
  3. Immutable storage ตั้งแล้วแก้ไม่ได้จริงๆ รวมถึงเราเอง — เริ่ม retention ที่ 90 วันพอดีก่อน อย่าตั้งยาวเกินจนเปลืองโดยยังไม่แน่ใจ

🎯 ถ้าเป็นผมจะทำอย่างไร (ความเห็น Fable)

  1. 9.5 ForwardedHeaders ห้ามอยู่ Phase 3 — rate limit per-IP และ audit log ทั้งหมดเพี้ยนถ้า IP spoof ได้ — ต้องขยับไปทำคู่ rate limiter ใน Phase 1 (ตามที่ plan เขียนไว้แล้ว — เน้นย้ำ)
  2. 9.2 NetworkPolicy: ตรวจ CNI enforce ได้จริงก่อนเขียน manifest แม้แต่บรรทัดเดียว — NetworkPolicy บน cluster ที่ไม่ enforce = false sense of security ที่แย่กว่าไม่มี
  3. 9.6 alerting คือสิ่งที่ผมจะดันขึ้น Phase 2 — ทุก control ที่เปิดใน Phase 0-1 (bypass ปิด, FallbackPolicy, rate limit) จะมีค่าก็ต่อเมื่อมีคนเห็นตอนมันทำงาน (401 spike, 429 spike) — เปิด control โดยไม่มี alert = ไม่รู้ว่ากำลังโดนโจมตีหรือกำลัง block user จริง
  4. 9.1 non-root ทำที่ Template + Dockerfile ก่อน แล้วให้ service อัปเดตตามรอบ deploy ปกติ — ไม่ต้องทำ big-bang · readOnlyRootFilesystem ทำทีหลังเพราะต้องเคลียร์ file log ก่อน (เสนอ: ปิด file log บน cluster ไปเลย — stdout + collector มีแล้ว)
  5. 9.4 mTLS: ข้าม — NetworkPolicy + private cluster พอสำหรับ compliance ระดับนี้ · service mesh คือ operational cost ถาวรที่ทีมขนาดนี้ยังไม่ควรแบก — re-assess เมื่อมี requirement จากผู้ตรวจชัดเจนเท่านั้น

📚 อ้างอิงมาตรฐาน (สำหรับใช้ในที่ประชุม):

หลักการแหล่งอ้างอิง
Non-root, no privilege escalation, restricted profile (official)Kubernetes — Pod Security Standards
Default-deny + allow รายเส้น (official)Kubernetes — Network Policies
Checklist รวม K8s hardeningOWASP Kubernetes Security Cheat Sheet
ForwardedHeaders/KnownNetworks — ทำไมห้ามเชื่อทุก proxy (official)Microsoft Learn — Configure ASP.NET Core to work with proxy servers
Log management + retentionNIST SP 800-92 — Guide to Computer Security Log Management
WORM / immutable audit storage (official)Microsoft Learn — Immutable storage for Azure Blob Storage