คำขอเครื่อง UAT ใหม่ (Full Stack) — Phase 2¶
เป้าหมาย: ขอ VM UAT ใหม่ 1 เครื่อง ที่รันครบทุกระบบ S1–S9 พร้อม Keycloak + MinIO + เชื่อม AD ของตัวเอง เพื่อให้ทีมทดสอบ คุม Authentication & Authorization เองได้เต็มที่ (จัดการ realm / client / role / user ได้อิสระ ไม่ต้องแตะ SSO กลาง prod)
ทำไมต้องแยก: ปัจจุบัน UAT บน
.124ใช้ Keycloak กลาง prodsso.rlpd.go.th(.127) realmrlpdร่วมกัน → แก้ 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 |
| S9 — Open 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 — ต้องเปิดทั้งคู่):
POST https://uat-sso.rlpd.go.th/realms/rlpd/protocol/openid-connect/token(grantclient_credentials) → ได้ access tokenGET https://uat-openapi.rlpd.go.th/api/dataset(headerAuthorization: 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 จาก internet →
uat-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ตรง ๆ ไม่มี prefixopen-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 จำลอง + realmrlpdModel B) รันอยู่บน dev box72.60.211.241แล้ว — Samba bind DN ตรง prod (CN=Rlpd ADmange,OU=ICT,OU=Group User,DC=rlpd,DC=go,DC=th), Keycloakvendor=ad→ drop-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(VMRLPD_UAT_Devphase2, hostnamerlpdustdevphase2, Ubuntu 24.04, บน RLPD LAN). Stack รันครบ: nginx (80/443) + Keycloak (realmrlpd) + 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)