Chuyển đến nội dung chính

Bài 11: Multi-Factor Authentication - OTP, WebAuthn và Passkeys

Cấu hình Two-Factor Authentication với TOTP/HOTP (Google Authenticator, FreeOTP), OTP Policy settings, Recovery Codes. WebAuthn setup (FIDO2 security keys), WebAuthn Passwordless Policy. Passkeys integration (conditional và modal UI), đăng ký Passkeys qua AIA, Kerberos authentication và X.509 client certificate authentication.

🔒 DevSecOps — Bài 11 Bài 11: Multi-Factor Authentication - OTP, WebAuthn và Passkeys

Keycloak từ Cơ bản đến Nâng cao

Phần 3: Authentication, MFA và Identity Brokering

xdev.asia

1. OTP Authentication — TOTP và HOTP

OTP (One-Time Password) là phương thức MFA phổ biến nhất. Keycloak hỗ trợ hai loại:

LoạiMô tảThuật toán
TOTP (Time-based)Mã OTP thay đổi theo thời gian (mỗi 30s)RFC 6238
HOTP (HMAC-based)Mã OTP thay đổi theo counterRFC 4226

TOTP được khuyến khích vì bảo mật hơn — mã tự hết hạn theo thời gian. HOTP chỉ dùng khi thiết bị không hỗ trợ đồng hồ chính xác.

1.1 OTP Policy Configuration

Cấu hình OTP Policy tại Authentication → Policies → OTP Policy:

SettingMô tảGiá trị mặc địnhKhuyến nghị
OTP TypeTOTP hoặc HOTPtotptotp
OTP Hash AlgorithmThuật toán hashSHA1SHA256 hoặc SHA512
Number of DigitsSố chữ số OTP66 (tương thích tốt nhất)
Look Ahead WindowSố mã trước/sau được chấp nhận11 — tăng nếu user hay bị lệch time
OTP Token PeriodThời gian sống mỗi mã (giây) — chỉ TOTP3030
Initial CounterCounter khởi đầu — chỉ HOTP00
Supported ApplicationsApps hiển thị trong hướng dẫn setupFreeOTP, Google AuthenticatorThêm các app khác nếu cần

1.2 Setup OTP với Google Authenticator / FreeOTP

Bước 1: Bật OTP trong Authentication Flow

Mặc định, Browser Flow đã có Browser - Conditional OTP sub-flow. OTP chỉ yêu cầu khi user đã setup OTP credential. Để bắt buộc tất cả users phải setup OTP:

  1. Vào Authentication → Required Actions
  2. Tìm Configure OTP
  3. Bật Default Action: On — tất cả users mới phải setup OTP
  4. Hoặc bật Required ở column "Set as default action" để enforce cho existing users

Bước 2: User đăng ký OTP

Khi user đăng nhập lần đầu (hoặc sau khi admin bật Required Action):

  1. Keycloak hiển thị trang "Mobile Authenticator Setup"
  2. User mở app Google Authenticator hoặc FreeOTP
  3. Scan QR code hoặc nhập manual key
  4. Nhập mã OTP xác nhận từ app
  5. OTP credential được lưu cho user

Bước 3: Xác thực OTP

Từ lần đăng nhập tiếp theo, sau khi nhập username/password, user phải nhập mã OTP từ app.

1.3 Quản lý OTP Credentials

# Admin xem OTP credentials của user
curl -s -X GET \
  "https://keycloak.example.com/admin/realms/myrealm/users/$USER_ID/credentials" \
  -H "Authorization: Bearer $ADMIN_TOKEN" | \
  jq '.[] | select(.type=="otp")'

# Admin xóa OTP credential (force user setup lại)
curl -X DELETE \
  "https://keycloak.example.com/admin/realms/myrealm/users/$USER_ID/credentials/$CREDENTIAL_ID" \
  -H "Authorization: Bearer $ADMIN_TOKEN"

# Admin trigger Required Action cho user cụ thể
curl -X PUT \
  "https://keycloak.example.com/admin/realms/myrealm/users/$USER_ID" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "requiredActions": ["CONFIGURE_TOTP"]
  }'

