Keycloak: ทำ SSO ล็อกอินครั้งเดียวทุกแอปขององค์กรด้วย Docker

ติดตั้ง Keycloak 26 โหมด production ด้วย Docker Compose คู่กับ PostgreSQL หลัง HTTPS สร้างผู้ดูแลถาวร แยก realm พนักงานจาก master และสร้าง client แรกสำหรับ SSO

โดย ทีมงาน THAI DATA CLOUD อัปเดต อ่าน 11 นาที

แชร์FacebookXLINELinkedIn
Keycloak — Keycloak: ทำ SSO ล็อกอินครั้งเดียวทุกแอปขององค์กรด้วย Docker
Keycloak: ทำ SSO ล็อกอินครั้งเดียวทุกแอปขององค์กรด้วย Docker

คำตอบสั้น ๆ: ติดตั้ง Keycloak 26 โหมด production ด้วย Docker Compose คู่กับ PostgreSQL หลัง HTTPS สร้างผู้ดูแลถาวร แยก realm พนักงานจาก master และสร้าง client แรกสำหรับ SSO

คู่มือนี้อธิบาย Keycloak ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย

Keycloak คือระบบจัดการตัวตนและ Single Sign-On (SSO) แบบโอเพนซอร์ส ให้พนักงานล็อกอินครั้งเดียวแล้วเข้าได้ทุกแอปที่เชื่อมไว้ผ่านมาตรฐาน OpenID Connect หรือ SAML 2.0 รองรับการยืนยันตัวตนหลายขั้น (OTP) การดึงผู้ใช้จาก LDAP หรือ Active Directory และการปิดบัญชีพนักงานที่ลาออกจากจุดเดียว เหมาะกับองค์กรที่มีแอปภายในหลายตัว เช่น Git Server, Wiki, Grafana และระบบ CI

เมื่อทำตามคู่มือนี้จบ คุณจะมี Keycloak 26 ในโหมด production คู่กับ PostgreSQL อยู่หลัง HTTPS ใช้บัญชีผู้ดูแลถาวรแทนบัญชีชั่วคราวตอนติดตั้ง มี realm สำหรับพนักงานแยกจาก realm master และมี client แรกพร้อมเชื่อมกับแอป

สิ่งที่ต้องเตรียม

  • Cloud VPS ที่ใช้ Ubuntu 24.04 พร้อม Docker Engine และ Compose plugin ขนาดเริ่มต้นราว 2 vCPU / RAM 4 GB เพราะรันบน Java เป็นค่าประมาณ ปรับตามจำนวนผู้ใช้และการล็อกอินพร้อมกัน
  • ซับโดเมน เช่น sso.example.com และ Nginx Proxy Manager พร้อมเครือข่าย proxy
  • บัญชี SMTP สำหรับอีเมลยืนยันและลืมรหัสผ่าน
  • รายชื่อแอปที่จะเชื่อม SSO และ URL callback ของแต่ละแอป

ก่อนเริ่มควรเข้าใจสองคำ realm คือพื้นที่แยกกันของผู้ใช้และการตั้งค่า ส่วน client คือแอปแต่ละตัวที่ขอให้ระบบยืนยันตัวตนแทน

แผนภาพพนักงานล็อกอินผ่าน Keycloak หลัง Nginx Proxy Manager แล้วใช้ token เข้า Gitea BookStack และ Grafana
แอปส่งผู้ใช้มาล็อกอินที่ sso.example.com แล้วรับ token กลับไปตามมาตรฐาน OpenID Connect

ขั้นตอนที่ 1: เตรียม .env และรหัสผ่าน

sudo install -d -o $USER /opt/sso
cd /opt/sso
cat > .env <<EOF
DB_PASSWORD=$(openssl rand -hex 24)
KC_BOOTSTRAP_ADMIN_USERNAME=tempadmin
KC_BOOTSTRAP_ADMIN_PASSWORD=$(openssl rand -base64 18)
EOF
chmod 600 .env
cat .env

บัญชี tempadmin เป็นบัญชีชั่วคราวสำหรับเข้าครั้งแรกเท่านั้น ระบบจะแสดงคำเตือนจนกว่าคุณจะสร้างผู้ดูแลถาวรและลบบัญชีนี้

ขั้นตอนที่ 2: เขียน compose.yaml ในโหมด production

services:
  db:
    image: postgres:17-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: sso
      POSTGRES_USER: sso
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - ./postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U sso -d sso"]
      interval: 10s
      retries: 5

  keycloak:
    image: quay.io/keycloak/keycloak:26.8
    container_name: keycloak
    command: start
    restart: unless-stopped
    environment:
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://db:5432/sso
      KC_DB_USERNAME: sso
      KC_DB_PASSWORD: ${DB_PASSWORD}
      KC_HOSTNAME: https://sso.example.com
      KC_HTTP_ENABLED: "true"
      KC_PROXY_HEADERS: xforwarded
      KC_HEALTH_ENABLED: "true"
      KC_BOOTSTRAP_ADMIN_USERNAME: ${KC_BOOTSTRAP_ADMIN_USERNAME}
      KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_BOOTSTRAP_ADMIN_PASSWORD}
    depends_on:
      db:
        condition: service_healthy
    networks:
      - default
      - proxy

networks:
  proxy:
    external: true
  • command: start คือโหมด production ต่างจาก start-dev ที่ใช้ฐานข้อมูลในตัวและไม่ควรใช้จริง
  • KC_HOSTNAME ใส่เป็น URL เต็ม ทำให้ลิงก์ในอีเมลและค่า issuer ของ token ถูกต้องเสมอ
  • KC_HTTP_ENABLED และ KC_PROXY_HEADERS จำเป็นเมื่อ HTTPS สิ้นสุดที่ reverse proxy แล้วส่งต่อเป็น HTTP พร้อม header X-Forwarded-*
  • พอร์ต 9000 สำหรับ health และ metrics ไม่ได้ publish และไม่ควรเปิดผ่าน proxy
docker compose up -d
docker compose logs -f keycloak

การเริ่มครั้งแรกใช้เวลาราว 1–2 นาที เพราะระบบ build การตั้งค่าและสร้างตารางในฐานข้อมูล รอจนล็อกแสดงว่าเริ่มทำงานในโหมด production แล้ว

ขั้นตอนที่ 3: เปิด HTTPS และจำกัดหน้าแอดมิน

ใน Nginx Proxy Manager เพิ่ม Proxy Host กรอก Domain Names sso.example.com, Forward Hostname keycloak, Forward Port 8080 เปิด Block Common Exploits ขอใบรับรองพร้อม Force SSL และ HSTS

เส้นทาง /realms/ และ /resources/ ต้องเข้าถึงได้จากทุกที่ เพราะผู้ใช้ล็อกอินผ่านเส้นทางเหล่านี้ แต่ /admin/ ควรจำกัดเฉพาะ IP สำนักงานหรือ VPN ในแท็บ Custom Locations กด Add Location ใส่ location /admin/ ส่งต่อไปที่ keycloak พอร์ต 8080 แล้วใส่คำสั่งนี้ในช่องคอนฟิกเพิ่มเติมของ location นั้น

allow 198.51.100.0/24;
deny all;

ขั้นตอนที่ 4: สร้างผู้ดูแลถาวรแทนบัญชีชั่วคราว

เปิด https://sso.example.com/admin/ ล็อกอินด้วย tempadmin แล้วทำตามลำดับใน realm master

  1. ไปที่ Users → Add user ใส่ Username เช่น it-admin และ Email แล้วกด Create
  2. แท็บ Credentials → Set password ตั้งรหัสผ่านยาว ปิดตัวเลือก Temporary
  3. แท็บ Role mapping → Assign role เลือกบทบาท realm ชื่อ admin แล้วกด Assign
  4. ในแท็บ Details ของผู้ใช้ เพิ่ม Required user actions เป็น Configure OTP เพื่อบังคับตั้ง OTP ตอนล็อกอินครั้งแรก
  5. ล็อกเอาต์ ล็อกอินด้วย it-admin แล้วลบผู้ใช้ tempadmin

เมื่อเสร็จแล้วลบสองบรรทัด KC_BOOTSTRAP_ADMIN_* ออกจาก .env และ compose.yaml แล้วรัน docker compose up -d เพื่อไม่ให้รหัสผ่านชั่วคราวค้างอยู่ในเครื่อง

ขั้นตอนที่ 5: สร้าง realm สำหรับพนักงาน

ใช้ realm master สำหรับผู้ดูแล Keycloak เท่านั้น ห้ามเพิ่มพนักงานทั่วไปหรือเชื่อมแอปไว้ในนั้น กดเมนูเลือก realm มุมซ้ายบน (บางรุ่นอยู่ในเมนู Manage realms) แล้วเลือก Create realm ตั้ง Realm name เช่น example แล้วกด Create

ใน realm ใหม่ ไปที่ Realm settings แท็บ Email เพื่อใส่ SMTP แท็บ Login เปิด Forgot password และ Login with email ส่วน User registration ปล่อยปิดไว้ แล้วเพิ่มพนักงานใน Users พร้อมจัดกลุ่มใน Groups ตามแผนก หรือเชื่อม Active Directory ผ่าน User federation

ตารางเปรียบเทียบการใช้ realm master กับ realm ของพนักงานใน Keycloak ด้านผู้ใช้ แอป และความเสี่ยง
แยก realm ตั้งแต่วันแรก ย้ายผู้ใช้ภายหลังยุ่งยากกว่ามาก

ขั้นตอนที่ 6: สร้าง client แรกให้แอปล็อกอินผ่าน SSO

ตัวอย่างนี้เชื่อม Gitea ใน realm example ไปที่ Clients → Create client

  • General settings: Client type OpenID Connect, Client ID gitea
  • Capability config: เปิด Client authentication และเลือก Standard flow
  • Login settings: Valid redirect URIs เป็น https://git.example.com/user/oauth2/keycloak/callback
ภาพจำลองหน้า Create client ใน Keycloak Admin Console ตั้ง Client ID gitea เปิด Client authentication และใส่ redirect URI
Valid redirect URIs ต้องตรงกับ callback ของแอปทุกตัวอักษร (ภาพจำลอง)

กด Save แล้วคัดลอก Client secret จากแท็บ Credentials ฝั่งแอปใช้ค่า discovery URL https://sso.example.com/realms/example/.well-known/openid-configuration คู่กับ Client ID และ secret ตรวจความถูกต้องได้ด้วยคำสั่ง curl -s ไปที่ URL นี้ ค่า issuer ต้องเป็น https://sso.example.com/realms/example

สำรองฐานข้อมูลทุกวันด้วย docker compose exec -T db pg_dump -U sso -Fc sso | sudo tee /var/backups/sso-$(date +%F).dump > /dev/null แล้วส่งออกนอกเครื่อง และอัปเดตโดยเปลี่ยนแท็กเป็นรุ่นใหม่อย่างตั้งใจ อ่าน Upgrading Guide แล้วรัน docker compose pull && docker compose up -d ระบบจะย้ายโครงสร้างฐานข้อมูลให้เองตอนเริ่ม

ปัญหาที่พบบ่อยเกี่ยวกับ Keycloak

เปิดหน้าล็อกอินแล้วขึ้นข้อความ HTTPS required?

ระบบคิดว่าคำขอมาทาง HTTP เพราะไม่ได้รับ header X-Forwarded-Proto ที่ถูกต้อง ตรวจว่าเปิดผ่าน https://sso.example.com ไม่ใช่ IP หรือพอร์ต 8080 ตรง และตั้ง KC_PROXY_HEADERS: xforwarded ไว้แล้ว

แอปฟ้อง Invalid parameter: redirect_uri?

URL ที่แอปส่งมาไม่ตรงกับ Valid redirect URIs ของ client ทุกตัวอักษร รวมถึง http กับ https และ / ท้าย URL ดู URL จริงจากแถบที่อยู่ของเบราว์เซอร์ตอนเกิดข้อผิดพลาด แล้วเพิ่มให้ตรง หลีกเลี่ยงการใช้ * แบบกว้างในงานจริง

ลิงก์ในอีเมลหรือค่า issuer เป็น http://keycloak:8080?

KC_HOSTNAME ไม่ได้ตั้งเป็น URL เต็ม ระบบจึงสร้าง URL จากคำขอภายใน แก้ให้เป็น https://sso.example.com แล้วรัน docker compose up -d แอปที่เชื่อมไว้แล้วอาจต้องล็อกอินใหม่หนึ่งครั้ง

ควรเพิ่มผู้ใช้และแอปใน realm master ได้ไหม?

ไม่ควร realm master มีสิทธิ์จัดการทุก realm ถ้าบัญชีพนักงานธรรมดาอยู่ในนั้น ความผิดพลาดของการตั้งสิทธิ์อาจกลายเป็นสิทธิ์ผู้ดูแลทั้งระบบ แยก realm ของพนักงานตามขั้นตอนที่ 5 ตามแนวทางใน Configuring Keycloak for production และ Using a reverse proxy

ผลคำสั่ง docker compose ps ของ Keycloak และ PostgreSQL และ curl อ่านค่า issuer จาก openid-configuration ของ realm example
issuer ต้องเป็น https และเป็นโดเมนจริง ถ้าเห็น http หรือ :8080 ให้ตรวจ KC_HOSTNAME

ต้องการวาง SSO ให้แอปภายในหลายตัวพร้อมระบบสำรองที่เชื่อถือได้ ดู Cloud VPS App Plus หรือ ติดต่อทีมงาน THAI DATA CLOUD เพื่อช่วยออกแบบโครงสร้างการยืนยันตัวตนขององค์กร

อ่านเพิ่มเติมเกี่ยวกับ Keycloak

แชร์FacebookXLINELinkedIn

มีคำถามเรื่องบริการ? ติดต่อทีมงาน