ข้ามไปที่เนื้อหา

คำขอเครื่อง UAT ใหม่ (Full Stack) — Phase 2

เป้าหมาย: ขอ VM UAT ใหม่ 1 เครื่อง ที่รันครบทุกระบบ S1–S9 พร้อม Keycloak + MinIO + เชื่อม AD ของตัวเอง เพื่อให้ทีมทดสอบ คุม Authentication & Authorization เองได้เต็มที่ (จัดการ realm / client / role / user ได้อิสระ ไม่ต้องแตะ SSO กลาง prod)

ทำไมต้องแยก: ปัจจุบัน UAT บน .124 ใช้ Keycloak กลาง prod sso.rlpd.go.th (.127) realm rlpd ร่วมกัน → แก้ role/client เพื่อ test ไม่ได้โดยไม่กระทบ prod ไม่ระบุ credentials ในไฟล์นี้ — ดู VM_Credentials.xlsx / vault


1. สเปคเครื่องที่ขอ

รายการ สเปคที่ขอ เหตุผล
OS Ubuntu 24.04 LTS ตรง pattern prod .119 / uat .124
CPU / RAM / Disk 8 vCPU · 32 GB RAM · 2 TB (เดิมขอ 500 GB → ขยายเป็น 2 TB) รันครบ S1–S9 + Keycloak + Postgres + MSSQL + MinIO · ขยาย storage เพราะ S6 OCIPA จะย้าย DB (RLPD02 — legacy ก้อนใหญ่) มา reuse MSSQL 2022 บนเครื่องนี้ + persistent volume/nightly backup ของทุกระบบ (ดู OCIPA_UAT_DOCKER_REQUEST.md §5.1) — .124 เดิม 7.7 GB ตันแล้ว
Virtualization Nutanix AHV มาตรฐานกรม
Network subnet 10.136.27.0/24 · เปิด 22/443 จาก VPN เข้าถึงผ่าน VPN เดียวกัน
DNS uat-<ระบบ>.rlpd.go.th (เช่น uat-webportal, uat-lcs) — GDCC prefix uat- อ่านง่าย/group ง่าย · อยู่ใต้ wildcard cert *.rlpd.go.th เดิม (ได้ TLS ฟรี) — ขอแค่ A record ต่อโฮสต์ ชี้ IP เครื่องใหม่
Directory Test AD/LDAP แยกบนเครื่องนี้ (ไม่แตะ prod AD .15) isolate การทดสอบ user/group/role เต็มตัว ไม่กระทบ auth ของกรมจริง
+ S6 (แยก) คง OCIPA UAT .144 (Windows/IIS) เดิม .NET Framework 4.7.2 รันบน Ubuntu container ไม่ได้

2. Stack ที่รันบนเครื่อง (Docker บน host เดียว)

Component รูปแบบ Port UAT DNS หมายเหตุ
nginx (reverse proxy) host-level 443 (front ทุกโดเมน) reverse proxy กลาง
S1 ให้คำปรึกษา 🐳 Node (React/Vite + NestJS) uat-lcs.rlpd.go.th greenfield
S2 PJOS 🐳 Node uat-pjos.rlpd.go.th greenfield
S3 รายงานผล/หลักสูตร 🐳 Node uat-ar-crs.rlpd.go.th greenfield
S4 ไกล่เกลี่ย 🐳 React/Vite + NestJS (Phase-2) uat-emediation.rlpd.go.th cutover จาก legacy + migrate data
S5 เบิกจ่าย 134/1 🐳 PHP 7.4 CodeIgniter (โค้ดเดิม) uat-ia.rlpd.go.th มี Dockerfile.local แล้ว
S7 คุ้มครองพยาน WPIS 🐳 .NET 9 uat-wpis.rlpd.go.th port เป็น Linux แล้ว
S8 เว็บไซต์กรม (public front) 🐳 .NET Core 3.1 (⚠️ bump 8) uat-www.rlpd.go.th เว็บ public ที่ประชาชนเข้า — prod = www.rlpd.go.th (live, หลัง Imperva WAF)
S8 — Admin (CMS) 🐳 .NET Core 3.1 uat-ww2-admin.rlpd.go.th "ระบบบริหารจัดการเว็บไซต์" — prod = ww2-admin.rlpd.go.th
S8 — API 🐳 .NET Core 3.1 uat-ww2-api.rlpd.go.th prod = ww2-api.rlpd.go.th (IIS/ASP.NET)
S9 Web Portal 🐳 Node uat-webportal.rlpd.go.th Phase 1 reference
S9Open Data API (ให้หน่วยงานภายนอกเรียก) 🐳 Node (BFF ตัวเดียวกับ S9) uat-openapi.rlpd.go.th 🆕 REQ-WPT-001 · prod = openapi.rlpd.go.th · ⚠️ ต้องเปิดจาก internet (ไม่ใช่ VPN-only เหมือน host อื่นในตารางนี้) — ดู §2.1
Keycloak (SSO) 🐳 Keycloak 8443 uat-sso.rlpd.go.th realm UAT ของตัวเอง — คุม client/role/user · ⚠️ token endpoint ต้องเรียกได้จาก internet ด้วย (§2.1)
PostgreSQL (Keycloak DB) 🐳 postgres 5432 (internal) backing store ของ Keycloak
Test AD (Directory) 🐳 Samba AD (จำลอง) 389 (internal) directory แยกของ UAT — bind DN ตรง prod, ไม่แตะ AD .15 · มี compose พร้อมบน dev box 72.60.211.241 ก็อปมาได้เลย
MSSQL 2022 (App DB) 🐳 mssql:2022 + persistent volume 1433 (internal) DB ของทุกระบบ + nightly backup
MinIO (Object Storage) 🐳 minio 9000/9001 uat-minio.rlpd.go.th (console) · uat-s3.rlpd.go.th (API) ไฟล์แนบ แยก bucket ต่อระบบ
S6 OCIPA 🪟 บน .144 (นอกเครื่องนี้) 443 uat-ocipa.rlpd.go.th ข้อยกเว้น — Windows/IIS

