Initial Guide — Entra External ID (CIAM): จาก tenant เปล่า ถึง state ปัจจุบัน

จุดประสงค์: หลัง provision tenant Microsoft Entra External ID แล้ว (หน้า App registrations ยังว่าง) ต้อง config อะไรต่อ เพื่อให้ SuperApp (shell, Sentinel Gateway, UserService, NotificationService, admin portal) login / sign-up / ออก token ได้เหมือน state ปัจจุบัน ตรวจสอบกับของจริงเมื่อ: 2026-09-25

อ่านคู่กับ initial-guide-apim.md และ initial-guide-aks.md

การอ่าน tag ท้าย bullet:

⚠️ ข้อจำกัดของข้อมูล


0. ขอบเขต


1. Prerequisite นอก Entra (ขาดอันใดอันหนึ่ง = login / sign-up ตาย)

[!IMPORTANT] ต้องครบทั้ง 4 ข้อก่อนเริ่ม §4 — ขาดข้อใดข้อหนึ่ง login / sign-up ของ env นั้นใช้ไม่ได้

  1. สิทธิ์คนทำ = Global Administrator ของ CIAM tenant

    • ถ้าไม่ได้ Global Admin ต้องมีครบ 3 role: Application Administrator + External ID User Flow Administrator + Authentication Extensibility Administrator
    • ปัจจุบันมี Global Admin 7 คน: guest *_exim.go.th#EXT# 6 คน + o-parichat@eximcustnonprd.onmicrosoft.com [live]
  2. Endpoint ของ custom extension ต้องเข้าได้จาก internet และ TLS ต้อง valid

    • Entra เรียก endpoint เหล่านี้จาก cloud ของ Microsoft ไม่ได้เรียกจากใน VNet
    • ผลทดสอบ POST จากเครื่อง corp วันที่ 2026-09-25 (TLS verify ผ่านทุกตัว) [live]:
    Env Endpoint ผล
    dev …/notification-api/…/auth-extension/email-otp-send ✅ 200
    uat …/uat-notification-api/…/auth-extension/email-otp-send ✅ 200
    sit …/sit-notification-api/…/auth-extension/email-otp-send ❌ 404
    sit …/sit-userservice-api/api/user-service/v1/token-issuance/on-token-issuance-start ❌ 404
    • ยังไม่ได้ทดสอบจาก internet นอก corp [assume]
    • controller ของ endpoint ทั้งหมดในตารางเป็น [AllowAnonymous]: app ไม่ได้ validate token ที่ Entra ส่งมาเอง [repo]
  3. Service ต้องรันอยู่ก่อน bind extension

    • NotificationService: ส่ง OTP
    • UserService: token issuance, native auth sign-up, Graph
    • Sentinel Gateway: OIDC redirect
    • ถ้า NotificationService ล่ม Entra จะส่ง OTP ไม่ได้ ทำให้ sign-up / login ด้วย OTP ใช้ไม่ได้ทั้ง env [assume]
  4. Key Vault sua-azure-nonprd-kv + CSI SecretProviderClass ต้องมี client secret ของแต่ละ env (ชื่อ secret ดูใน §9) [repo]

    • config ใน cloud ตั้ง KeyVault.VaultUri: "" จึงไม่ได้ใช้ Key Vault provider ใน app; secret เข้ามาเป็น env var ผ่าน CSI เท่านั้น
    • ถ้าเปิด Key Vault provider ใน app ชื่อ secret แบบ Dev--TenantRegistry--… จะ map ไปผิด key [repo]

2. ค่าปัจจุบัน (ใช้เป็น target ตอน config)

2.1 Tenant-level

หัวข้อ ค่าจริง tag
⚠️ Domain ⚠️ eximcustnonprd.onmicrosoft.com ตัวเดียว (ไม่มี custom domain) [live]
Conditional Access ไม่มี policy [live]
Company branding default layout, header/footer ซ่อน, hideAccountResetCredentials: true [live]
Email OTP authentication method ต้องเปิด (user flow ทุกตัวใช้ EmailOtpSignup-OAUTH) [assume] — อ่าน policy ไม่ได้
Social IdP (Google/Facebook) ไม่ได้ใช้ใน user flow [live] (ระดับ flow)

[!WARNING] Tenant นี้ไม่มี custom domain: ทุกอย่างผูกกับ eximcustnonprd.onmicrosoft.com / eximcustnonprd.ciamlogin.com

2.2 ชุด app ต่อ environment

