03
Phase 1: Basic • Foundations

Day 3: Keycloak Entities — Realms, Users, Credentials & Storage Boundaries

Phase 1 Index ↗
Module 03 • First Principles เริ่มต้นจากความเข้าใจระดับรากฐาน: รู้จักตัวละครหลักใน IAM

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)

❌ ฐานข้อมูลผู้ใช้แบบเดิม (Monolithic Custom DB) High Risk
  • ผู้ใช้ทุกประเภทยัดรวมในตารางเดียว แยกสิทธิ์ด้วยธง Boolean หรือ String กว้างๆ
  • การรั่วไหลเพียงจุดเดียว ทำให้ผู้โจมตีเข้าถึงรายชื่อและแฮชรหัสผ่านของทั้งองค์กร
  • นโยบายความปลอดภัย (Password Policy, กุญแจเข้ารหัส, อายุ Session) ต้องใช้เหมือนกันหมดทุกระบบ แยกปรับตามความเสี่ยงไม่ได้
✅ สถาปัตยกรรม Realm ใน Keycloak (Tenant Boundary) Isolated Tenants
  • Realm = ขอบเขตความปลอดภัยอิสระ (Security Realm / Tenant Boundary): แต่ละ Realm มี User, Roles, Clients, นโยบายรหัสผ่าน และ กุญแจเข้ารหัส (RSA Keys) เป็นของตัวเอง 100%
  • ผู้ใช้ใน Realm หนึ่งจะไม่มองเห็น ไม่ทับซ้อน และไม่สามารถข้ามไปล็อกอินในอีก Realm หนึ่งได้โดยเด็ดขาด
  • สามารถปรับ Password Policy แตกต่างกันได้ เช่น Realm พนักงานบังคับรหัสยาว 16 ตัวอักษร ส่วน Realm ลูกค้าเน้นความสะดวก
นิยามระดับรากฐาน (Root Technical Definitions): • Realm: ขอบเขตการบริหารจัดการอัตลักษณ์แบบเอกเทศ (Isolated Tenant Boundary) เปรียบเสมือน Virtual IAM Server 1 เครื่องที่มีประชากรผู้ใช้และกุญแจลับเฉพาะตัว • User Entity: ตัวตนของบุคคลหรือระบบที่สามารถยืนยันตัวตนได้ใน Realm นั้นๆ ระบุด้วย UUID ถาวร • Credential Entity: ข้อมูลลับที่ใช้พิสูจน์ตัวตน (รหัสผ่าน, กุญแจ OTP, Passkey) ซึ่งถูกจัดเก็บแยกตารางและผ่านการแฮชแบบ One-way Cryptographic Hash พร้อม Salt เสมอ

📚 ศัพท์เทคนิคและตารางโครงสร้างข้อมูลของ Keycloak ใน PostgreSQL

เมื่อ Keycloak เชื่อมต่อกับ PostgreSQL ตารางหลักที่สร้างขึ้นเพื่อรองรับ Entity มีหน้าที่ทางวิศวกรรมดังต่อไปนี้:

Entity / Table Name นิยามทางสถาปัตยกรรม ข้อมูลที่จัดเก็บ & หน้าที่หลัก ข้อกำหนดความปลอดภัย
REALM Table ตารางกำหนดขอบเขต Tenant สูงสุด เก็บการตั้งค่าระดับ Realm เช่น ชื่อ Realm, การเปิดใช้งาน SSL, SSO Session Lifespans, และสถานะ Enabled Master Realm ทำหน้าที่เป็น Super-tenant เท่านั้น
USER_ENTITY ตารางข้อมูลผู้ใช้หลัก (Core User Record) เก็บเฉพาะ Core Attributes: id (UUID), username, email, first_name, last_name, enabled, และ realm_id ห้ามเก็บรหัสผ่านในตารางนี้เด็ดขาด
USER_ATTRIBUTE ตารางจัดเก็บฟิลด์เพิ่มเติมแบบ EAV (Entity-Attribute-Value) เก็บข้อมูล Custom Profile เช่น department, employee_id, หรือ phone_number โดยผูกกับ user_id รองรับ Multivalued (1 key หลาย value)
CREDENTIAL Table ตารางจัดเก็บความลับยืนยันตัวตนของผู้ใช้ เก็บประเภท (type='password'), แฮชลับในรูปแบบ JSON: secretData (hash value, salt) และ credentialData (algorithm, iterations) ไม่เคยเก็บ Plaintext (One-way Hash เท่านั้น)
Password Hashing Algorithm ฟังก์ชันทางคณิตศาสตร์แบบทางเดียว (One-way Cryptographic Hash) Keycloak ใช้ PBKDF2-SHA512 เป็นค่าตั้งต้น (ปรับรอบ Iterations ได้) และรองรับ Argon2id สำหรับองค์กรที่ต้องการป้องกันการโจมตีด้วยชิป GPU/ASIC Salt สุ่มเฉพาะตัวทุก User ป้องกัน Rainbow Table
Required Actions ภารกิจบังคับก่อนเข้าใช้งาน (Post-Authentication Interceptors) คำสั่งบังคับให้ผู้ใช้ต้องทำก่อนได้รับ Token เช่น UPDATE_PASSWORD (บังคับเปลี่ยนรหัสผ่านครั้งแรก), VERIFY_EMAIL, หรือ CONFIGURE_TOTP บล็อก Token จนกว่าจะทำสำเร็จ
Mental Model #03 ภาพเปรียบเทียบเชิงกายภาพในชีวิตประจำวัน