2.1 Open Data API — DNS + ทางเข้าจากภายนอก (REQ-WPT-001)

โจทย์: หน่วยงานภายนอก (สป.ยธ. / MSC / หน่วยงานที่ขอ dataset) ต้อง เรียก API ได้จากอินเทอร์เน็ต — ไม่ได้ต่อ VPN กรม ต่างจากทุก host ในตาราง §2 ที่เป็น VPN-only

Flow ที่ผู้เรียกภายนอกต้องทำ (2 hop — ต้องเปิดทั้งคู่):

  1. POST https://uat-sso.rlpd.go.th/realms/rlpd/protocol/openid-connect/token (grant client_credentials) → ได้ access token
  2. GET https://uat-openapi.rlpd.go.th/api/dataset (header Authorization: Bearer <token>) → ได้ข้อมูล dataset ที่ผูกกับ client นั้น
รายการ UAT Prod หมายเหตุ
Open Data API uat-openapi.rlpd.go.th openapi.rlpd.go.th A record → IP เครื่อง UAT/prod · nginx proxy เฉพาะ path /api/dataset ไป BFF ของ S9 (ชื่อโฮสต์บอกอยู่แล้วว่าเป็น Open API → ไม่ซ้ำใน path)
Keycloak token endpoint uat-sso.rlpd.go.th sso.rlpd.go.th (มีอยู่แล้ว) เปิดแค่ /realms/rlpd/protocol/openid-connect/token พอ — ไม่ต้องเปิด /admin