2. Recovery Codes

Recovery Codes cho phép user khôi phục truy cập khi mất thiết bị OTP.

2.1 Bật Recovery Codes

  1. Vào Authentication → Required Actions
  2. Tìm Recovery Authentication Codes (nếu chưa có, cần register)
  3. Bật Default Action hoặc Enabled

Enforce Recovery Codes sau OTP setup:

Để bắt buộc user tạo recovery codes ngay sau khi setup OTP, cấu hình Required Actions theo thứ tự:

  1. CONFIGURE_TOTP — Setup OTP trước
  2. CONFIGURE_RECOVERY_AUTHN_CODES — Tạo recovery codes sau

2.2 Sử dụng Recovery Codes

Khi user mất thiết bị OTP:

  1. Tại màn hình nhập OTP, click "Try another way"
  2. Chọn "Recovery Code"
  3. Nhập 1 trong các recovery codes đã lưu
  4. Mỗi code chỉ dùng được 1 lần
  5. Sau khi dùng hết codes, cần generate lại

3. WebAuthn (FIDO2) — Security Keys

WebAuthn cho phép xác thực bằng hardware security keys (YubiKey, Google Titan) hoặc platform authenticators (Touch ID, Windows Hello).

3.1 Setup WebAuthn trong Browser Flow

Bước 1: Thêm WebAuthn vào Authentication Flow

  1. Duplicate Browser Flow → Browser with WebAuthn
  2. Trong sub-flow Forms, thêm WebAuthn Authenticator
  3. Cấu trúc flow:
    Browser with WebAuthn
    ├── Cookie (Alternative)
    └── Forms (Alternative)
        ├── Username Password Form (Required)
        └── WebAuthn MFA (Conditional)
            ├── Condition - User Configured (Required)
            └── WebAuthn Authenticator (Required)
  4. Bind flow: Authentication → Bindings → Browser Flow = Browser with WebAuthn

Bước 2: Bật Required Action

  1. Vào Authentication → Required Actions
  2. Tìm WebAuthn Register → bật Default Action
  3. Users mới sẽ được yêu cầu đăng ký security key

3.2 WebAuthn Policy Configuration

Cấu hình tại Authentication → Policies → WebAuthn Policy:

SettingMô tảGiá trị
Relying Party Entity NameTên hiển thị cho userKeycloak hoặc tên công ty
Signature AlgorithmsThuật toán chữ kýES256 (khuyến nghị), RS256
Relying Party IDDomain của Keycloakkeycloak.example.com (hoặc để trống = auto)
Attestation Conveyance PreferenceYêu cầu attestation từ keynot specified hoặc direct
Authenticator AttachmentLoại authenticatornot specified (chấp nhận cả USB key và platform)
Require Resident KeyKey phải lưu trên devicenot specified
User Verification RequirementYêu cầu xác thực user trên devicenot specified hoặc required
Create TimeoutTimeout khi đăng ký key (giây)0 (không timeout)
Avoid Same Authenticator RegisterKhông cho đăng ký cùng key 2 lầnOff
Acceptable AAGUIDsWhitelist security key modelsĐể trống = chấp nhận tất cả

3.3 Quản lý WebAuthn Credentials

# Xem WebAuthn credentials của user
curl -s -X GET \
  "https://keycloak.example.com/admin/realms/myrealm/users/$USER_ID/credentials" \
  -H "Authorization: Bearer $ADMIN_TOKEN" | \
  jq '.[] | select(.type=="webauthn")'

# Response
{
  "id": "credential-uuid",
  "type": "webauthn",
  "userLabel": "YubiKey 5",
  "createdDate": 1711900000000,
  "credentialData": "{\"aaguid\":\"...\",\"credentialPublicKey\":\"...\"}"
}

User cũng có thể tự quản lý security keys trong Account Console tại /realms/myrealm/account/#/security/webauthn.

4. Passkeys

Passkeys là phát triển tiếp theo của WebAuthn — cho phép đăng nhập không mật khẩu (passwordless) bằng fingerprint, face recognition, hoặc device PIN.

4.1 Passkeys vs WebAuthn truyền thống

Tính năngWebAuthn (MFA)Passkeys (Passwordless)
Mục đíchMFA — thêm bước sau passwordThay thế password hoàn toàn
AuthenticatorWebAuthn AuthenticatorWebAuthn Passwordless Authenticator
PolicyWebAuthn PolicyWebAuthn Passwordless Policy
Required ActionWebAuthn RegisterWebAuthn Register Passwordless
Resident KeyKhông bắt buộcBắt buộc (discoverable credential)
User VerificationTuỳ chọnRequired (biometrics/PIN)

4.2 Bật Passkeys

Bước 1: Cấu hình WebAuthn Passwordless Policy

  1. Vào Authentication → Policies → WebAuthn Passwordless Policy
  2. Cấu hình:
    • Relying Party Entity Name: My Company
    • Signature Algorithms: ES256
    • User Verification Requirement: required
    • Require Resident Key: Yes — bắt buộc cho Passkeys

Bước 2: Tạo Passwordless Browser Flow

Passwordless Browser Flow
├── Cookie (Alternative)
└── Passwordless Login (Alternative)
    ├── WebAuthn Passwordless Authenticator (Alternative)  → Đăng nhập bằng Passkey
    └── Username Password Fallback (Alternative)           → Sub-flow fallback
        ├── Username Password Form (Required)
        └── Conditional OTP (Conditional)
            ├── Condition - User Configured (Required)
            └── OTP Form (Required)

Bước 3: Bật Required Action

  1. Vào Authentication → Required Actions
  2. Bật WebAuthn Register Passwordless → Default Action: On

4.3 Passkey UI Modes — Conditional và Modal

Conditional UI (Autofill):

Passkey gợi ý tự động trong trường username — user chỉ cần chọn và xác thực bằng biometrics. Đây là trải nghiệm mượt nhất.

Để bật Conditional UI, đặt WebAuthn Passwordless Authenticator ở vị trí đầu tiên trong flow với requirement Alternative.

Modal UI:

Browser hiển thị dialog yêu cầu xác thực bằng Passkey. User phải tương tác với dialog. Dùng khi muốn explicit UX.

4.4 Đăng ký Passkey qua AIA (Application Initiated Action)

User có thể đăng ký Passkey bất kỳ lúc nào qua AIA link:

# AIA URL để trigger Passkey registration
GET /realms/myrealm/protocol/openid-connect/auth?
  client_id=my-app&
  redirect_uri=https://myapp.example.com/callback&
  response_type=code&
  scope=openid&
  kc_action=webauthn-register-passwordless

Skip if exists: Nếu muốn skip registration khi user đã có Passkey:

# Thêm parameter skip_if_exists
GET /realms/myrealm/protocol/openid-connect/auth?
  client_id=my-app&
  redirect_uri=https://myapp.example.com/callback&
  response_type=code&
  scope=openid&
  kc_action=webauthn-register-passwordless&
  kc_action_parameter=skip_if_exists

JavaScript integration:

// Sử dụng keycloak-js adapter
const keycloak = new Keycloak({
  url: 'https://keycloak.example.com',
  realm: 'myrealm',
  clientId: 'my-app'
});

// Trigger Passkey registration
function registerPasskey() {
  keycloak.login({
    action: 'webauthn-register-passwordless'
  });
}

// Button trong UI
document.getElementById('registerPasskeyBtn')
  .addEventListener('click', registerPasskey);

5. Kerberos Authentication

Kerberos cho phép Single Sign-On tự động cho users đã đăng nhập vào domain (Windows AD, MIT Kerberos). User không cần nhập credentials — browser tự gửi Kerberos ticket.

5.1 Kerberos Server Setup

Yêu cầu:

  • KDC (Key Distribution Center) đang chạy — Active Directory hoặc MIT Kerberos
  • SPN (Service Principal Number) cho Keycloak service
  • Keytab file cho Keycloak
# Tạo SPN và keytab cho Keycloak (MIT Kerberos)
kadmin -q "addprinc -randkey HTTP/[email protected]"
kadmin -q "ktadd -k /etc/keycloak/keycloak.keytab HTTP/[email protected]"

# Đặt permission
chmod 600 /etc/keycloak/keycloak.keytab
chown keycloak:keycloak /etc/keycloak/keycloak.keytab

5.2 Cấu hình Keycloak cho Kerberos

Option 1: Kerberos User Storage Provider

  1. Vào User Federation → Add provider → Kerberos
  2. Cấu hình:
    • Kerberos Realm: EXAMPLE.COM
    • Server Principal: HTTP/[email protected]
    • Key Tab: /etc/keycloak/keycloak.keytab
    • Allow Kerberos Authentication: On
    • Use Kerberos For Password Authentication: On
    • Update First Login: On

Option 2: LDAP + Kerberos (Active Directory)

  1. Vào User Federation → Add provider → LDAP
  2. Cấu hình LDAP connection cho AD
  3. Bật mục Allow Kerberos Authentication
  4. Nhập Kerberos Realm, Server Principal, Key Tab

5.3 Bật Kerberos trong Browser Flow

  1. Vào Authentication → Flows → Browser (hoặc custom flow)
  2. Tìm Kerberos execution
  3. Đổi requirement từ Disabled sang Alternative
Browser Flow (Kerberos enabled)
├── Cookie (Alternative)
├── Kerberos (Alternative)                    ← BẬT lên
├── Identity Provider Redirector (Alternative)
└── Forms (Alternative)
    ├── Username Password Form (Required)
    └── Browser - Conditional OTP (Conditional)
        ├── Condition - User Configured (Required)
        └── OTP Form (Required)

5.4 Cross-realm Trust

Cho phép users từ một Kerberos realm tin tưởng realm khác:

# /etc/krb5.conf trên Keycloak server
[libdefaults]
    default_realm = CORP.EXAMPLE.COM
    dns_lookup_realm = false
    dns_lookup_kdc = false

[realms]
    CORP.EXAMPLE.COM = {
        kdc = dc1.corp.example.com
        admin_server = dc1.corp.example.com
    }
    PARTNER.EXAMPLE.COM = {
        kdc = kdc.partner.example.com
    }

[capaths]
    PARTNER.EXAMPLE.COM = {
        CORP.EXAMPLE.COM = .
    }

6. X.509 Client Certificate Authentication

X.509 cho phép xác thực bằng client certificate — phổ biến trong môi trường enterprise, government, hoặc mTLS.

6.1 Thêm X.509 vào Browser Flow

  1. Duplicate Browser Flow → Browser with X.509
  2. Thêm X509/Validate Username Form vào flow
Browser with X.509
├── Cookie (Alternative)
├── X509/Validate Username Form (Alternative)  ← Thêm mới
├── Identity Provider Redirector (Alternative)
└── Forms (Alternative)
    ├── Username Password Form (Required)
    └── Browser - Conditional OTP (Conditional)
        ├── Condition - User Configured (Required)
        └── OTP Form (Required)

6.2 Cấu hình X.509 Authenticator

Click ⚙️ bên cạnh X509/Validate Username Form:

SettingMô tảVí dụ
User Identity SourceTrường trong certificate để identify userSubject's Common Name, Subject's e-mail
Mapping Source to User AttributeMap identity source sang user attributeUsername or Email
A regular expressionRegex extract identity từ cert fieldCN=(.*?)(?:,\|$)
CRL Checking EnabledKiểm tra Certificate Revocation ListOn
CRL Distribution PointURL hoặc path đến CRLldap://ca.example.com/CN=...
OCSP Checking EnabledKiểm tra Online Certificate Status ProtocolOn
OCSP Responder URIOCSP responder URLhttp://ocsp.example.com
Certificate Key UsageKey usage bắt buộcdigitalSignature
Certificate Extended Key UsageExtended key usageclientAuth
Certificate Policy Validation ModeValidate certificate policiesNot Specified

6.3 Certificate Mapping Strategies

Có nhiều cách map certificate sang Keycloak user:

# 1. Subject's Common Name → Username
# Certificate: CN=john.doe, OU=Engineering, O=Example Corp
# → username: john.doe

# 2. Subject's e-mail → Email
# Certificate: [email protected]
# → email: [email protected]

# 3. Serial Number → User Attribute
# Certificate: Serial=1A2B3C4D
# → user attribute "x509_serial" = "1A2B3C4D"

# 4. SHA-256 Certificate Thumbprint → User Attribute
# Certificate SHA-256: ab:cd:ef:12:34:...
# → user attribute "x509_thumbprint" = "ab:cd:ef:12:34:..."

# 5. Subject's DN với regex
# Certificate: CN=john.doe, OU=Engineering, O=Example Corp, C=VN
# Regex: CN=(.*?)(?:,|$)
# → Extracted: john.doe

6.4 CRL và OCSP Checking

Để đảm bảo certificates chưa bị thu hồi (revoked):

CRL (Certificate Revocation List):

  • Keycloak download và cache CRL từ configured URI
  • Kiểm tra serial number của client cert có trong CRL không
  • Nếu CRL không available và CRL Checking Enabled=On → xác thực fail

OCSP (Online Certificate Status Protocol):

  • Real-time check trạng thái certificate
  • Keycloak gửi request đến OCSP Responder
  • Nhanh hơn CRL cho individual checks
  • Nhược điểm: phụ thuộc OCSP server availability
# Test OCSP check
openssl ocsp \
  -issuer ca.pem \
  -cert client.pem \
  -url http://ocsp.example.com \
  -resp_text

# Test certificate info
openssl x509 -in client.pem -noout -subject -serial -fingerprint -sha256

6.5 Keycloak mTLS Setup

Để Keycloak nhận client certificates, cần cấu hình reverse proxy hoặc Keycloak trực tiếp:

# Docker Compose — Keycloak với mTLS qua nginx
services:
  nginx:
    image: nginx:latest
    ports:
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
      - ./certs/server.crt:/etc/nginx/certs/server.crt
      - ./certs/server.key:/etc/nginx/certs/server.key
      - ./certs/ca.crt:/etc/nginx/certs/ca.crt
    depends_on:
      - keycloak

  keycloak:
    image: quay.io/keycloak/keycloak:26.0
    command: start --proxy-headers xforwarded
    environment:
      KC_HOSTNAME: keycloak.example.com
      KC_HTTP_ENABLED: "true"
      KC_PROXY_HEADERS: xforwarded
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: admin
# nginx.conf — Forward client certificate
server {
    listen 443 ssl;
    server_name keycloak.example.com;

    ssl_certificate /etc/nginx/certs/server.crt;
    ssl_certificate_key /etc/nginx/certs/server.key;
    ssl_client_certificate /etc/nginx/certs/ca.crt;
    ssl_verify_client optional;

    location / {
        proxy_pass http://keycloak:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port 443;
        
        # Forward client certificate
        proxy_set_header ssl-client-cert $ssl_client_escaped_cert;
    }
}

7. So sánh các phương thức MFA

Phương thứcBảo mậtUXPhishing-resistantUse case
TOTP/HOTPTrung bìnhTốtKhôngPhổ biến, dễ deploy
WebAuthn (MFA)CaoTốtCóEnterprise, compliance
PasskeysRất caoXuất sắcCóConsumer + Enterprise
KerberosCaoXuất sắc (transparent)Có (domain)Enterprise, Windows domain
X.509 CertificateRất caoTransparentCóGovernment, military, banking

8. Tóm tắt

Khái niệmMô tả
OTP PolicyTOTP/HOTP config — algorithm, digits, period, look ahead
Recovery CodesBackup codes khi mất thiết bị OTP
WebAuthnFIDO2 security keys — phishing-resistant MFA
PasskeysPasswordless authentication — discoverable credentials + biometrics
KerberosTransparent SSO cho domain users
X.509Client certificate authentication — mTLS
CRL/OCSPCertificate revocation checking