The Luxury Condominium Complex: Juristic Office vs. Private Towers

เปรียบเทียบสถาปัตยกรรม Keycloak เสมือน "โครงการคอนโดมิเนียมหรูขนาดใหญ่": Master Realm คือ "สำนักงานนิติมหานคร (Juristic Office)" ที่มีกุญแจแม่บทและดูแลภาพรวมของโครงการทั้งหมด (ห้ามให้ลูกบ้านทั่วไปเข้ามาอยู่อาศัยเด็ดขาด) ขณะที่ Business Realms (เช่น app-dev, customer-portal) เปรียบเสมือน "อาคารพักอาศัยส่วนบุคคลแต่ละตึก" ที่มีประตูล็อกแยกเป็นอิสระ ลูกบ้าน (User Entity) จะมีห้องพักเป็นของตนเองในตึกนั้นๆ โดยกุญแจห้อง (Credential Entity) เป็นระบบสแกนลายนิ้วมือดิจิทัลที่ถอดรหัสย้อนกลับไม่ได้ แม้จะมีขโมยแอบบุกเข้ามาขโมยกล่องบันทึกข้อมูลกุญแจ ก็จะเห็นเพียงตัวเลขแฮชที่สับสน ไม่สามารถนำไปเปิดห้องพักของลูกบ้านได้!

POSTGRESQL RELATIONAL STORAGE: keycloak_db MASTER REALM (Management Plane) id: "master" | Purpose: Super-Admin provisioning only ⚠️ BLAST RADIUS สูงสุด ห้ามสร้าง Business Users ในนี้เด็ดขาด BUSINESS REALM: "app-dev" (Isolated Tenant) realm_id: "6a91c84f-..." | Dedicated Password Policy & RSA Keys TABLE: USER_ENTITY PK: id (UUID) username: "somchai" email: "[email protected]" enabled: true email_verified: false FK: realm_id ("app-dev") ✅ Core Profile Record (No plain passwords stored) TABLE: CREDENTIAL PK: id (UUID) FK: user_id ➔ USER_ENTITY.id type: "password" credential_data (JSON): {"algorithm":"pbkdf2-sha512","hashIterations":27500} secret_data (JSON): {"value":"Hk9x...","salt":"w9Zq..."} 🛡️ Salted One-Way Cryptographic Hash TABLE: USER_ATTRIBUTE FK: user_id name: "department" value: "Engineering" name: "employee_id" value: "EMP-4091" name: "phone_number" value: "+66819998888" 📦 Flexible Key-Value (EAV)
Case Study #03 Security Incident Post-Mortem

The $1.8M Credential Stuffing & Master Realm Contamination Incident

Direct Financial Loss
$1,850,000

ค่าชดเชยการละเมิดข้อมูลส่วนบุคคลและค่าปรับตามกฎหมายคุ้มครองข้อมูล (PDPA/GDPR)

Vulnerability Vector
Master Realm Contamination & Weak PBKDF2

สร้างผู้ใช้ลูกค้าลงใน Master Realm และใช้ค่า Password Policy ขั้นต่ำทำให้ถูก Brute-force บน GPU สำเร็จ

Architectural Takeaway
Strict Tenant Isolation & Password Policy Tuning

แยก 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 ของลูกค้าทุกองค์กรในระบบ!

Defense Argument สำหรับคุยกับทีม: "ในโลกของ Keycloak กฎเหล็กข้อที่หนึ่งคือ Master Realm มีไว้สำหรับการดูแลระบบระดับราก (Root Management Plane) เท่านั้น ห้ามสร้างบัญชีผู้ใช้ทางธุรกิจหรือลูกค้าไว้ใน Master Realm เป็นอันขาด! ทุกระบบธุรกิจต้องสร้างเป็น Dedicated Business Realm แยกขาดออกมา ซึ่งนอกจากจะจำกัด Blast Radius แล้ว ยังทำให้เราสามารถตั้ง Password Policy (เช่น บังคับความยาว 12 ตัวอักษร, กำหนดแฮช PBKDF2/Argon2id และเปิด Required Actions บังคับเปลี่ยนรหัส) ให้สอดคล้องกับมาตรฐานความปลอดภัยระดับสากลได้โดยไม่กระทบกัน!"
Hands-on Breakdown แกะโครงสร้างคำสั่ง & ลงมือสร้างจริง 3 เลเวล

Anatomy of Realm Creation, User Provisioning & Password Policies