สิ่งที่ต้องขอเพิ่มนอกจาก A record:

  • Inbound 443 จาก internetuat-openapi และ token endpoint ของ uat-sso (host อื่นคงเดิม VPN-only)
  • Outbound BFF → Keycloak — โค้ดตรวจ token ด้วย introspection endpoint ของ Keycloak (ไม่ได้ verify JWT เอง) และตอน admin ออก client ใหม่เรียก Keycloak Admin API → เครื่อง S9 ต้องคุยกับ Keycloak ได้ทั้ง 2 ทาง ไม่ใช่แค่เปิดขาเข้า
  • หลัง WAF — ใช้แนวเดียวกับ www.rlpd.go.th (Imperva) หรืออย่างน้อย rate limit ที่ nginx
  • TLS: อยู่ใต้ wildcard *.rlpd.go.th เดิม → ไม่ต้องขอ cert ใหม่
  • nginx เปิดเฉพาะ path ที่จำเป็น: location = /api/dataset เท่านั้น — path อื่นของ BFF (/api/admin/*, /api/auth/*, …) ต้อง block บนโฮสต์นี้ ไม่ให้ portal ทั้งตัวหลุดออก internet (สำคัญกว่าเดิม เพราะตอนนี้ endpoint อยู่ใต้ /api ตรง ๆ ไม่มี prefix open-api กันไว้แล้ว)
  • ⚠️ nginx ต้องเขียนทับ X-Forwarded-For: proxy_set_header X-Forwarded-For $remote_addr; (ห้ามใช้ $proxy_add_x_forwarded_for) — แอปอ่าน IP ผู้เรียกจาก header ตัวนี้ ถ้าไม่เขียนทับ ผู้เรียกภายนอกปลอม header เองแล้ว ข้าม IP allowlist ได้

Compensating control ที่มีในโค้ดแล้ว (ไม่ต้องขอ infra เพิ่ม): OAuth2 client_credentials ต่อหน่วยงาน (auto-provision client opendata_* ใน Keycloak, secret โชว์ครั้งเดียว) · one client = one dataset — client_id จาก token เป็นตัวเลือก dataset เอง ไม่มี id ใน URL · คอลัมน์ที่เห็นได้เป็น allowlist ที่ admin คัดจาก view เท่านั้น · row limit (default 1,000 · สูงสุด 5,000) · IP allowlist ต่อ token (ApiTokens.AllowedIpAddresses) · log ทุกครั้งที่เรียกลง OpenApiExecuteLog (รวมเคส IP_DENIED)

ตอนขอข้อมูลจากหน่วยงานภายนอก: IP allowlist ในโค้ดเทียบ IP ตรงตัว (ไม่รองรับ CIDR/range) → ต้องขอ public egress IP แบบ fix จากหน่วยงานผู้เรียก (ถ้าเขาออกหลาย IP ให้ระบุมาให้ครบทุกตัว)

ถ้ากรมไม่ยอมเปิด BFF ออก internet ตรง ๆ: ทางเลือกคือวาง reverse proxy/API gateway ตัวหน้าไว้ DMZ แล้ว forward เข้ามา — DNS ที่ขอยังชื่อเดิม (openapi.rlpd.go.th) แค่ชี้ไป DMZ แทน


3. Authentication & Authorization Chain (จุดที่อยากคุมเอง)

ชั้น ตัวใน UAT (แยกทั้งหมด) บทบาท คุมอะไรได้
Directory Test AD/LDAP UAT (บนเครื่องใหม่) แหล่ง user/group ของ UAT คุมเต็ม — สร้าง/แก้ user, OU, group ได้อิสระ ไม่แตะ prod AD .15
IdP / SSO Keycloak UAT (บนเครื่องใหม่) realm/client/role ของ UAT คุมเต็ม — สร้าง client, map role, ทดสอบ flow ได้อิสระ
Object ACL MinIO UAT (บนเครื่องใหม่) bucket policy ต่อระบบ ✅ คุม access key / bucket policy เอง
App (S1–S9) OIDC client → Keycloak UAT rely on token/role ทดสอบ RBAC ต่อระบบ

หลักการ: user จาก Samba AD (UAT) → auth ผ่าน Keycloak UAT → app เช็ค role/permission จาก token · ทั้ง 3 ชั้นแยกจาก production ทั้งหมด (ไม่แตะ AD .15 / SSO .127) ทดสอบ Authen/Authorize ได้ครบวงจรแบบ isolate เต็มตัว Template พร้อมแล้ว: stack นี้ (Keycloak 26.1 + Postgres + Samba AD จำลอง + realm rlpd Model B) รันอยู่บน dev box 72.60.211.241 แล้ว — Samba bind DN ตรง prod (CN=Rlpd ADmange,OU=ICT,OU=Group User,DC=rlpd,DC=go,DC=th), Keycloak vendor=addrop-in ย้ายไป AD จริงแค่เปลี่ยน connectionUrl เป็น LDAPS · ก็อป compose จาก box มาใช้บนเครื่อง UAT ใหม่ได้เลย (ดู SSO_PROD_MIGRATION.md §1.6, §4)


4. สิ่งที่ต้องขอ / ตั้งค่าเพิ่ม

รายการ ต้องทำ
VM 8vCPU/32GB Ubuntu · storage 2 TB (ขยายจาก 500 GB — รองรับ DB OCIPA ที่ย้ายมา reuse) ขอกรมจัดสรร/ขยาย disk เครื่อง .155 (Nutanix)
Samba AD + Keycloak + Postgres container ก็อป compose จาก dev box 72.60.211.241 (พร้อมแล้ว) — ไม่ต้องเปิด firewall ไป prod AD .15
DNS uat-*.rlpd.go.th (A record ต่อโฮสต์ → IP เครื่องใหม่) ขอผ่าน GDCC — ใช้ wildcard cert *.rlpd.go.th เดิม
DNS uat-openapi.rlpd.go.th + prod openapi.rlpd.go.th 🆕 ขอผ่าน GDCC — A record + เปิด 443 จาก internet (ไม่ใช่ VPN-only) ให้หน่วยงานภายนอกเรียก Open Data API · ดู §2.1
เปิด token endpoint ของ Keycloak ออก internet 🆕 /realms/rlpd/protocol/openid-connect/token เท่านั้น (UAT uat-sso · prod sso.rlpd.go.th) — ไม่มีอันนี้ผู้เรียกภายนอกขอ token ไม่ได้
MSSQL persistent volume + nightly backup ตั้งบนเครื่องใหม่ (อย่าซ้ำปัญหา .124 ที่ไม่มี volume)
S6 UAT ใช้ .144 Windows/IIS เดิม

5. 🆕 รายการ DNS A-record ที่ต้องขอ (concrete — พร้อมส่ง GDCC/ทีม network) — ยืนยัน 2026-07-20

เครื่อง UAT จริงถูกยกขึ้นแล้ว: 10.136.27.155 (VM RLPD_UAT_Devphase2, hostname rlpdustdevphase2, Ubuntu 24.04, บน RLPD LAN). Stack รันครบ: nginx (80/443) + Keycloak (realm rlpd) + Postgres + MinIO + MSSQL + Samba AD.

ตรวจ DNS 2026-07-20 (resolver กรม 115.178.58.10/.26): ทุก host ด้านล่าง = NXDOMAIN — ยังไม่มี record สักตัว. ผลคือตอนนี้เข้าถึงได้เฉพาะเครื่องที่แก้ /etc/hosts เอง → เป็น blocker สำหรับให้ทีม/ผู้ทดสอบคนอื่นเข้าใช้. cert *.rlpd.go.th (Sectigo, ถึง 2026-07-31) ครอบทุก host แล้ว → ขอแค่ A record ไม่ต้องขอ cert.

ขอ A record ทั้งหมดชี้ 10.136.27.155:

# FQDN Type ระบบ หมายเหตุ
1 uat-sso.rlpd.go.th A 10.136.27.155 infra Keycloak SSO (ทุกระบบ login ผ่านนี้)
2 uat-s3.rlpd.go.th A 10.136.27.155 infra MinIO S3 API (แอปเก็บ/ดึงไฟล์)
3 uat-minio.rlpd.go.th A 10.136.27.155 infra MinIO console UI
4 uat-lcs.rlpd.go.th A 10.136.27.155 S1 Legal Consultation
5 uat-pjos.rlpd.go.th A 10.136.27.155 S2 PJOS
6 uat-ar-crs.rlpd.go.th A 10.136.27.155 S3 Activity Report/Courses
7 uat-emediation.rlpd.go.th A 10.136.27.155 S4 Mediation
8 uat-ia.rlpd.go.th A 10.136.27.155 S5 Lawyer Compensation (ม.134/1)
9 uat-ocipa.rlpd.go.th A 10.136.27.155 S6 OCIPA (proxy ไป .144)
10 uat-wpis.rlpd.go.th A 10.136.27.155 S7 Witness Protection
11 uat-www.rlpd.go.th A 10.136.27.155 S8 เว็บไซต์กรม (public front)
12 uat-ww2-admin.rlpd.go.th A 10.136.27.155 S8 CMS admin
13 uat-ww2-api.rlpd.go.th A 10.136.27.155 S8 API engine
14 uat-webportal.rlpd.go.th A 10.136.27.155 S9 Web Portal
15 uat-openapi.rlpd.go.th A 10.136.27.155 S9 Open Data API — ⚠️ ต้องเปิด 443 จาก internet (ไม่ใช่ VPN-only) + prod openapi.rlpd.go.th ด้วย ดู §2.1/§4

Zone-file style (ก๊อปส่งได้เลย):

uat-sso        IN A 10.136.27.155
uat-s3         IN A 10.136.27.155
uat-minio      IN A 10.136.27.155
uat-lcs        IN A 10.136.27.155
uat-pjos       IN A 10.136.27.155
uat-ar-crs     IN A 10.136.27.155
uat-emediation IN A 10.136.27.155
uat-ia         IN A 10.136.27.155
uat-ocipa      IN A 10.136.27.155
uat-wpis       IN A 10.136.27.155
uat-www        IN A 10.136.27.155
uat-ww2-admin  IN A 10.136.27.155
uat-ww2-api    IN A 10.136.27.155
uat-webportal  IN A 10.136.27.155
uat-openapi    IN A 10.136.27.155

หมายเหตุ: อย่าใช้ wildcard *.rlpd.go.th (จะชนกับ prod ที่อยู่หลัง Imperva WAF เช่น www/webportal.rlpd.go.th) — ขอ record เฉพาะ 15 ตัวตามรายการนี้ปลอดภัยกว่า. จนกว่า record จะขึ้น ให้ dev แก้ /etc/hosts (10.136.27.155 uat-sso.rlpd.go.th uat-s3.rlpd.go.th ...) ไปพลางก่อน.


จัดทำ: 2026-07-14 · §5 เพิ่ม 2026-07-20 (IP UAT จริง 10.136.27.155 + verify DNS = NXDOMAIN ทั้งชุด) · อ้างอิงสำรวจ 30 มี.ค. 2569 + SSH re-check .124 14 ก.ค. 2569 (ยืนยัน UAT ใช้ Keycloak กลาง realm rlpd)