1. セキュリティ強化チェックリスト
Keycloakを実稼働環境に導入する前に、次の強化策を完全に実装する必要があります。
| # | カテゴリ | レベル | 状態 |
|---|---|---|---|
| 1 | HTTPS/TLS の強制 | 致命的 | ☐ |
| 2 | デフォルトの管理者の資格情報を変更する | 致命的 | ☐ |
| 3 | ブルートフォース検出 | 高い | ☐ |
| 4 | パスワードポリシー | 高い | ☐ |
| 5 | セッションタイムアウト | 高い | ☐ |
| 6 | CSPヘッダー | 高い | ☐ |
| 7 | クリックジャッキング保護 | 高い | ☐ |
| 8 | CORS 構成 | 中くらい | ☐ |
| 9 | シークレットの Vault 統合 | 高い | ☐ |
| 10 | 管理コンソールのアクセス制限 | 高い | ☐ |
| 11 | 未使用の機能/エンドポイントを無効にする | 中くらい | ☐ |
| 12 | 保存時のデータベースの暗号化 | 高い | ☐ |
| 13 | トークンセキュリティ (有効期限が短い) | 高い | ☐ |
| 14 | 監査ログが有効になっている | 高い | ☐ |
2. コンテンツ セキュリティ ポリシー (CSP) ヘッダー
CSP ヘッダーは、ページへの読み込みを許可するリソースを制御することにより、XSS 攻撃から保護します。
2.1 KeycloakでCSPを構成する
KeycloakはCSPを構成しますレルム設定 → セキュリティ防御:
# Headers tab → Content-Security-Policy
frame-src 'self'; frame-ancestors 'self'; object-src 'none';
# Nâng cao: restrict thêm script-src, style-src
frame-src 'self'; frame-ancestors 'self'; object-src 'none'; \
script-src 'self' 'unsafe-inline'; \
style-src 'self' 'unsafe-inline';
2.2 REST APIによる設定
# Cập nhật Security Headers cho realm
curl -X PUT "http://localhost:8080/admin/realms/my-realm" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"browserSecurityHeaders": {
"contentSecurityPolicy": "frame-src '\''self'\''; frame-ancestors '\''self'\''; object-src '\''none'\'';",
"contentSecurityPolicyReportOnly": "",
"xContentTypeOptions": "nosniff",
"xRobotsTag": "none",
"xFrameOptions": "SAMEORIGIN",
"strictTransportSecurity": "max-age=31536000; includeSubDomains",
"xXSSProtection": "1; mode=block",
"referrerPolicy": "no-referrer"
}
}'
2.3 重要なセキュリティヘッダー
| ヘッダ | 推奨値 | 目的 |
|---|---|---|
X フレーム オプション | 同じ原産地 | クリックジャッキング対策 |
X-コンテンツタイプ-オプション | 鼻を鳴らす | MIME タイプ スニッフィングを防止する |
X-XSS 保護 | 1;モード=ブロック | ブラウザの XSS フィルターをオンにする |
厳格な輸送セキュリティ | 最大年齢=31536000;サブドメインを含む | HTTPS (HSTS) を強制する |
リファラーポリシー | 非参照者 | リファラーヘッダーを送信しない |
コンテンツセキュリティポリシー | フレームソース、オブジェクトソースを制限する | XSS とデータ インジェクションを防止する |
3. ブルートフォース検出
Keycloakには、ログイン試行に対するブルートフォース防止メカニズムが組み込まれています。
3.1 ブルートフォース構成
入力レルム設定 → セキュリティ防御 → ブルートフォース検出:
# Bật/tắt
Enabled: ON
# Lockout settings
Permanent Lockout: OFF # Có khóa vĩnh viễn không
Max Login Failures: 5 # Số lần thất bại tối đa trước khi lock
Wait Increment (seconds): 60 # Thời gian chờ tăng dần mỗi lần fail tiếp
Max Wait (seconds): 900 # Thời gian chờ tối đa (15 phút)
Quick Login Check (milliseconds): 1000 # Khoảng thời gian giữa 2 lần login nhanh
Minimum Quick Login Wait: 60 # Chờ tối thiểu khi quick login detected
Failure Reset Time (seconds): 43200 # Reset failure counter sau 12 giờ
3.2 REST APIによる設定
curl -X PUT "http://localhost:8080/admin/realms/my-realm" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"bruteForceProtected": true,
"permanentLockout": false,
"maxFailureWaitSeconds": 900,
"minimumQuickLoginWaitSeconds": 60,
"waitIncrementSeconds": 60,
"quickLoginCheckMilliSeconds": 1000,
"maxDeltaTimeSeconds": 43200,
"failureFactor": 5
}'
3.3 ブルートフォース検出の仕組み
Lần fail thứ 1: Không lockout
Lần fail thứ 2: Không lockout
Lần fail thứ 3: Không lockout
Lần fail thứ 4: Không lockout
Lần fail thứ 5: Lockout 60 giây (waitIncrementSeconds)
Lần fail thứ 6: Lockout 120 giây (60 * 2)
Lần fail thứ 7: Lockout 240 giây (60 * 4)
...tiếp tục tăng...
Max lockout: 900 giây (15 phút)
Sau 12 giờ không fail: Reset counter về 0
3.4 ロックの解除 ユーザーがロックされています
# Kiểm tra trạng thái brute-force cho user
curl -s "http://localhost:8080/admin/realms/my-realm/attack-detection/brute-force/users/$USER_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN" | jq .
# Response mẫu:
# {
# "numFailures": 6,
# "disabled": true,
# "lastIPFailure": "192.168.1.100",
# "lastFailure": 1710489045000
# }
# Unlock user cụ thể
curl -X DELETE "http://localhost:8080/admin/realms/my-realm/attack-detection/brute-force/users/$USER_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN"
# Unlock tất cả users
curl -X DELETE "http://localhost:8080/admin/realms/my-realm/attack-detection/brute-force/users" \
-H "Authorization: Bearer $ACCESS_TOKEN"
4. パスワードポリシー
Keycloakは、強力なパスワードを確保するために多くのパスワード・ポリシーをサポートしています。
4.1 パスワードポリシーの構成
入力認証 → ポリシー → パスワードポリシーそしてポリシーを追加します。
| ポリシー | 説明する | サンプル値 |
|---|---|---|
長さ。長さ | 最小長さ | 12 |
最大長さ | 最大長さ | 128 |
数字 | 数字の最小数 | 1 |
小文字 | 最小文字数 | 1 |
大文字 | 大文字の最小数 | 1 |
特別な文字 | 特殊文字の最小数 | 1 |
ユーザー名ではありません | パスワードはユーザー名と同じであってはなりません | (値なし) |
メールではありません | パスワードはメールアドレスと一致してはなりません | (値なし) |
パスワード履歴 | 過去 N 個のパスワードを再利用しないでください | 5 |
ハッシュアルゴリズム | パスワードハッシュアルゴリズム | pbkdf2-sha512 |
ハッシュ反復 | ハッシュの反復数 | 210000 |
強制期限切れパスワード変更 | N日後にMKの変更を強制される | 90 |
regulx式 | カスタム正規表現パターン | ^(?!.*(.)\1{2}).*$ |
4.2 REST APIによる設定
# Set password policies cho realm
curl -X PUT "http://localhost:8080/admin/realms/my-realm" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"passwordPolicy": "length(12) and digits(1) and lowerCase(1) and upperCase(1) and specialChars(1) and notUsername and notEmail and passwordHistory(5) and hashAlgorithm(pbkdf2-sha512) and hashIterations(210000) and forceExpiredPasswordChange(90) and maxLength(128)"
}'
4.3 ハッシュアルゴリズムの推奨事項
| アルゴリズム | 反復 (推奨) | 注記 |
|---|---|---|
pbkdf2-sha256 | 600,000 | OWASP 2023 の推奨事項 |
pbkdf2-sha512 | 210,000 | OWASP 2023 の推奨事項 |
アルゴン2 | 該当なし (Keycloak 24+) | メモリに負荷がかかるため、新規導入に推奨 |
# Sử dụng Argon2 (Keycloak 24+)
# passwordPolicy: hashAlgorithm(argon2)
curl -X PUT "http://localhost:8080/admin/realms/my-realm" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"passwordPolicy": "length(12) and digits(1) and lowerCase(1) and upperCase(1) and specialChars(1) and hashAlgorithm(argon2)"
}'
5. セッション管理
厳密なセッション管理はセキュリティにとって重要です。
5.1 セッションのタイムアウト
での構成レルム設定 → セッション:
| 設定 | 説明する | 推奨 |
|---|---|---|
| SSO セッションのアイドル状態 | SSO セッションの最大アイドル時間 | 30分 |
| SSO セッション最大値 | SSO セッションの最大時間 (アクティビティに関係なく) | 10時 |
| SSO セッション アイドル状態 リメンバーミー | 「Remember Me」が有効な場合のアイドル タイムアウト | 7日間 |
| SSO セッション Max Remember Me | 「Remember Me」が有効な場合の最大有効期間 | 30日 |
| クライアントセッションアイドル状態 | クライアント固有のセッションのアイドル タイムアウト | 15分 |
| クライアントセッション最大値 | クライアント固有のセッションの最大存続期間 | 8時 |
| オフラインセッションアイドル状態 | オフライントークンのアイドルタイムアウト | 30日 |
| オフラインセッション最大値 | オフラインセッションの最大制限ライフタイム | 60日 |
5.2 セッションの詳細な設定
# Cấu hình session timeouts
curl -X PUT "http://localhost:8080/admin/realms/my-realm" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ssoSessionIdleTimeout": 1800,
"ssoSessionMaxLifespan": 36000,
"ssoSessionIdleTimeoutRememberMe": 604800,
"ssoSessionMaxLifespanRememberMe": 2592000,
"clientSessionIdleTimeout": 900,
"clientSessionMaxLifespan": 28800,
"offlineSessionIdleTimeout": 2592000,
"offlineSessionMaxLifespan": 5184000,
"offlineSessionMaxLifespanEnabled": true
}'
5.3 セッション制限
ユーザーごとの同時セッション数を制限します。
# Authentication → Flows → Browser Flow
# Thêm step "User Session Limits"
Session Limits Configuration:
- Max concurrent sessions per user: 3
- Behavior on breach: "Terminate oldest session"
# Hoặc cấu hình qua Authentication Flow:
# 1. Copy "Browser" flow
# 2. Thêm execution "User Session Count Limiter"
# 3. Cấu hình max sessions
5.4 セッションの監査と取り消し
# List sessions của user
curl -s "http://localhost:8080/admin/realms/my-realm/users/$USER_ID/sessions" \
-H "Authorization: Bearer $ACCESS_TOKEN" | jq .
# Response mẫu:
# [
# {
# "id": "session-id",
# "username": "john",
# "userId": "user-uuid",
# "ipAddress": "192.168.1.100",
# "start": 1710489045,
# "lastAccess": 1710492645,
# "clients": { "client-uuid": "my-app" }
# }
# ]
# Revoke session cụ thể
curl -X DELETE "http://localhost:8080/admin/realms/my-realm/sessions/$SESSION_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN"
# Logout tất cả sessions của user
curl -X POST "http://localhost:8080/admin/realms/my-realm/users/$USER_ID/logout" \
-H "Authorization: Bearer $ACCESS_TOKEN"
# Logout tất cả sessions trong realm
curl -X POST "http://localhost:8080/admin/realms/my-realm/logout-all" \
-H "Authorization: Bearer $ACCESS_TOKEN"
6. CORS の設定
CORS (Cross-Origin Resource Sharing) が構成されているクライアントごとキークロークで。
6.1 クライアントの CORS の構成
# Client Settings → Web Origins
# Cho phép specific origins
https://myapp.com
https://admin.myapp.com
# Cho phép tất cả redirect URIs (sử dụng "+")
+
# KHÔNG sử dụng "*" trong production
# "*" cho phép tất cả origins — nguy hiểm!
# Cấu hình CORS qua REST API
curl -X PUT "http://localhost:8080/admin/realms/my-realm/clients/$CLIENT_UUID" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"webOrigins": [
"https://myapp.com",
"https://admin.myapp.com"
]
}'
6.2 CORS のベスト プラクティス
- 常に特定の起源を指定する— ワイルドカードは使用しないでください
* - 使用
+— 有効なリダイレクト URI から起点を自動的に導出する - 個別のクライアント— 各フロントエンド アプリには、独自の CORS 構成を持つ独自のクライアントが必要です
- 慎重にテストしてください— ブラウザーの DevTools で CORS 応答ヘッダーを確認する
7. クリックジャッキング保護
クリックジャッキング攻撃は、Keycloak ログインページを iframe に埋め込んで認証情報を盗みます。
7.1 X フレーム オプションの構成
# Realm Settings → Security Defenses → Headers
X-Frame-Options: SAMEORIGIN
# - DENY: Không cho phép iframe dưới bất kỳ điều kiện nào
# - SAMEORIGIN: Chỉ cho phép iframe từ cùng origin
# - ALLOW-FROM uri: (deprecated, dùng CSP frame-ancestors thay thế)
7.2 CSP フレーム祖先 (推奨)
# Content-Security-Policy header
frame-ancestors 'self';
# Cho phép specific parent origins
frame-ancestors 'self' https://portal.mycompany.com;
8. HTTPS/TLS の強制
8.1 ホスト名とTLSの構成
# Production: Strict HTTPS
bin/kc.sh start \
--hostname=auth.mycompany.com \
--hostname-strict=true \
--https-certificate-file=/etc/certs/tls.crt \
--https-certificate-key-file=/etc/certs/tls.key \
--https-port=8443 \
--http-enabled=false
8.2 リバース プロキシを使用した TLS (一般的)
# Khi sử dụng reverse proxy (Nginx, HAProxy) terminate TLS
bin/kc.sh start \
--hostname=auth.mycompany.com \
--hostname-strict=true \
--proxy-headers=xforwarded \
--http-enabled=true \
--http-port=8080
# Nginx reverse proxy configuration
server {
listen 443 ssl http2;
server_name auth.mycompany.com;
ssl_certificate /etc/ssl/certs/auth.mycompany.com.crt;
ssl_certificate_key /etc/ssl/private/auth.mycompany.com.key;
# Strong TLS configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
proxy_pass http://keycloak:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Timeouts
proxy_read_timeout 90s;
proxy_send_timeout 90s;
}
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name auth.mycompany.com;
return 301 https://$host$request_uri;
}
8.3 相互TLS (mTLS)
# Bật mTLS cho client authentication
bin/kc.sh start \
--https-certificate-file=/etc/certs/tls.crt \
--https-certificate-key-file=/etc/certs/tls.key \
--https-trust-store-file=/etc/certs/truststore.jks \
--https-trust-store-password=changeit \
--https-client-auth=request
# --https-client-auth options:
# none: không yêu cầu client cert
# request: yêu cầu nhưng không bắt buộc
# required: bắt buộc client cert
8.4 証明書の管理
# Sử dụng cert-manager trong Kubernetes
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: keycloak-tls
namespace: keycloak
spec:
secretName: keycloak-tls-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- auth.mycompany.com
renewBefore: 720h # Renew 30 ngày trước khi hết hạn
# Kubernetes Deployment sử dụng TLS secret
apiVersion: apps/v1
kind: Deployment
metadata:
name: keycloak
spec:
template:
spec:
containers:
- name: keycloak
image: quay.io/keycloak/keycloak:26.1
args:
- start
- --hostname=auth.mycompany.com
- --https-certificate-file=/etc/certs/tls.crt
- --https-certificate-key-file=/etc/certs/tls.key
volumeMounts:
- name: tls-certs
mountPath: /etc/certs
readOnly: true
volumes:
- name: tls-certs
secret:
secretName: keycloak-tls-secret
9. ボールトの統合
Keycloakは、データベース内のプレーンテキストではなく、外部ボールトへのシークレット(LDAPバインド・パスワード、SMTPパスワード、クライアント・シークレット)の保存をサポートしています。
9.1 HashiCorp Vault の統合
# Cấu hình Keycloak sử dụng HashiCorp Vault
bin/kc.sh start \
--vault=hashicorp \
--vault-hashicorp-paths=/secret/data/keycloak \
--vault-hashicorp-address=https://vault.mycompany.com:8200 \
--vault-hashicorp-auth-method=token \
--vault-hashicorp-token=$VAULT_TOKEN
# Hoặc sử dụng AppRole authentication
bin/kc.sh start \
--vault=hashicorp \
--vault-hashicorp-paths=/secret/data/keycloak \
--vault-hashicorp-address=https://vault.mycompany.com:8200 \
--vault-hashicorp-auth-method=approle \
--vault-hashicorp-approle-role-id=$ROLE_ID \
--vault-hashicorp-approle-secret-id=$SECRET_ID
9.2 HashiCorp Vault へのシークレットの保存
# Cấu hình Vault KV secrets engine
vault secrets enable -path=secret kv-v2
# Lưu LDAP bind password
vault kv put secret/keycloak/my-realm \
ldap_bind_credential="LdapS3cur3P@ss!" \
smtp_password="SmtpP@ssw0rd!" \
my-client-secret="Cl13ntS3cr3t!"
# Cấu trúc path trong Vault:
# secret/data/keycloak/{realm-name}/{key}
9.3 KeycloakでのVaultリファレンスの使用
Keycloak では、次の構文を使用します${vault.key}平文の代わりに:
# LDAP User Federation
Bind Credential: ${vault.ldap_bind_credential}
# SMTP Settings
Password: ${vault.smtp_password}
# Client Secret
Client Secret: ${vault.my-client-secret}
9.4 Kubernetes/OpenShift Secrets Vault
# Sử dụng Kubernetes Secrets làm vault
bin/kc.sh start \
--vault=file \
--vault-dir=/mnt/secrets
# Kubernetes Secret
apiVersion: v1
kind: Secret
metadata:
name: keycloak-vault
namespace: keycloak
type: Opaque
stringData:
# Format: {realm-name}_{key}
my-realm_ldap_bind_credential: "LdapS3cur3P@ss!"
my-realm_smtp_password: "SmtpP@ssw0rd!"
my-realm_my-client-secret: "Cl13ntS3cr3t!"
# Mount Secret vào Keycloak Pod
apiVersion: apps/v1
kind: Deployment
metadata:
name: keycloak
spec:
template:
spec:
containers:
- name: keycloak
args:
- start
- --vault=file
- --vault-dir=/mnt/secrets
volumeMounts:
- name: vault-secrets
mountPath: /mnt/secrets
readOnly: true
volumes:
- name: vault-secrets
secret:
secretName: keycloak-vault
9.5 ファイルベースのボールト (開発)
# Tạo vault files cho development
mkdir -p /opt/keycloak/vault/my-realm
# Mỗi file chứa một secret (filename = key)
echo -n "LdapS3cur3P@ss!" > /opt/keycloak/vault/my-realm/ldap_bind_credential
echo -n "SmtpP@ssw0rd!" > /opt/keycloak/vault/my-realm/smtp_password
# Cấu hình Keycloak
bin/kc.sh start-dev \
--vault=file \
--vault-dir=/opt/keycloak/vault
9.6 認証情報のローテーション
# HashiCorp Vault: Rotate LDAP password
# 1. Update secret trong Vault
vault kv put secret/keycloak/my-realm \
ldap_bind_credential="NewLdapP@ss2026!"
# 2. Keycloak sẽ tự động lấy secret mới
# (Vault SPI cache TTL = 0 by default, mỗi lần cần sẽ fetch lại)
# Kubernetes Secrets: Update secret
kubectl create secret generic keycloak-vault \
--from-literal=my-realm_ldap_bind_credential="NewLdapP@ss2026!" \
--dry-run=client -o yaml | kubectl apply -f -
# Rolling restart Keycloak để pickup new secrets
kubectl rollout restart deployment/keycloak -n keycloak
10. 管理コンソールのアクセス制限
10.1 専用の管理者レルム
使用マスターレルム管理者の場合のみ、ユーザー/クライアント ビジネスを作成しないでください。
Best Practice:
- Master realm: Chỉ chứa admin users
- Business realms: Chứa application users/clients
- Không cho phép self-registration trên master realm
- MFA bắt buộc cho admin accounts
10.2 管理コンソールの IP ホワイトリスト
# Nginx: Restrict Admin Console access
location /admin/ {
# Chỉ cho phép IP nội bộ
allow 10.0.0.0/8;
allow 172.16.0.0/12;
allow 192.168.0.0/16;
deny all;
proxy_pass http://keycloak:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Block admin REST API từ external
location /admin/realms/ {
allow 10.0.0.0/8;
deny all;
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;
}
10.3 Kubernetesネットワークポリシー
# NetworkPolicy: Restrict Admin API access
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: keycloak-admin-restrict
namespace: keycloak
spec:
podSelector:
matchLabels:
app: keycloak
policyTypes:
- Ingress
ingress:
# Allow user-facing traffic from ingress controller
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- port: 8080
# Allow admin traffic only from management namespace
- from:
- namespaceSelector:
matchLabels:
name: management
ports:
- port: 8080
11. トークンのセキュリティ
11.1 有効期間の短いトークン
# Cấu hình token lifespans
curl -X PUT "http://localhost:8080/admin/realms/my-realm" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"accessTokenLifespan": 300,
"accessTokenLifespanForImplicitFlow": 900,
"actionTokenGeneratedByUserLifespan": 300,
"actionTokenGeneratedByAdminLifespan": 43200
}'
# Per-client token lifespan override
curl -X PUT "http://localhost:8080/admin/realms/my-realm/clients/$CLIENT_UUID" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"attributes": {
"access.token.lifespan": "180",
"client.session.idle.timeout": "600",
"client.session.max.lifespan": "3600"
}
}'
11.2 トークンのイントロスペクション
# Introspect token (kiểm tra validity)
curl -X POST "http://localhost:8080/realms/my-realm/protocol/openid-connect/token/introspect" \
-d "client_id=my-resource-server" \
-d "client_secret=$CLIENT_SECRET" \
-d "token=$ACCESS_TOKEN"
# Response
# {
# "active": true,
# "sub": "user-uuid",
# "aud": "my-app",
# "exp": 1710492645,
# "iat": 1710489045,
# "realm_access": { "roles": ["user"] },
# "scope": "openid profile email"
# }
11.3 トークンの取り消し
# Revoke refresh token
curl -X POST "http://localhost:8080/realms/my-realm/protocol/openid-connect/revoke" \
-d "client_id=my-app" \
-d "client_secret=$CLIENT_SECRET" \
-d "token=$REFRESH_TOKEN" \
-d "token_type_hint=refresh_token"
# Revoke access token
curl -X POST "http://localhost:8080/realms/my-realm/protocol/openid-connect/revoke" \
-d "client_id=my-app" \
-d "client_secret=$CLIENT_SECRET" \
-d "token=$ACCESS_TOKEN" \
-d "token_type_hint=access_token"
12. 実稼働環境への導入 — 強化された
# docker-compose.production.yml - Hardened Keycloak
services:
keycloak:
image: quay.io/keycloak/keycloak:26.1
command:
- start
- --hostname=auth.mycompany.com
- --hostname-strict=true
- --proxy-headers=xforwarded
- --http-enabled=true
- --metrics-enabled=true
- --health-enabled=true
- --vault=file
- --vault-dir=/mnt/secrets
- --log=console
- --log-console-output=json
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD_FILE: /run/secrets/db_password
KC_CACHE: ispn
KC_CACHE_STACK: kubernetes
volumes:
- ./secrets:/mnt/secrets:ro
secrets:
- db_password
deploy:
replicas: 2
resources:
limits:
memory: 1G
cpus: '1.0'
reservations:
memory: 512M
cpus: '0.5'
healthcheck:
test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/9000 && echo -e 'GET /health/ready HTTP/1.1\r\nHost: localhost\r\n\r\n' >&3 && cat <&3 | grep -q '\"status\":\"UP\"'"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
secrets:
db_password:
file: ./secrets/db_password
13. ベストプラクティスの概要
- どこでもHTTPS— TLS を使用せずに Keycloak 本番環境をデプロイしないでください。 HSTS ヘッダーを使用します。
- Vault の秘密— 平文の認証情報を DB に保存しないでください。 HashiCorp Vault または Kubernetes Secret を使用します。
- 強力なパスワードポリシー— 最小 12 文字。反復回数が多い場合は Argon2 または PBKDF2-SHA512 を使用します。
- セッション制限— 同時セッションの数を制限します。それに応じてアイドル/最大タイムアウトを設定します。
- 管理者アクセスが制限されています— 管理コンソールの IP ホワイトリスト。管理者アカウントには MFA が必要です。
- 有効期間の短いトークン— アクセス トークンは 5 分間、リフレッシュ トークンのローテーションは有効です。
- ブルートフォース保護— 有効にし、それに応じて設定します。ログイン失敗率を監視します。
- 定期的なセキュリティ監査— Keycloak構成を定期的に確認します。最新バージョンにアップデートしてください。
- 別個の管理レルム— マスターレルムは管理者のみに使用します。管理者ユーザーとビジネス ユーザーを混在させないでください。
- 監視と警告— イベント ログ (レッスン 18) をセキュリティ監視と組み合わせて、検出と対応を行います。