การบริหารจัดการ Entity สามารถทำได้ผ่าน Keycloak Admin Console (Web UI) และสั่งผ่าน Keycloak Admin CLI (kcadm.sh) ซึ่งเป็นเครื่องมือหลักสำหรับ DevOps ในการทำ Automation:

LEVEL 1: Creating an Isolated Business Realm via kcadm.sh Admin CLI

เข้าสู่คอนเทนเนอร์ 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
LEVEL 2: User Provisioning with Custom Attributes & Required Actions ⚡ User & Credential Scripting

สร้างผู้ใช้ใหม่ใน 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"]'
LEVEL 3: Hardened Password Policy (Anti-Pattern vs Production-Ready) Password Policy Tuning
❌ Flawed & Dangerous Setup
  • ไม่กำหนด Password Policy ใน Realm (ยอมรับรหัสสั้น 3-4 ตัวอักษร)
  • สร้าง Business Users ปะปนใน master realm
  • ตั้งรหัสผ่านให้ผู้ใช้แบบ Permanent (ถาวร) โดยไม่บังคับเปลี่ยน
  • ปล่อยให้รอบ Iterations ของ PBKDF2 อยู่ที่ค่าต่ำมากจนเสี่ยงต่อการ Brute-force
  • ไม่อนุญาตหรือเปิดใช้ Required Actions ในการตรวจสอบอีเมล
# เสี่ยง: เสี่ยงต่อ Credential Stuffing และ Brute-force ออฟไลน์ด้วย GPU ทันทีหาก Database หลุด
✅ Production-Grade Hardened Policy
  • กำหนด Password Policy: ความยาวขั้นต่ำ 12 ตัวอักษร และมีอักขระพิเศษ
  • ปรับรอบการแฮช hashIterations=210000 หรือเลือกใช้ Argon2id
  • ตั้งประวัติรหัสผ่านป้องกันการใช้ซ้ำ: passwordHistory=5
  • แอดมินตั้งรหัสผ่านเริ่มต้นเป็น Temporary เสมอ
  • แยก Business Tenant ขาดจาก Master Realm 100%
# ปลอดภัยสูง: สอดคล้องกับมาตรฐาน NIST SP 800-63B และ ISO/IEC 27001
Simulator #03 Live Password Hashing Cost & GPU Brute-Force Sandbox

Password Hashing Algorithm & GPU Resistance Sandbox

ทดลองเลือกอัลกอริทึมการแฮชของ Keycloak, ปรับรอบการคำนวณ (Hash Iterations) และจำลองการโจมตีจากคลัสเตอร์การ์ดจอแฮกเกอร์ (GPU Cracking Rig) เพื่อดูว่าต้องใช้เวลากี่ปีในการถอดรหัสผ่าน พร้อมวัดภาระ Latency บน Server แบบ Real-time:

2. Hash Iterations (รอบการวนลูป) 27,500 รอบ
OWASP แนะนำ: PBKDF2-SHA512 อย่างน้อย 210,000 รอบ
3. ความซับซ้อนของรหัสผ่าน (Password Entropy) 8 ตัวอักษร (ง่าย)
ตัวเลข + อักษรพิมพ์เล็ก-ใหญ่ + อักขระพิเศษ
สมมติฐานอุปกรณ์แฮกเกอร์ (Attacker Hardware):
8x NVIDIA RTX 4090 Hashcat Rig (~1.2 TeraHash/s บน MD5)
Server Auth Latency
12 ms
Very Responsive
Time to Crack (Brute Force)
14.2 Hours
High Risk of Cracking
Security Evaluation Verdict VULNERABLE

รหัสผ่านความยาว 8 ตัวอักษรคู่กับจำนวนรอบที่ต่ำเกินไป สามารถถูกถอดรหัสได้ในเวลาไม่ถึงวันหากแฮกเกอร์ได้ไฟล์ Dump ของตาราง CREDENTIAL ไป!

Key takeaway: ยิ่งเพิ่ม Hash Iterations แฮกเกอร์ยิ่งเจาะยากขึ้น แต่ Server จะใช้ CPU นานขึ้นตามไปด้วย วิศวกรจึงต้องเลือกค่าที่สมดุลระหว่างความปลอดภัยและ Latency ของผู้ใช้ (แนะนำ PBKDF2 210,000+ รอบ หรือเปลี่ยนไปใช้ Argon2id)
Active Recall Comprehensive Exam 12 Production Scenarios (100% Constructive Alignment)

Day 3 Entities, Realms, Users & Storage Boundaries Exam

ครอบคลุม Realm Isolation, Database Schema, Password Hashing, Required Actions พร้อมข้อสอบ Spaced Repetition จาก Day 1 และ Day 2

Live Score
0/12 answered
0 / 12
🎯

Day 3 Practical Deliverable (ภารกิจประจำวัน)

ก่อนก้าวไปสู่ Day 4 (Clients Anatomy: Public vs Confidential Clients) คุณต้องทำภารกิจต่อไปนี้ให้สำเร็จบน Keycloak ของคุณ: