1. Realm, User และ Credential คืออะไร? ทำไม Keycloak ถึงจัดเก็บข้อมูลแบบ Multi-Tenant?
ใน Day 1 เราติดตั้ง Keycloak และต่อฐานข้อมูล PostgreSQL สำเร็จแล้ว และใน Day 2 เราได้เห็นการส่งข้อมูลผ่าน OIDC และ PKCE แต่คำถามพื้นฐานที่สำคัญที่สุดของวิศวกรระบบคือ: "เมื่อ Keycloak ทำหน้าที่เป็นศูนย์กลางข้อมูลผู้ใช้ โครงสร้างข้อมูลข้างในเก็บอย่างไร? คำว่า Realm แปลว่าอะไร? และรหัสผ่านของผู้ใช้ถูกเก็บไว้ที่ไหน ปลอดภัยเพียงใด?"
หากเราเขียนระบบเองในอดีต เรามักสร้างฐานข้อมูลที่มีตาราง users เพียงตารางเดียว ทุกแอปในบริษัทใช้ตารางนี้ร่วมกัน
ผลที่ตามมาคือ: หากต้องการแยกผู้ใช้ของระบบลูกค้า (Customer) ออกจากระบบพนักงานภายใน (Internal Staff) หรือแยกระบบบริษัทย่อย เรามักต้องเพิ่มคอลัมน์ tenant_id หรือแยกฐานข้อมูลใหม่ทั้งยวง ซึ่งเสี่ยงต่อการที่โค้ดลืมกรอง WHERE tenant_id = ? ทำให้ข้อมูลลูกค้ารั่วไหลข้ามบริษัท (Data Leakage)
- ผู้ใช้ทุกประเภทยัดรวมในตารางเดียว แยกสิทธิ์ด้วยธง Boolean หรือ String กว้างๆ
- การรั่วไหลเพียงจุดเดียว ทำให้ผู้โจมตีเข้าถึงรายชื่อและแฮชรหัสผ่านของทั้งองค์กร
- นโยบายความปลอดภัย (Password Policy, กุญแจเข้ารหัส, อายุ Session) ต้องใช้เหมือนกันหมดทุกระบบ แยกปรับตามความเสี่ยงไม่ได้
- Realm = ขอบเขตความปลอดภัยอิสระ (Security Realm / Tenant Boundary): แต่ละ Realm มี User, Roles, Clients, นโยบายรหัสผ่าน และ กุญแจเข้ารหัส (RSA Keys) เป็นของตัวเอง 100%
- ผู้ใช้ใน Realm หนึ่งจะไม่มองเห็น ไม่ทับซ้อน และไม่สามารถข้ามไปล็อกอินในอีก Realm หนึ่งได้โดยเด็ดขาด
- สามารถปรับ Password Policy แตกต่างกันได้ เช่น Realm พนักงานบังคับรหัสยาว 16 ตัวอักษร ส่วน Realm ลูกค้าเน้นความสะดวก
📚 ศัพท์เทคนิคและตารางโครงสร้างข้อมูลของ Keycloak ใน PostgreSQL
เมื่อ Keycloak เชื่อมต่อกับ PostgreSQL ตารางหลักที่สร้างขึ้นเพื่อรองรับ Entity มีหน้าที่ทางวิศวกรรมดังต่อไปนี้:
The Luxury Condominium Complex: Juristic Office vs. Private Towers
เปรียบเทียบสถาปัตยกรรม Keycloak เสมือน "โครงการคอนโดมิเนียมหรูขนาดใหญ่":
Master Realm คือ "สำนักงานนิติมหานคร (Juristic Office)" ที่มีกุญแจแม่บทและดูแลภาพรวมของโครงการทั้งหมด (ห้ามให้ลูกบ้านทั่วไปเข้ามาอยู่อาศัยเด็ดขาด)
ขณะที่ Business Realms (เช่น app-dev, customer-portal)
เปรียบเสมือน "อาคารพักอาศัยส่วนบุคคลแต่ละตึก" ที่มีประตูล็อกแยกเป็นอิสระ
ลูกบ้าน (User Entity) จะมีห้องพักเป็นของตนเองในตึกนั้นๆ โดยกุญแจห้อง (Credential Entity)
เป็นระบบสแกนลายนิ้วมือดิจิทัลที่ถอดรหัสย้อนกลับไม่ได้ แม้จะมีขโมยแอบบุกเข้ามาขโมยกล่องบันทึกข้อมูลกุญแจ ก็จะเห็นเพียงตัวเลขแฮชที่สับสน ไม่สามารถนำไปเปิดห้องพักของลูกบ้านได้!
The $1.8M Credential Stuffing & Master Realm Contamination Incident
ค่าชดเชยการละเมิดข้อมูลส่วนบุคคลและค่าปรับตามกฎหมายคุ้มครองข้อมูล (PDPA/GDPR)
สร้างผู้ใช้ลูกค้าลงใน Master Realm และใช้ค่า Password Policy ขั้นต่ำทำให้ถูก Brute-force บน GPU สำเร็จ
แยก Business Tenant ขาดจาก Master, บังคับใช้ Required Actions และเพิ่มความแข็งแกร่งของ Hash Algorithm
สถานการณ์จริง: แพลตฟอร์มให้บริการซอฟต์แวร์ B2B SaaS แห่งหนึ่ง ได้นำ Keycloak มาติดตั้งเพื่อให้บริการยืนยันตัวตนสำหรับลูกค้าองค์กร แต่ด้วยความเร่งรีบในการขึ้นระบบ ทีมวิศวกรได้สร้างบัญชีผู้ใช้ของลูกค้าทุกคนไว้ใน master realm โดยตรงแทนที่จะสร้าง Realm แยกเฉพาะ
นอกจากนี้ ยังไม่ได้กำหนด Password Policy ใดๆ ในระบบ ทำให้ Keycloak ยอมรับรหัสผ่านที่สั้นและง่าย
ผู้โจมตีได้นำชุดข้อมูล Username/Password ที่หลุดมาจาก Dark Web มาทำ Credential Stuffing Attack บน Endpoint ล็อกอินของ Master Realm เนื่องจากผู้ใช้รายหนึ่งใช้รหัสผ่านเดียวกับอีเมลส่วนตัว ผู้โจมตีจึงล็อกอินผ่านได้สำเร็จ
และด้วยความที่บัญชีนี้อยู่ใน Master Realm จึงเกิดช่องโหว่การยกระดับสิทธิ์ (Privilege Escalation) จนผู้โจมตีสามารถมองเห็นรายชื่อ Realm ทั้งหมด, ดาวน์โหลดกุญแจเข้ารหัสลับประจำ Realm และเข้าถึงตาราง USER_ENTITY ของลูกค้าทุกองค์กรในระบบ!
Anatomy of Realm Creation, User Provisioning & Password Policies
การบริหารจัดการ Entity สามารถทำได้ผ่าน Keycloak Admin Console (Web UI) และสั่งผ่าน Keycloak Admin CLI (kcadm.sh) ซึ่งเป็นเครื่องมือหลักสำหรับ DevOps ในการทำ Automation:
เข้าสู่คอนเทนเนอร์ Keycloak แล้วใช้คำสั่ง CLI สร้าง Realm แยกต่างหากชื่อ app-dev เพื่อไม่ให้ปนเปื้อนใน Master Realm
# 1. ล็อกอินเข้าสู่ Admin CLI ผ่านบัญชี Superadmin ของ Master Realm
docker exec -it keycloak-core /opt/keycloak/bin/kcadm.sh config credentials \
--server http://localhost:8080 --realm master --user superadmin --password AdminSuperSecret2026!
# 2. สร้าง Business Realm ใหม่ชื่อ 'app-dev' ที่เปิดใช้งานทันที
docker exec -it keycloak-core /opt/keycloak/bin/kcadm.sh create realms \
-s realm=app-dev \
-s enabled=true \
-s displayName="App Development Realm"
# 3. ตรวจสอบว่า Realm ถูกสร้างและมีสถานะ Enabled
docker exec -it keycloak-core /opt/keycloak/bin/kcadm.sh get realms/app-dev --fields realm,enabled
สร้างผู้ใช้ใหม่ใน Realm app-dev พร้อมใส่ Custom Attributes ในตาราง USER_ATTRIBUTE และตั้งรหัสผ่านชั่วคราวที่บังคับให้เปลี่ยนเมื่อล็อกอินครั้งแรก
# 1. สร้างผู้ใช้ 'somchai' พร้อมข้อมูลโปรไฟล์และ Custom Attributes
docker exec -it keycloak-core /opt/keycloak/bin/kcadm.sh create users -r app-dev \
-s username=somchai \
-s email="[email protected]" \
-s firstName="Somchai" \
-s lastName="Prasert" \
-s enabled=true \
-s emailVerified=false \
-s 'attributes.department=["Engineering"]' \
-s 'attributes.employee_id=["EMP-9912"]'
# 2. ดึง User ID ของ somchai
USER_ID=$(docker exec -it keycloak-core /opt/keycloak/bin/kcadm.sh get users -r app-dev -q username=somchai --fields id --format csv | tail -n 1 | tr -d '\r')
# 3. กำหนดรหัสผ่านชั่วคราว (Temporary = true บังคับให้เปลี่ยนรหัสผ่านเมื่อล็อกอินครั้งแรก)
docker exec -it keycloak-core /opt/keycloak/bin/kcadm.sh set-password -r app-dev \
--userid $USER_ID \
--new-password "TempPass2026!" \
--temporary
# 4. เพิ่ม Required Action: บังคับให้อัปเดตโปรไฟล์และยืนยันอีเมล
docker exec -it keycloak-core /opt/keycloak/bin/kcadm.sh update users/$USER_ID -r app-dev \
-s 'requiredActions=["UPDATE_PASSWORD", "VERIFY_EMAIL"]'
- ไม่กำหนด Password Policy ใน Realm (ยอมรับรหัสสั้น 3-4 ตัวอักษร)
- สร้าง Business Users ปะปนใน
masterrealm - ตั้งรหัสผ่านให้ผู้ใช้แบบ Permanent (ถาวร) โดยไม่บังคับเปลี่ยน
- ปล่อยให้รอบ Iterations ของ PBKDF2 อยู่ที่ค่าต่ำมากจนเสี่ยงต่อการ Brute-force
- ไม่อนุญาตหรือเปิดใช้ Required Actions ในการตรวจสอบอีเมล
- กำหนด Password Policy: ความยาวขั้นต่ำ 12 ตัวอักษร และมีอักขระพิเศษ
- ปรับรอบการแฮช
hashIterations=210000หรือเลือกใช้ Argon2id - ตั้งประวัติรหัสผ่านป้องกันการใช้ซ้ำ:
passwordHistory=5 - แอดมินตั้งรหัสผ่านเริ่มต้นเป็น
Temporaryเสมอ - แยก Business Tenant ขาดจาก Master Realm 100%
Password Hashing Algorithm & GPU Resistance Sandbox
ทดลองเลือกอัลกอริทึมการแฮชของ Keycloak, ปรับรอบการคำนวณ (Hash Iterations) และจำลองการโจมตีจากคลัสเตอร์การ์ดจอแฮกเกอร์ (GPU Cracking Rig) เพื่อดูว่าต้องใช้เวลากี่ปีในการถอดรหัสผ่าน พร้อมวัดภาระ Latency บน Server แบบ Real-time:
รหัสผ่านความยาว 8 ตัวอักษรคู่กับจำนวนรอบที่ต่ำเกินไป สามารถถูกถอดรหัสได้ในเวลาไม่ถึงวันหากแฮกเกอร์ได้ไฟล์ Dump ของตาราง CREDENTIAL ไป!
Day 3 Entities, Realms, Users & Storage Boundaries Exam
ครอบคลุม Realm Isolation, Database Schema, Password Hashing, Required Actions พร้อมข้อสอบ Spaced Repetition จาก Day 1 และ Day 2
Day 3 Practical Deliverable (ภารกิจประจำวัน)
ก่อนก้าวไปสู่ Day 4 (Clients Anatomy: Public vs Confidential Clients) คุณต้องทำภารกิจต่อไปนี้ให้สำเร็จบน Keycloak ของคุณ: