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

レッスン 13: ユーザー フェデレーション - LDAP と Active Directory

LDAP/AD フェデレーション、ストレージ モード (READ_ONLY、WRITABLE、UNSYNCED)、編集モード、接続設定 (SSL、接続プール)、LDAP マッパー (ユーザー属性、フルネーム、グループ、ロール、ハードコードされたロール、MSAD ユーザー アカウント制御)、パスワード ハッシュ、ユーザー同期、SSSD/FreeIPA 統合、Kerberos ブリッジ、カスタム ユーザー ストレージ SPI、LDAP の問題のトラブルシューティングを構成します。

🔒 DevSecOps — レッスン 13 レッスン 13: ユーザー フェデレーション - LDAP とアクティブ ディレクトリ

基本から上級までの Keycloak

パート 4: ユーザー フェデレーション、組織、および認可

xdev.asia

1. ユーザーフェデレーション — 概要

ユーザーフェデレーションによるKeycloakの有効化外部ユーザーデータベースに接続するLDAP、Active Directory、カスタム データベースなど。すべてのユーザーをKeycloakにインポートする代わりに、外部ソースから直接認証できます。

ユーザー フェデレーションを設定するには、次の場所に移動します。管理コンソール → ユーザーフェデレーション.

1.1 ユーザー フェデレーションが必要な理由は何ですか?

理由説明する
ユーザー管理を一元化するLDAP/AD はすでに企業内の主要なユーザー ソースである → 重複する必要はありません
現在のシステムをそのまま維持するユーザーをKeycloakに移行する必要はありません
単一の真実の情報源ユーザーデータは 1 か所にのみ存在し、不整合を回避します
ケルベロス SSOActive Directory からの Kerberos 認証の統合

1.2 フェデレーションプロバイダーの種類

プロバイダー説明する
LDAPOpenLDAP、389 Directory Server、および LDAP 準拠サーバーをサポート
アクティブディレクトリMicrosoft Active Directory (LDAP プロトコル + AD 固有のマッパーを使用)
SSSDシステム セキュリティ サービス デーモン — FreeIPA/Red Hat IdM の統合
カスタム ユーザー ストレージ SPI任意のデータベースに接続するための独自のプロバイダーを作成します

2. LDAPプロバイダーの追加

入力管理コンソール → ユーザー フェデレーション → LDAP プロバイダーの追加.

2.1 一般的なオプション

設定説明するサンプル値
コンソールの表示名管理コンソールに表示される名前企業LDAP
優先度プロバイダが多い場合の優先順位0(最高)
有効プロバイダーの有効化/無効化の上
ユーザーをインポートするLDAPユーザーをKeycloakローカルデータベースにインポートするの上

2.2 接続設定

# Connection URL
Connection URL: ldap://ldap.example.com:389
# Hoặc LDAPS (SSL):
Connection URL: ldaps://ldap.example.com:636

# Bind Type
Bind Type: simple

# Bind DN — tài khoản để Keycloak kết nối LDAP
Bind DN: cn=admin,dc=example,dc=com

# Bind Credential — mật khẩu
Bind Credential: ********

接続プールの設定:

設定説明するデフォルト
接続プーリング接続プールを有効にしてパフォーマンスを最適化するの上
接続プールの認証認証された接続用のプール単純。単純
接続プールのデバッグ接続プールのデバッグをログに記録するオフ
接続プールの初期サイズ最初に初期化された接続の数1
接続プールの最大サイズ最大接続数1000
接続プールのタイムアウトプールから接続を取得するまでの待ち時間30000MS

2.3 SSL/LDAPS設定

LDAPS (ポート 636) に接続するには、CA 証明書を Keycloak トラストストアにインポートする必要があります。

# Tải CA certificate từ LDAP server
openssl s_client -connect ldap.example.com:636 -showcerts < /dev/null 2>/dev/null | \
  openssl x509 -outform PEM > ldap-ca.pem

# Import vào Java truststore
keytool -import -alias ldap-ca \
  -keystore /opt/keycloak/conf/truststore.jks \
  -file ldap-ca.pem \
  -storepass changeit -noprompt

# Hoặc sử dụng PEM truststore (Keycloak 24+)
# Đặt file PEM vào /opt/keycloak/conf/truststores/
cp ldap-ca.pem /opt/keycloak/conf/truststores/

トラストストアを使用するように Keycloak を構成します。

# keycloak.conf
# Java keystore
spi-truststore-file-file=/opt/keycloak/conf/truststore.jks
spi-truststore-file-password=changeit
spi-truststore-file-type=JKS

# Hoặc PEM directory (Keycloak 24+)
truststore-paths=/opt/keycloak/conf/truststores

2.4 StartTLS を使用する

LDAPS (ポート 636) の代わりに、次のものを使用できます。TLSの開始ポート 389:

Connection URL: ldap://ldap.example.com:389
Use StartTLS: ON

StartTLS は、通常の LDAP 接続を同じポート 389 上の暗号化された接続にアップグレードします。

3. LDAP検索設定

設定説明するサンプル値
ユーザーDNKeycloakがユーザーを検索するベースDNou=人、dc=例、dc=com
ユーザーオブジェクトクラスユーザーエントリのLDAPオブジェクトクラスinetOrgperson、organizationalperson
ユーザー名のLDAP属性LDAP 属性にはユーザー名が含まれますUID(LDAP) /sAMアカウント名(広告)
RDN LDAP 属性RDN (相対識別名) に使用される属性UID(LDAP) /CN(広告)
UUID LDAP 属性属性は一意のIDとして使用されますエントリUUID(LDAP) /オブジェクトGUID(広告)
検索範囲1 つのレベルまたはサブツリーサブツリー
カスタムユーザーLDAPフィルターユーザーをフィルタリングするための追加の LDAP フィルタ(&(objectClass=person)(memberOf=cn=app-users,ou=Groups,dc=example,dc=com))
読み取りタイムアウトLDAP読み取り操作のタイムアウト30000MS

3.1 Active Directoryの設定

選ぶときはベンダー = Active Directory, Keycloak は適切な値を自動的に構成します。

Username LDAP attribute: cn
RDN LDAP attribute: cn
UUID LDAP attribute: objectGUID
User Object Classes: person, organizationalPerson, user
Users DN: cn=Users,dc=corp,dc=example,dc=com

4. ストレージモード

Keycloakは、KeycloakがLDAPと対話する方法を決定する3つのストレージモードをサポートしています。

モードLDAPから読み取るLDAPリバースロギングKeycloak DBへのインポートユースケース
読み取り専用✅❌✅ (キャッシュ)LDAP は単一ソースであり、ユーザーが Keycloak 経由で情報を変更することはできません
書き込み可能✅✅✅ユーザーが情報 (パスワード、プロファイル) を変更し、LDAP に書き戻すことができるようにします。
未同期✅❌✅LDAP からユーザーをインポートし、Keycloak DB にのみ変更を保存します (ライトバックなし)

4.1 編集モード

編集モードは、ユーザーまたは管理者が情報を変更するときの動作を規制します。

READ_ONLY:
  - User không thể đổi password qua Keycloak
  - Admin không thể edit user attributes
  - Mọi thay đổi phải thực hiện trực tiếp trên LDAP

WRITABLE:
  - User có thể đổi password → Keycloak ghi ngược về LDAP
  - Admin edit user attributes → cập nhật LDAP
  - Cẩn thận với password policy: phải match giữa Keycloak và LDAP

UNSYNCED:
  - User đổi password → chỉ lưu trong Keycloak DB
  - Đăng nhập: Keycloak thử password local trước, nếu fail thì thử LDAP
  - Phù hợp khi muốn dần migrate users sang Keycloak

5. 同期設定

Keycloakは、次の2つのメカニズムによってLDAPからユーザーを同期できます。

5.1 定期的な完全同期

# Import toàn bộ users từ LDAP vào Keycloak DB
Periodic Full Sync: ON
Full Sync Period: 604800  # seconds (7 ngày)

5.2 変更されたユーザーの定期的な同期

# Chỉ đồng bộ users có thay đổi (dựa vào modifyTimestamp)
Periodic Changed Users Sync: ON
Changed Users Sync Period: 86400  # seconds (1 ngày)

5.3 手動同期

同期は、管理コンソールまたは CLI 経由で手動でトリガーできます。

# Trigger full sync qua Admin REST API
curl -X POST "http://localhost:8080/admin/realms/my-realm/user-storage/${LDAP_PROVIDER_ID}/sync?action=triggerFullSync" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}"

# Trigger changed users sync
curl -X POST "http://localhost:8080/admin/realms/my-realm/user-storage/${LDAP_PROVIDER_ID}/sync?action=triggerChangedUsersSync" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}"

6. LDAP マッパー

LDAP マッパーが Keycloak をどのように定義するかLDAP属性をKeycloakユーザーモデルにマッピングする。これは、LDAP フェデレーションを構成する場合に最も重要な部分です。

6.1 ユーザー属性 LDAP マッパー

LDAP 属性を Keycloak ユーザー属性にマップします。

Mapper Type: user-attribute-ldap-mapper
LDAP Attribute: mail
User Model Attribute: email
Read Only: true
Always Read Value From LDAP: false
Is Mandatory In LDAP: true

デフォルトのマッパーは自動的に作成されます。

マッパー名LDAP 属性キークローク属性
ユーザー名。ユーザー名UID / sAMアカウント名ユーザー名。ユーザー名
電子メール郵便電子メール
ファーストネーム名 / CNファーストネーム
苗字すん苗字
作成日タイムスタンプの作成タイムスタンプの作成
日付を変更するタイムスタンプの変更タイムスタンプの変更

6.2 フルネーム LDAP マッパー

LDAP のマップCN(通称)Keycloakへファーストネーム + 苗字:

Mapper Type: full-name-ldap-mapper
LDAP Full Name Attribute: cn
Read Only: true
Write Only: false

LDAP のみが使用可能な場合に役立ちますCN分離せずに名/すん.

6.3 グループLDAPマッパー

LDAP グループを Keycloak グループに同期します。

Mapper Type: group-ldap-mapper
LDAP Groups DN: ou=Groups,dc=example,dc=com
Group Name LDAP Attribute: cn
Group Object Classes: groupOfNames
Membership LDAP Attribute: member
Membership Attribute Type: DN
Membership User LDAP Attribute: uid
Mode: READ_ONLY
User Groups Retrieve Strategy: LOAD_GROUPS_BY_MEMBER_ATTRIBUTE
Drop non-existing groups during sync: false
Groups Path: /

ユーザーグループの取得戦略オプション:

戦略説明する
LOAD_GROUPS_BY_MEMBER_ATTRIBUTEメンバー属性に基づいて LDAP からグループをロードします
GET_GROUPS_FROM_USER_MEMBEROF_ATTRIBUTE読むメンバーのユーザーエントリの属性
LOAD_GROUPS_BY_MEMBER_ATTRIBUTE_RECURSIVELYグループを再帰的にロードします (ネストされたグループ)

6.4 ロールLDAPマッパー

LDAP ロール/グループを Keycloak レルム ロールに同期します。

Mapper Type: role-ldap-mapper
LDAP Roles DN: ou=Roles,dc=example,dc=com
Role Name LDAP Attribute: cn
Role Object Classes: groupOfNames
Membership LDAP Attribute: member
Membership Attribute Type: DN
Membership User LDAP Attribute: uid
Mode: READ_ONLY
Use Realm Roles Mapping: true
Client ID: (để trống nếu dùng realm roles)

6.5 ハードコードされた LDAP ロールマッパー

固定役割を自動的に割り当てる全てLDAP プロバイダーからのユーザー:

Mapper Type: hardcoded-ldap-role-mapper
Role: realm-role-name
# Hoặc client role:
Role: client-id.client-role-name

ロール マーカーを使用して LDAP ユーザーとローカル ユーザーを区別する場合に便利です。

6.6 msad-user-account-control-mapper

特別なマッパーアクティブディレクトリ、 ハンドルユーザーアカウントコントロール属性:

Mapper Type: msad-user-account-control-mapper
# Xử lý:
# - Account enabled/disabled status
# - Password expired status
# - Account locked status
# - Require user to change password at next login

このマッパーはビットマスクを読み取りますユーザーアカウントコントロールKeycloakユーザーステータスにマッピングするADの:

ADフラグ(ビット)キークロークの動作
責任を負う(0x0002)ユーザーはKeycloakで無効になっています
ロックアウト(0x0010)ユーザーがロックされています
PASSWORD_EXPIREDユーザーはログイン時にパスワードを変更する必要があります

6.7 証明書-LDAP-マッパー

X.509 認証の LDAP 証明書属性を Keycloak ユーザー属性にマップします。

Mapper Type: certificate-ldap-mapper
LDAP Attribute: userCertificate
User Model Attribute: usercertificate
Is DER Formatted: true
Always Read Value From LDAP: true

7. パスワードのハッシュ化

LDAP フェデレーションを使用する場合、パスワード ハッシュにはいくつかの重要な特性があります。

シナリオパスワードハッシュ注記
読み取り専用モードパスワードは常に LDAP サーバーで直接検証されます。Keycloakはパスワードハッシュを保存しません
書き込み可能モードパスワードは、LDAP パスワード ポリシーに従って LDAP に記録されます。LDAPサーバーはハッシュを実行します
非同期モードKeycloakハッシュを使用してKeycloak DBに保存された新しいパスワード古いパスワードは引き続き LDAP 経由で検証されます
# Kiểm tra password policy trên LDAP (OpenLDAP)
ldapsearch -x -H ldap://localhost:389 \
  -D "cn=admin,dc=example,dc=com" -W \
  -b "cn=config" "(objectClass=olcGlobal)" olcPasswordHash

# Output ví dụ:
# olcPasswordHash: {SSHA}

8. SSSD と FreeIPA の統合

Keycloakはとの統合をサポートしていますSSSD (システム セキュリティ サービス デーモン)D-Bus インターフェース経由で、FreeIPA または Red Hat Identity Manager からユーザーを認証できるようになります。

8.1 前提条件

# Cài đặt SSSD trên Keycloak server
sudo dnf install sssd sssd-dbus

# Cấu hình SSSD (/etc/sssd/sssd.conf)
[sssd]
services = nss, pam, ifp
domains = example.com

[domain/example.com]
id_provider = ipa
auth_provider = ipa
access_provider = ipa
ipa_domain = example.com
ipa_server = ipa.example.com

[ifp]
allowed_uids = root, keycloak
user_attributes = +mail, +givenname, +sn, +telephoneNumber

8.2 SSSD フェデレーションプロバイダーの構成

管理コンソールで、追加しますSSSDフェデレーションプロバイダー — KeycloakはD-Bus経由でSSSDと通信し、次のことを行います。

  • ユーザーの認証 (PAM)
  • ユーザー属性の取得 (InfoPipe)
  • グループメンバーシップを取得する

9. ケルベロスブリッジ

キークロークが使えるケルベロス認証LDAP フェデレーションと併用すると、ユーザーは Kerberos チケット (SPNEGO) を使用して自動的にログインできるようになります。

9.1 LDAP を使用した Kerberos の構成

# Trong LDAP provider settings
Allow Kerberos authentication: ON
Kerberos Realm: EXAMPLE.COM
Server Principal: HTTP/[email protected]
KeyTab: /etc/keycloak/keycloak.keytab
Use Kerberos for password authentication: ON
# Tạo keytab cho Keycloak service principal
kadmin.local -q "addprinc -randkey HTTP/[email protected]"
kadmin.local -q "ktadd -k /etc/keycloak/keycloak.keytab HTTP/[email protected]"

# Set permissions
chown keycloak:keycloak /etc/keycloak/keycloak.keytab
chmod 600 /etc/keycloak/keycloak.keytab

9.2 SPNEGO のブラウザ設定

Firefox:
1. about:config
2. network.negotiate-auth.trusted-uris = .example.com
3. network.negotiate-auth.delegation-uris = .example.com

Chrome / Edge:
1. Policy: AuthServerAllowlist = *.example.com
2. Hoặc command line: --auth-server-whitelist="*.example.com"

10. カスタム ユーザー ストレージ SPI

LDAP が十分でない場合は、次のように書くことができますカスタム ユーザー ストレージ プロバイダーあらゆるデータ ソース (SQL データベース、REST API、レガシー システムなど) に接続できます。

10.1 SPI インターフェース

// UserStorageProviderFactory — tạo provider instances
public class MyUserStorageProviderFactory
    implements UserStorageProviderFactory<MyUserStorageProvider> {

    @Override
    public String getId() {
        return "my-user-storage";
    }

    @Override
    public MyUserStorageProvider create(KeycloakSession session,
                                         ComponentModel model) {
        return new MyUserStorageProvider(session, model);
    }
}

// UserStorageProvider — implement các interfaces cần thiết
public class MyUserStorageProvider implements
    UserStorageProvider,
    UserLookupProvider,
    CredentialInputValidator,
    UserQueryProvider {

    @Override
    public UserModel getUserByUsername(RealmModel realm, String username) {
        // Query external database
        ExternalUser extUser = externalDb.findByUsername(username);
        if (extUser == null) return null;

        // Wrap vào Keycloak UserModel
        return new UserAdapter(session, realm, model, extUser);
    }

    @Override
    public boolean isValid(RealmModel realm, UserModel user,
                           CredentialInput input) {
        if (!supportsCredentialType(input.getType())) return false;
        // Verify password với external system
        return externalDb.verifyPassword(
            user.getUsername(),
            input.getChallengeResponse()
        );
    }
}

10.2 カスタムプロバイダーのデプロイ

# Build JAR
mvn clean package

# Copy vào Keycloak providers directory
cp target/my-user-storage.jar /opt/keycloak/providers/

# Rebuild Keycloak
/opt/keycloak/bin/kc.sh build

11. kcadm.sh を使用して LDAP を構成する

使用kcadm.shコマンドライン経由で LDAP フェデレーションを設定するには、次の手順を実行します。

# Đăng nhập
kcadm.sh config credentials \
  --server http://localhost:8080 \
  --realm master \
  --user admin \
  --password admin

# Tạo LDAP provider
kcadm.sh create components -r my-realm \
  -s name="Corporate LDAP" \
  -s providerId=ldap \
  -s providerType=org.keycloak.storage.UserStorageProvider \
  -s 'config.vendor=["other"]' \
  -s 'config.connectionUrl=["ldap://ldap.example.com:389"]' \
  -s 'config.bindDn=["cn=admin,dc=example,dc=com"]' \
  -s 'config.bindCredential=["admin_password"]' \
  -s 'config.usersDn=["ou=People,dc=example,dc=com"]' \
  -s 'config.userObjectClasses=["inetOrgPerson, organizationalPerson"]' \
  -s 'config.usernameLDAPAttribute=["uid"]' \
  -s 'config.rdnLDAPAttribute=["uid"]' \
  -s 'config.uuidLDAPAttribute=["entryUUID"]' \
  -s 'config.editMode=["READ_ONLY"]' \
  -s 'config.syncRegistrations=["false"]' \
  -s 'config.searchScope=["2"]' \
  -s 'config.importEnabled=["true"]' \
  -s 'config.enabled=["true"]' \
  -s 'config.priority=["0"]' \
  -s 'config.fullSyncPeriod=["604800"]' \
  -s 'config.changedSyncPeriod=["86400"]'

# Lấy LDAP provider ID
LDAP_ID=$(kcadm.sh get components -r my-realm \
  --fields id,name \
  -q providerType=org.keycloak.storage.UserStorageProvider \
  | jq -r '.[0].id')

# Thêm group mapper
kcadm.sh create components -r my-realm \
  -s name="group-mapper" \
  -s providerId=group-ldap-mapper \
  -s providerType=org.keycloak.storage.ldap.mappers.LDAPStorageMapper \
  -s parentId=$LDAP_ID \
  -s 'config.groups.dn=["ou=Groups,dc=example,dc=com"]' \
  -s 'config.group.name.ldap.attribute=["cn"]' \
  -s 'config.group.object.classes=["groupOfNames"]' \
  -s 'config.membership.ldap.attribute=["member"]' \
  -s 'config.membership.attribute.type=["DN"]' \
  -s 'config.membership.user.ldap.attribute=["uid"]' \
  -s 'config.mode=["READ_ONLY"]' \
  -s 'config.drop.non.existing.groups.during.sync=["false"]'

# Trigger full sync
kcadm.sh create user-storage/$LDAP_ID/sync -r my-realm \
  -s action=triggerFullSync

12. LDAP 問題のトラブルシューティング

12.1 接続の問題

エラー理由解決
javax.naming.CommunicationExceptionLDAPサーバーに接続できませんネットワーク、ファイアウォール、ポート 389/636 を確認してください
javax.naming.AuthenticationException間違ったバインド DN またはバインド資格情報バインド資格情報を検証しますldapsearch
SSLハンドシェイク例外証明書が信頼されていませんCA 証明書をトラストストアにインポートする
接続タイムアウトLDAPサーバーが応答しない接続タイムアウトを増やし、DNS を確認してください
# Test LDAP connection
ldapsearch -x -H ldap://ldap.example.com:389 \
  -D "cn=admin,dc=example,dc=com" -W \
  -b "ou=People,dc=example,dc=com" \
  "(objectClass=inetOrgPerson)" uid mail cn

# Test LDAPS connection
ldapsearch -x -H ldaps://ldap.example.com:636 \
  -D "cn=admin,dc=example,dc=com" -W \
  -b "dc=example,dc=com" "(uid=testuser)"

# Bật debug logging trong Keycloak
bin/kc.sh start-dev \
  --log-level=org.keycloak.storage.ldap:DEBUG

12.2 同期の失敗

エラー理由解決
ユーザー ... すでに存在しますLDAP とローカル ユーザーの間でユーザー名が競合するローカル ユーザーを削除するか、ユーザー名のマッピングを変更します
サイズ制限を超えましたLDAP サーバーは返される結果の数を制限しますLDAP サーバーでページングを構成するか、LDAP フィルターを追加して範囲を縮小します
紹介LDAP は結果ではなく紹介を返しますセット紹介=フォロー接続設定で

12.3 マッパーの問題

# Kiểm tra LDAP attributes có tồn tại
ldapsearch -x -H ldap://ldap.example.com:389 \
  -D "cn=admin,dc=example,dc=com" -W \
  -b "uid=testuser,ou=People,dc=example,dc=com" \
  "*" "+"

# Kiểm tra group membership
ldapsearch -x -H ldap://ldap.example.com:389 \
  -D "cn=admin,dc=example,dc=com" -W \
  -b "ou=Groups,dc=example,dc=com" \
  "(member=uid=testuser,ou=People,dc=example,dc=com)" cn

13. ベストプラクティス

  • 常に LDAPS または StartTLS を使用する— 資格情報を平文で送信しないようにします
  • 別のサービス アカウントを使用するバインド DN の場合 — 管理者アカウントを使用しないでください
  • 検索範囲を制限する— カスタム ユーザー LDAP フィルターを使用して、必要なユーザーのみをインポートします
  • 接続プールをオンにする— 接続作成のオーバーヘッドを削減します
  • 同期期間を適切に構成する— 短すぎると LDAP に大きな負荷がかかり、長すぎるとデータが古くなります
  • 同期ログを監視する— Keycloakは同期プロセスに関する詳細をログに記録します
  • 最初に READ_ONLY でテストします— 最初に設定するときは、WRITABLE を転送する前に READ_ONLY を使用して検証します。
  • メジャー同期の前にKeycloak DBをバックアップする— 完全同期では数千のユーザーをインポートできます