KeyCloak と LDAPを統合する自動化の備忘録

# はじめに

KeyCloakのユーザーレポジトリとしてLDAPを構成するスクリプトを作成するのに苦労したことを備忘録として残します。

以下のページの構成を拡張するような内容となります。

https://qiita.com/keniooi/items/050b5ae0d8f50bf63c84

https://qiita.com/keniooi/items/cfe2b8ef692b23500a15

https://qiita.com/keniooi/items/724cd8cc191096d6da23

# KeyCloakの管理コンソールからLDAPを構成

http://localhost:8080/admin にログインして　pdprof の Realm（左上）を選択し、User federation (左下) をクリック、ここで Add Ldap providers をクリックしてLDAPを構成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262366/3fd81c71-2a04-edbd-37e4-1bb66bf262c0.png)

詳細名指定は自動化のスクリプト作成時にCLIの出力を取得するのでそちらを見てください。


# LDAP上のユーザーでのログインテスト

接続テストなどは動作してログインをためすが、403のエラーになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262366/a5268509-6e29-698f-3b02-da7caf2b9c97.png)

401のエラーではないので、ユーザーの認証（ユーザー名、パスワード）は問題なく、認可（権限がたりない）のエラー、ただAllAutheticated（認証が済んでいれば認可もできる）にしているので理由がよくわからない。

本番LDAPだとうまく動作してくれたので、LDAPのユーザー情報が不足してるのではないかと予想してattributeを追加（mail address)してみる。

https://github.com/pdprof/security-auth/commit/d5d3694894bcbd555800ed4c48c2aa968a475814

同じuidを使用しているため、競合しないようにuidも変更していた。結果 mail の追加で認証ができるようになった。エラーメッセージをみてもわからなかったので、うまく動作するLDAPとの比較ができたのがLDAPの情報を疑えたのでよかった。

# LDAP構成の自動化

GUIで構成した内容をCLIで取得して、それと同じような構成をするように試みる。まずは構成を取得する。

```
alias kcadm=/opt/keycloak/bin/kcadm.sh  
KEYCLOAK_USER=admin
KEYCLOAK_PASSWORD=password
```

実行コマンド
```
kcadm get components -r pdprof --server http://localhost:8080/ --realm master --user $KEYCLOAK_USER --password $KEYCLOAK_PASSWORD
```

結果（抜粋）
```
{
  "id" : "91f1f8bc-e730-4965-9589-5066e87dc60c",
  "name" : "ldap",
  "providerId" : "ldap",
  "providerType" : "org.keycloak.storage.UserStorageProvider",
  "parentId" : "f1e884dc-622a-43d5-a424-405701e2a912",
  "config" : {
    "fullSyncPeriod" : [ "-1" ],
    "pagination" : [ "false" ],
    "startTls" : [ "false" ],
    "connectionPooling" : [ "false" ],
    "usersDn" : [ "dc=pdprof,dc=mustgather" ],
    "cachePolicy" : [ "DEFAULT" ],
    "useKerberosForPasswordAuthentication" : [ "false" ],
    "importEnabled" : [ "false" ],
    "enabled" : [ "true" ],
    "bindDn" : [ "cn=admin,dc=pdprof,dc=mustgather" ],
    "usernameLDAPAttribute" : [ "uid" ],
    "changedSyncPeriod" : [ "-1" ],
    "bindCredential" : [ "**********" ],
    "vendor" : [ "other" ],
    "uuidLDAPAttribute" : [ "uid" ],
    "allowKerberosAuthentication" : [ "false" ],
    "connectionUrl" : [ "ldap://centos:1389" ],
    "syncRegistrations" : [ "false" ],
    "authType" : [ "simple" ],
    "krbPrincipalAttribute" : [ "krb5PrincipalName" ],
    "searchScope" : [ "2" ],
    "useTruststoreSpi" : [ "always" ],
    "usePasswordModifyExtendedOp" : [ "false" ],
    "trustEmail" : [ "false" ],
    "userObjectClasses" : [ "inetOrgPerson, organizationalPerson" ],
    "rdnLDAPAttribute" : [ "uid" ],
    "editMode" : [ "READ_ONLY" ],
    "validatePasswordPolicy" : [ "false" ]
  }
}
```

これと

https://stackoverflow.com/questions/59407067/add-ldap-user-federation-with-kcadm-cli-but-fails-to-show-in-ui-until-any-realm

を真似て

```
kcadm create components -r pdprof \
    -s name="openldap" \
    -s providerId=ldap \
    -s providerType=org.keycloak.storage.UserStorageProvider \
    -s 'config.fullSyncPeriod=["-1"]' \
    -s 'config.changedSyncPeriod=["-1"]' \
    -s 'config.cachePolicy=["DEFAULT"]' \
    -s 'config.editMode=["READ_ONLY"]' \
    -s 'config.syncRegistrations=["false"]' \
    -s 'config.importEnabled=["false"]' \
    -s 'config.vendor=["other"]' \
    -s 'config.usernameLDAPAttribute=["uid"]' \
    -s 'config.rdnLDAPAttribute=["uid"]' \
    -s 'config.uuidLDAPAttribute=["uid"]' \
    -s 'config.userObjectClasses=["inetOrgPerson, organizationalPerson"]' \
    -s 'config.connectionUrl=["ldap://centos:1389"]' \
    -s 'config.usersDn=["dc=pdprof,dc=mustgather"]' \
    -s 'config.authType=["simple"]' \
    -s 'config.bindDn=["cn=admin,dc=pdprof,dc=mustgather"]' \
    -s 'config.bindCredential=["passw0rd"]' \
    -s 'config.searchScope=["2"]' \
    -s 'config.useTruststoreSpi=["always"]' \
    -s 'config.connectionPooling=["false"]' \
    -s 'config.pagination=["false"]' \
    -s 'config.useKerberosForPasswordAuthentication=["false"]'　\
    --server http://localhost:8080/ --realm master \
    --user $KEYCLOAK_USER --password $KEYCLOAK_PASSWORD
```

のようにします。元記事には parentIdの指定がありましたが、指定がなければ自動で入りました。nameの指定を変えつつ作成を試すことができます。テストで作ったものは管理コンソールで消してしまいます。

同じユーザーIDを使用しているせいか登録を繰り替えしているとユーザー検索で探すとエラーになってしまうので、LDAPの構成をGUIから編集して保管すると回避できました。


# 構成の自動化

自動化の開始時の構成をどこにするかは悩むところですが、setup-docker.shを実行した後ということで始めます。構成ができている前提で実行するスクリプトを作成しました。

KeyCloakのイメージ作成時にスクリプトをコピーして、起動後のContainerで実行するようにしてあります。

変更内容は以下

https://github.com/pdprof/security-auth/commit/71b2e5e9ae37382febb42e3d030b4469dfd2d653

LDAPのイメージとコンテナーが別スクリプトになっているので、構成できていない場合には構成するように条件をつけてあります

```setup-ldap.sh 
#!/bin/bash
if [ ! "$(docker image list -q ldap)" ]; then
	docker build -t ldap -f ../ldap-docker/Dockerfile.openldap ../ldap-docker/
fi

if [ ! "$(docker ps -a | grep ldap)" ]; then
	docker run -d -p 1389:389 --name ldap ldap --loglevel debug
fi

docker exec kc /tmp/setup-kc-ldap.sh
```


# 構成ステップリスト


レポジトリコピー
```
git clone https://github.com/pdprof/security-auth.git
cd security-auth/saml-docker
```

LibertyとKeyCloakの構成
```
export ACCESS_HOST=`hostname`
./setup-docker.sh
```
注：ACCESS_HOSTはブラウザからのアクセスに使うホスト名とkcのcontainerからldapに接続するホスト名に使います。Containerのkcでもつかうのでlocalhostでは動作しません。使う場合はあとでldap接続先を管理コンソールで変更します。

LDAP構成の追加
```
./setup-ldap.sh
```

上のコマンドをコピーして実行するだけで構成できます。構成がおわったら

http://centos:9080/security.auth/

のようにアクセスしてログインをためしてみます。

https://qiita.com/keniooi/items/33473c980c9043173c3d

でLDAPに登録してあるユーザー （2024/10/30 転記）
|User | Password|
|---|---|
|wasadmin|passw0rd|
|pdadmin|passw0rd|
|myuser|passw0rd|

でログインできるかためしてみましょう。


# まとめ
LibertyでSAMLの構成でLDAPも統合できることを確認しました。作成された libertyの server.xml や KeyCloakの構成（User federation)を変更するなどして環境にあわせて調整します。