Env Customer app (clientId) Client secret (ชื่อ / หมดอายุ) User flow OnOtpSend extension OnTokenIssuanceStart AuthExtension-API app
DEV IDP_Super_APP dba195d4-84a6-43b8-bbc4-fc03b0c068e8 UserService-Local-Dev-v2 / 2027-04-07 SuperAPP_Flow Super APP Custom Email OTP ไม่มี SuperApp-AuthExtension-API 34948d2a…
SIT SuperApp-SIT-Customer-CIAM-V2 a4cef28a-2198-4e72-bed7-92e5e00f2dbf SIT-ClientSecret-2026 / 2028-04-27 SIT_SuperAPP_Flow_V2 SIT-EmailOtpSend SIT-TokenIssuanceStart SuperApp-AuthExtension-API 1e91c637…
UAT SuperApp-UAT-Customer-CIAM cf5521c5-3fbf-4f76-b047-1af5bafe51cc UAT-ClientSecret / 2028-07-14 User_Flow_V2 UAT-EmailOtpSend ไม่มี SuperApp-UAT-AuthExtension-API 836f359a…

3. ขั้นตอน config (ตามลำดับที่ต้องทำ)

ลำดับสำคัญ: app → AuthExtension-API app → custom extension → user flow → bind → wiring → test ทำซ้ำ §4–§7 หนึ่งรอบต่อ env (dev / sit / uat) — ใช้ Backend_Iac/scripts/create-sit-app-registration.ps1 เป็น reference สำหรับ clone ได้ แต่ ตรวจค่ากับ §4–§7 นี้ เพราะ script ต่างจาก live บางจุด (เช่น resourceId ของ extension) [repo]


4. Customer app registration (1 ตัวต่อ env)

Portal: Entra admin center → Applications → App registrations → New registration


5. AuthExtension-API app (1 ตัวต่อ env) — ตัวตนที่ Entra ใช้ยิงเข้า custom extension

Portal: เกิดอัตโนมัติตอนสร้าง custom authentication extension (§6) แล้วเลือก "Create new app registration" หรือสร้างเองก่อน


6. Custom authentication extensions

Portal: External Identities → Custom authentication extensions → Create a custom extension

6.1 OnOtpSend (ส่ง OTP ผ่าน NotificationService แทน email ของ Microsoft) — ทุก env

Env Display name Target URL Auth resource
dev Super APP Custom Email OTP https://gateway-dev.exim.go.th/notification-api/api/notification-service/v1/auth-extension/email-otp-send api://gateway-dev.exim.go.th/34948d2a…
sit SIT-EmailOtpSend https://gateway-dev.exim.go.th/sit-notification-api/api/notification-service/v1/auth-extension/email-otp-send api://gateway-dev.exim.go.th/1e91c637…
uat UAT-EmailOtpSend https://gateway-dev.exim.go.th/uat-notification-api/api/notification-service/v1/auth-extension/email-otp-send api://gateway-dev.exim.go.th/836f359a…

6.2 OnTokenIssuanceStart (custom claim UserProfile) — มีแค่ SIT


7. User flow (1 ตัวต่อ env)

Portal: External Identities → User flows → New user flow


8. Workforce app (SuperApp 6b0a2469… ใน tenant exim.go.th) — สำหรับ admin portal


9. Wiring ฝั่ง app (หลัง Entra พร้อม)

Env KV secret env var
dev Dev--TenantRegistry--Tenants--customer--AzureAd--ClientSecret, Dev--TenantRegistry--Tenants--employee--AzureAd--ClientSecret TenantRegistry__Tenants__{customer,employee}__AzureAd__ClientSecret
sit Sit--TenantRegistry--Tenants--{customer,employee}--AzureAd--ClientSecret เหมือนกัน
uat Uat--TenantRegistry--Tenants--{customer,employee}--AzureAd--ClientSecret เหมือนกัน

10. Smoke test

export AZURE_CONFIG_DIR=~/.azure-ciam
az login --tenant e18959dc-d97f-426c-b40e-09799337e28f --allow-no-subscriptions
az rest --url "https://graph.microsoft.com/v1.0/applications?\$select=displayName,appId,isFallbackPublicClient,nativeAuthenticationApisEnabled"
az rest --url "https://graph.microsoft.com/beta/identity/authenticationEventsFlows"
az rest --url "https://graph.microsoft.com/beta/identity/customAuthenticationExtensions"
az rest --url "https://graph.microsoft.com/beta/identity/authenticationEventListeners"

11. สิ่งที่พบ / ควรเก็บกวาด (บันทึกไว้ ยังไม่ได้แก้)