1. Keycloak คืออะไรกันแน่? ทำไมโลกซอฟต์แวร์สมัยใหม่ถึงต้องใช้มัน?
ลองจินตนาการถึงโลกของการพัฒนาเว็บหรือแอปพลิเคชันในอดีต: เมื่อใดก็ตามที่คุณสร้างโปรเจกต์ใหม่ ไม่ว่าจะเป็นเว็บขายของ, ระบบหลังบ้าน หรือโมบายแอป คุณมักจะต้องเขียนโค้ดชุดเดิมซ้ำๆ เสมอ ได้แก่: หน้าฟอร์มล็อกอิน, ตารางเก็บรหัสผ่านใน Database, ฟังก์ชันแฮชรหัสผ่าน (Bcrypt/Argon2), ระบบส่งอีเมลรีเซ็ตรหัสผ่าน, ระบบจำกัดสิทธิ์ Admin/User และระบบส่ง SMS ยืนยัน OTP
ผลลัพธ์คือ ทุกทีมเขียนระบบล็อกอินของตัวเอง และมักทำผิดพลาดด้านความปลอดภัย (เช่น แฮชรหัสผ่านไม่ปลอดภัย, เซสชันหลุด, โดนแฮกฐานข้อมูลผู้ใช้) แถมเมื่อองค์กรมี 10 แอปพลิเคชัน ผู้ใช้งานคนเดิมกลับต้องมาคอยจำรหัสผ่านถึง 10 ชุด!
- แต่ละแอปพลิเคชันต้องเขียนระบบ Login และทำฐานข้อมูล User ของตัวเอง
- รหัสผ่านกระจัดกระจายหลายที่ หากแอปใดโดนเจาะ ข้อมูลผู้ใช้จะรั่วไหลทันที
- ไม่มีระบบ Single Sign-On (SSO): ผู้ใช้เข้าเว็บหนึ่งแล้ว พอจะไปอีกเว็บหนึ่งต้องพิมพ์ล็อกอินใหม่
- การเพิ่มฟีเจอร์อย่าง 2FA (OTP) หรือ Google Login ต้องเขียนโค้ดใหม่ทุกแอปพลิเคชัน
- Single Sign-On (SSO): ล็อกอินครั้งเดียวผ่านเบราว์เซอร์ สามารถเข้าถึงทุกระบบในเครือได้ทันที
- Decoupled Security: หน้าเว็บและ API ไม่ต้องแตะต้องรหัสผ่านของผู้ใช้เลย ผลักหน้าที่ตรวจสอบตัวตนให้ Keycloak ทั้งหมด
- มาตรฐานระดับโลก: รองรับ OpenID Connect (OIDC), OAuth 2.0 และ SAML 2.0 ครบถ้วนโดยไม่ต้องเขียนโค้ดเพิ่ม
- ความปลอดภัยสำเร็จรูป: มีระบบตรวจจับ Brute Force, รีเซ็ตรหัสผ่าน, 2FA/WebAuthn และ Social Login ให้พร้อมใช้ในคลิกเดียว
⚙️ กายวิภาคภายใน: Keycloak ประกอบด้วย 7 ส่วนการทำงานหลัก (Core Subsystems)
Keycloak ไม่ใช่แค่แอปจัดการ Database ธรรมดา แต่คือระบบปฏิบัติการด้าน Identity ที่มีเครื่องใน 7 ส่วนทำงานสอดประสานกัน:
The Hotel Keycard Desk vs. The Tenant Apartments
เพื่อให้เห็นภาพการทำงาน ให้เปรียบเทียบ Keycloak เสมือน "เคาน์เตอร์แผนกต้อนรับของโรงแรมหรู": ผู้เข้าพัก (User) ไม่จำเป็นต้องมีกุญแจห้องถาวร แต่จะเดินมาที่แผนกต้อนรับเพื่อแสดงบัตรประจำตัว เมื่อผ่านการตรวจสอบ เคาน์เตอร์จะยื่น "คีย์การ์ดดิจิทัล (Token)" ให้ เมื่อผู้เข้าพักจะเข้าห้องพักหรือใช้บริการฟิตเนส (Resource API) ก็เพียงแค่แตะคีย์การ์ด โดยที่ประตูห้องพักไม่จำเป็นต้องจำประวัติหรือรหัสผ่านของผู้เข้าพักเลย!
The 47-Minute "Ghost Realm" Disaster: Ephemeral Database & Agroal Pool Starvation
สูญเสียมูลค่า GMV ในช่วง 47 นาทีแรกของแคมเปญ 11.11 เนื่องจากลูกค้ากว่า 120,000 คนล็อกอินและชำระเงินไม่ได้
รันโหมด Dev ใน Production ส่งผลให้ข้อมูลหายเมื่อ Pod รีสตาร์ท และ Agroal Pool ไม่ถูกจำกัดจนสูญเสียการควบคุม
แยก State ลง PostgreSQL, ใช้คำสั่ง start --optimized, และคำนวณ Pool Size สัมพันธ์กับ Database เสมอ
สถานการณ์จริง: ในคืนเปิดตัวแคมเปญ Flash Sale ประจำปี ทีมวิศวกรของบริษัทอีคอมเมิร์ซแห่งหนึ่งได้นำ Keycloak มาใช้เป็น Identity Provider (IdP) หลัก
แต่ด้วยความคุ้นชินจากการทดสอบในเครื่อง Local ไฟล์ Kubernetes Deployment จึงถูกกำหนดคำสั่งเริ่มต้นเป็น start-dev
โดยไม่ได้ต่อ Database ภายนอก และละเลยการ Mount Persistent Volume
เมื่อทราฟฟิกลูกค้าหลั่งไหลเข้ามามากกว่า 14,000 Requests Per Minute (RPM) ในนาทีแรก หน่วยความจำ JVM พุ่งแตะ 98% จนถูก Kubernetes OOMKilled รีสตาร์ท Pod อัตโนมัติ ผลลัพธ์ที่ตามมาคือ Realm Configuration ทั้งหมด, ข้อมูล Active Sessions และกุญแจ Public Key Pair (JWKS) สูญหายไปทั้งหมดทันที!
เมื่อ Pod บูตขึ้นมาใหม่ Keycloak เข้าสู่หน้าจอ Initial Setup เสมือนเพิ่งติดตั้งครั้งแรก ส่งผลให้ Access Token เดิมนับแสนใบถูก Microservices เบื้องหลังปฏิเสธ (Signature Mismatch) ทันที ส่งผลให้ระบบล่มสนิทเป็นเวลากว่า 47 นาทีกว่าจะกู้คืนข้อมูลสำรองได้
start-dev มีไว้สำหรับการเขียนโค้ดบนเครื่อง Dev เท่านั้น เพราะจะผ่อนปรนความปลอดภัย (Insecure HTTP), ไม่แคช Indexing และใช้ฐานข้อมูลชั่วคราว การนำเข้า Production ต้องปฏิบัติตามหลักการ Decoupled Persistence: แยกข้อมูลลง PostgreSQL, คำนวณ Agroal Connection Pool ให้แม่นยำ และทำการ Pre-build ด้วยคำสั่ง kc.sh build ก่อนเสมอ!"
Anatomy of Keycloak Configuration & Health Probes
ตั้งแต่ Keycloak ยุค Quarkus เป็นต้นมา ตัวแปร Configuration ทั้งหมดจะขึ้นต้นด้วยพรีฟิกซ์ KC_* เสมอ
โดยการตั้งค่าที่ถูกต้องต้องควบคุมทั้ง Database Connection, Reverse Proxy Forwarding, และ Health Metrics:
คำสั่งบรรทัดเดียวสำหรับทดลองสำรวจ Admin Console ชั่วคราว (ข้อมูลทั้งหมดจะสูญหายทันทีที่ Container ถูกปิด)
# รันโหมด Dev ชั่วคราว (ใช้ In-memory H2 DB ข้อมูลจะสูญหายทันทีที่ Stop)
docker run --name keycloak-sandbox -p 8080:8080 \
-e KEYCLOAK_ADMIN=superadmin \
-e KEYCLOAK_ADMIN_PASSWORD=AdminSuperSecret2026! \
quay.io/keycloak/keycloak:24.0.5 start-dev
โครงสร้างแยก PostgreSQL Database พร้อม Persistent Volume Mount, Healthcheck, และการเปิด Health Endpoints
version: '3.8'
services:
postgres:
image: postgres:16-alpine
container_name: keycloak-postgres
environment:
POSTGRES_DB: keycloak_db
POSTGRES_USER: kc_db_user
POSTGRES_PASSWORD: DB_Secret_SecurePassword_2026!
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- kc-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U kc_db_user -d keycloak_db"]
interval: 5s
timeout: 5s
retries: 5
keycloak:
image: quay.io/keycloak/keycloak:24.0.5
container_name: keycloak-core
command: start-dev
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak_db
KC_DB_USERNAME: kc_db_user
KC_DB_PASSWORD: DB_Secret_SecurePassword_2026!
KC_DB_POOL_MIN_SIZE: 10
KC_DB_POOL_MAX_SIZE: 30
KEYCLOAK_ADMIN: superadmin
KEYCLOAK_ADMIN_PASSWORD: AdminSuperSecret2026!
KC_HEALTH_ENABLED: "true"
KC_METRICS_ENABLED: "true"
KC_HTTP_ENABLED: "true"
ports:
- "8080:8080"
- "9000:9000"
depends_on:
postgres:
condition: service_healthy
networks:
- kc-network
volumes:
postgres_data:
driver: local
networks:
kc-network:
driver: bridge
- ใช้คำสั่ง
start-devในระบบ Production - สร้าง Business Users และ Clients ปนเปื้อนลงใน
masterrealm - ไม่จำกัด
KC_DB_POOL_MAX_SIZEทำให้ connection พุ่งชนเพดาน PostgreSQL - เขียนรหัสผ่านใหม่แบบ Plaintext ทับลงในตาราง
CREDENTIALตอนลืมรหัสผ่าน - ไม่เปิด
KC_PROXY_HEADERSทำให้ Redirect URI กลายเป็น http ไม่ปลอดภัย
- Pre-build ด้วย
kc.sh buildแล้วรันด้วยstart --optimized - สร้าง Business Realm (เช่น
app-dev) แยกขาดจาก Master Realm อย่างเด็ดขาด - คำนวณ Pool:
(Replicas × KC_DB_POOL_MAX_SIZE) < max_connections - กู้คืนรหัสผ่านด้วย CLI
kcadm.shหรือตัวแปร Bootstrap Admin ทางการ - ตั้งค่า
KC_PROXY_HEADERS=xforwardedคู่กับ Reverse Proxy ที่รองรับ TLS
Keycloak Agroal Pool & Worker Contention Simulator
ทดลองปรับแต่งตัวแปรเพื่อดูว่าเมื่อมีคำขอ Login เข้ามาพร้อมกัน หากกำหนดขนาด Database Pool หรือสัดส่วน Node ไม่สัมพันธ์กับ PostgreSQL ขีดจำกัดของระบบจะพังทลายที่จุดใดแบบ Real-time
Total Max Pool = Pods × KC_DB_POOL_MAX_SIZE. ต้องมีขนาดน้อยกว่า max_connections ของ PostgreSQL โดยเหลือเผื่อไว้ 15–20 slots สำหรับ Superuser และ Backup เสมอ!
Day 1 Architecture & Engineering Mastery Exam
ครอบคลุมนิยาม Keycloak, 7 Core Subsystems, Quarkus Runtime, Agroal Pool, Liquibase Locks และ Master Isolation
Day 1 Practical Deliverable (ภารกิจประจำวัน)
ก่อนก้าวไปสู่ Day 2 (The Core OIDC Protocol & Authorization Code with PKCE) คุณต้องทำภารกิจต่อไปนี้ให้สำเร็จบนเครื่องของคุณ: