1. 記事一覧 >
  2. ブログ記事
category logo

Keycloak PostgreSQL OpenLDAP mod_auth_openidcでSSO全手順

(更新) (公開)

はじめに

別記事「AD FS 構成から mod_auth_openidc による OpenID Connect 認証成功まで全手順
の Keycloak 版になります。
AD FS の代わりに、Keycloak が OpenID Provider だった場合、どのような手順になるのかやってみました。全手順を紹介していきます。
てんこ盛りのタイトルになっていますが、Postgre SQL、OpenLDAP は必須ではありません。
PostgreSQL、OpenLDAP のところを読み飛ばした場合、「Keycloak mod_auth_openidc で SSO 全手順」になります。
スタート:Keycloak インストール
ゴール:mod_auth_openidc による OpenID Connect 認証成功


Keycloak は、SAML、OAuth 2.0 にも対応していますが、今回は、OpenID Connect の OpenID Provider として利用になります。


【Keycloak】

Keycloak(キークローク)は、モダンなアプリケーションやサービスで使用することを目的に開発された、シングルサインオン、アイデンティティ管理、アクセス管理の機能を提供するオープンソースソフトウェア製品です。

Apache License 2.0ライセンスです。


・Keycloak の構造

Keycloakの構造

【WildFly】

企業向けの機能を集めたJava EE(Java Platform Enterprise Edition)のアプリケーションサーバです。

Red Hat社のJBoss Application Server (JBoss AS)がWildFlyと改名されたものです。

オープンソースのLGPL 2.1(または互換)ライセンスです。

【JBoss】

ジェイボス。Javaを基盤とするWebアプリケーションサーバの一つで、EJBコンテナやサーブレットコンテナ(Apache Tomcatを内蔵)などとして動作します。

WebサーバのUndertowやRDBMSのHSQLDB などが内蔵されており、これ一つでWebアプリケーションを動作させることもできます。

【Hibernate JPA】

Java Persistence API(JPA)とは、リレーショナルデータベースのデータを扱うJava SEおよびJakarta EE(旧Java EE)のアプリケーションを開発するためのJava用フレームワークです。

JPAはO/Rマッピング機能を持つことが大きな特徴です。

JPAは仕様でしかなく、JPAを実装したプロダクトが複数あり、その中の一つがHibernate(ハイバネート)です。

Hibernateは、Javaとリレーショナルデータベースで「O/Rマッピング」を実現するため設計された、オープンソースソフトウェアです。

【O/Rマッピング(ORM)】

O/Rマッピングとは、オブジェクト指向プログラミング言語におけるオブジェクトとリレーショナルデータベース(RDB)の間でデータ形式の相互変換を行うことです。

Javaオブジェクトとリレーショナルデータベース上のデータを関連付け、SQLを書かなくても、データベース操作ができる仕組みです。

【JDBC】

JDBCとはJava Database Connectivityの略で、Javaアプリケーションからデータベースを操作するAPIのことです。


構成

構成は、以下です。
※PostgreSQL、OpenLDAP の位置が意味不明ですが、あくまでテスト環境ですので、特に意味は無く、適当に決めました。

Keycloak PostgreSQL OpenLDAP mod_auth_openidc構成図


ユーザー
OS: Windows 10 PRO x64
Chrome: バージョン: 96.0.4664.45(Official Build) (64 ビット)


OpenID Provider
以下の呼び方の場合もあります。
OpenID プロバイダー
OP
Identity Provider
IdP


OS: CentOS Linux release 8.5.2111
Keycloak をインストールするサーバーです。
Keycloak の動作モードは、"standalone"です。
・Keycloak 15.0.2
・PostgreSQL 13.5(必須ではない)


Relying Party
以下の呼び方の場合もあります。
RP
Service Provider
SP
Client
クライアント


OS: Raspberry Pi Desktop
Debian ベースの Linux です。
/etc/debian_version:10.7
・Apache/2.4.38 (Debian)
・mod_auth_openidc-2.3.10.2
・PHP 7.3.31-1~deb10u1 (cli)
 ※php は、php である必要は無く、今回、認証が必要な Web アプリに見立てています。
・OpenLDAP 2.4.47(必須ではない)


Keycloak インストール

Keycloakインストール 図

OpenID Provider(OP) での作業になります。


インストールの準備をします。

# yum update -y
# yum install -y java-1.8.0-openjdk-devel
# yum install -y wget
→既に入っていた。
# yum install -y zip
→既に入っていた。

keycloak 実行ユーザー、グループを作成します。

# groupadd -r keycloak
# useradd -m -d /var/lib/keycloak -s /sbin/nologin -r -g keycloak keycloak

keycloak を/opt/keycloak/current へインストールします。

# mkdir -p /opt/keycloak
# wget https://github.com/keycloak/keycloak/releases/download/15.0.2/keycloak-15.0.2.zip -P /opt/keycloak
# unzip /opt/keycloak/keycloak-15.0.2.zip -d /opt/keycloak
# ln -s /opt/keycloak/keycloak-15.0.2 /opt/keycloak/current
# chown keycloak: -R /opt/keycloak
# chmod 700 /opt/keycloak/current/standalone

【wgetの-Pオプション】

-P, –directory-prefix=PREFIX ファイルを PREFIX/ 以下に保存

【chown keycloak:】

ユーザ名の後ろにグループ名なしでコロンだけが続く場合、ファイルの所有者がそのユーザに変更され、ファイルのグループがそのユーザのログイングループに変更されます。

systemctl のデーモンとして登録します。
192.168.12.10の部分は、バインドアドレスで、Keycloak サーバーの IP アドレスを指定します。(今作業しているサーバーの IP アドレスです。)

# cat > /etc/systemd/system/keycloak.service <<EOF
[Unit]
Description=Keycloak
After=network.target

[Service]
Type=idle
User=keycloak
Group=keycloak
ExecStart=/opt/keycloak/current/bin/standalone.sh -b 192.168.12.10
TimeoutStartSec=600
TimeoutStopSec=600

[Install]
WantedBy=multi-user.target
EOF

# systemctl daemon-reload
# systemctl enable keycloak
# systemctl start keycloak

systemctl start keycloakで何もエラーにならなければ、インストール成功です。


Keycloak SSL 対応

Keycloak SSL対応 図

OpenID Provider(OP) での作業になります。


Keycloak を 443 ポートで、https://kctest.constoso.com/ でアクセスできるようにします。


リバースプロキシを経由して、

ブラウザ/API発射側 → 443/リバースプロキシ → 8080/Keycloak or 8443/Keycloak

で良いのですが、443直に繋げる手順です。


ホスト名を設定します。

# hostnamectl set-hostname kctest.constoso.com
# vi /etc/hosts
192.168.12.10 kctest.constoso.com

CA スクリプトで、プライベート CA を作成したいのですが、CentOS8 には無いため、CentOS7 の openssl の RPM パッケージをダウンロードします。
(参考:https://blog.apar.jp/linux/14087/

# wget http://ftp.riken.jp/Linux/centos/7/os/x86_64/Packages/openssl-1.0.2k-19.el7.x86_64.rpm

/etc/pki/tls/misc/CA を取り出します。

# rpm2cpio openssl-1.0.2k-19.el7.x86_64.rpm | cpio -id ./etc/pki/tls/misc/CA
# find etc
etc
etc/pki
etc/pki/tls
etc/pki/tls/misc
etc/pki/tls/misc/CA

【rpm2cpio, cpio】

RPMファイルをcpioファイルに変換し、cpioコマンドで展開しています。

cpioファイルは、tarのような無圧縮アーカイブファイルです。

-i, --extract

コピーイン(copy-in)モードで動作=展開します。

-d, --make-directories

必要に応じてディレクトリを作成します。

/etc/pki/tls/misc/CA を従来(CentOS7)の場所に移動します。

# mv -i etc/pki/tls/misc/CA /etc/pki/tls/misc/

自前の CA(プライベート CA)を作成します。値は適当に入力します。※自己署名証明書作成の手順です。正式証明書がある場合、不要です。

# cd /etc/pki/tls/misc/
# ./CA -newca
CA certificate filename (or enter to create)
エンター

Making CA certificate ...
Generating a RSA private key
.........................................................................................................+++++
.....+++++
writing new private key to '/etc/pki/CA/private/./cakey.pem'
Enter PEM pass phrase:secret
Verifying - Enter PEM pass phrase:secret
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Aichi
Locality Name (eg, city) [Default City]:Toyota
Organization Name (eg, company) [Default Company Ltd]:ITC
Organizational Unit Name (eg, section) []:エンター
Common Name (eg, your name or your server's hostname) []:kctestca.contoso.com
Email Address []:admin@kctestca.contoso.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:エンター
An optional company name []:エンター
Using configuration from /etc/pki/tls/openssl.cnf
Enter pass phrase for /etc/pki/CA/private/./cakey.pem:secret
Check that the request matches the signature
Signature ok
・・・(略)・・・
Write out database with 1 new entries
Data Base Updated

これにより、
/etc/pki/CA/private/cakey.pem
/etc/pki/CA/careq.pem
/etc/pki/CA/cacert.pem
ができます。


keytool コマンドで、キーストアおよび証明書発行要求を作成します。
alias: kctest
ホスト名: kctest.contoso.com
キーストア: keycloak.jks
とします。キーストアは、keycloak.jks固定です。
ホスト名は、Keycloak のホスト名です。
alias のkctestは、任意ですが、キーストア内の位置を示す言葉で、この後のコマンドでも登場します。
その他は、適当で良いはずです。

# keytool -genkey -alias kctest -keyalg RSA -keystore keycloak.jks -validity 10950
Enter keystore password:secret
Re-enter new password:secret
What is your first and last name?
  [Unknown]:  kctest.constoso.com
What is the name of your organizational unit?
  [Unknown]:  エンター
What is the name of your organization?
  [Unknown]:  ITC
What is the name of your City or Locality?
  [Unknown]:  Toyota
What is the name of your State or Province?
  [Unknown]:  Aichi
What is the two-letter country code for this unit?
  [Unknown]:  JP
Is CN=kctest.constoso.com, OU=Unknown, O=ITC, L=Toyota, ST=Aichi, C=JP correct?
  [no]:  yes

Enter key password for <kctest>
        (RETURN if same as keystore password):secret
Re-enter new password:secret

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore keycloak.jks -destkeystore keycloak.jks -deststoretype pkcs12".

PKCS12 形式のキーストアをお勧めする警告が出ますが、無視して構いません。

【JKSとPKCS12】

キーストアの形式です。JKSはJava固有のフォーマットであるのに対して、PKCS12は暗号化された秘密キーと証明書を格納する標準化された言語に依存しない方法です。

# keytool -certreq -alias kctest -keystore keycloak.jks > keycloak.careq
Enter keystore password:  secret

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore keycloak.jks -destkeystore keycloak.jks -deststoretype pkcs12".

CA(プライベート CA)で、証明書発行要求に署名を入れます。

# echo subjectAltName=DNS:kctest.constoso.com > san.ext
# openssl ca -in keycloak.careq -out keycloak.crt -days 3650 -cert /etc/pki/CA/cacert.pem -keyfile /etc/pki/CA/private/cakey.pem -extfile san.ext
Using configuration from /etc/pki/tls/openssl.cnf
Enter pass phrase for /etc/pki/CA/private/cakey.pem:secret
Check that the request matches the signature
Signature ok
The stateOrProvinceName field is different between
CA certificate (Aichi) and the request (Aichi)

上記のようなエラーになる場合、-policy policy_anythingを付けて実施します。-policy policy_anythingは上記のようなエラーを無視するオプションです。

# openssl ca -in keycloak.careq -out keycloak.crt -days 3650 -cert /etc/pki/CA/cacert.pem -keyfile /etc/pki/CA/private/cakey.pem -extfile san.ext -policy policy_anything
Using configuration from /etc/pki/tls/openssl.cnf
Enter pass phrase for /etc/pki/CA/private/cakey.pem:secret
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number:
            28:69:0e:9f:73:15:d2:00:8e:40:ed:a2:bd:65:40:0c:6f:f7:4e:95
        Validity
            Not Before: Nov 28 10:07:07 2021 GMT
            Not After : Nov 26 10:07:07 2031 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = Aichi
            localityName              = Toyota
            organizationName          = ITC
            organizationalUnitName    = Unknown
            commonName                = kctest.constoso.com
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:kctest.constoso.com
Certificate is to be certified until Nov 26 10:07:07 2031 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

無事署名できました。


CA 証明書(/etc/pki/CA/cacert.pem)とサーバー証明書(keycloak.crt)をキーストアkeycloak.jksにインポートします。

# keytool -import -keystore keycloak.jks -file /etc/pki/CA/cacert.pem -alias root
Enter keystore password:secret
Owner: EMAILADDRESS=admin@kctestca.contoso.com, CN=kctestca.contoso.com, O=ITC, ST=Aichi, C=JP
Issuer: EMAILADDRESS=admin@kctestca.contoso.com, CN=kctestca.contoso.com, O=ITC, ST=Aichi, C=JP
Serial number: 28690e9f7315d2008e40eda2bd65400c6ff74e94
Valid from: Sun Nov 28 01:58:48 PST 2021 until: Wed Nov 27 01:58:48 PST 2024
Certificate fingerprints:
         SHA1: CA:42:68:66:25:D2:59:49:37:30:C8:1D:07:11:72:67:4B:25:86:C6
         SHA256: E7:65:5C:D8:64:14:69:78:F2:0D:5F:04:89:C0:1F:E4:9F:BF:AE:3C:C6:92:33:26:48:3B:A2:65:30:02:B1:AC
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3

Extensions:

#1: ObjectId: 2.5.29.35 Criticality=false
・・・(略)・・・
]

Trust this certificate? [no]:  yes
Certificate was added to keystore

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore keycloak.jks -destkeystore keycloak.jks -deststoretype pkcs12".
# keytool -import -alias kctest -keystore keycloak.jks -file keycloak.crt
Enter keystore password:secret
Certificate reply was installed in keystore

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore keycloak.jks -destkeystore keycloak.jks -deststoretype pkcs12".

Keycloak の構成定義ファイル(standalone.xml)を変更し、キーストア(keycloak.jks)を指定します。さらに、ポートを8443から443に変更します。

# vi /opt/keycloak/current/standalone/configuration/standalone.xml

元々あった方をコメントアウトか削除して、★ の行を追加します。(★ は要りません。)

<management>
  <security-realms>
    ・・・(略)・・・
    <security-realm name="ApplicationRealm">
      <server-identities>
        <ssl>
            <!-- <keystore path="application.keystore" relative-to="jboss.server.config.dir" keystore-password="password" alias="server" key-password="password" generate-self-signed-certificate-host="localhost"/> -->
<keystore path="keycloak.jks" relative-to="jboss.server.config.dir" keystore-password="secret" alias="kctest" key-password="secret" generate-self-signed-certificate-host="kctest"/>
        </ssl>
      </server-identities>
      ・・・(略)・・・
    </security-realm>
  </security-realms>
  ...
</management>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
・・・(略)・・・
  <!-- <socket-binding name="https" port="${jboss.https.port:8443}"/> -->
<socket-binding name="https" port="${jboss.https.port:443}"/>
・・・(略)・・・
</socket-binding-group>

この時点で、

# systemctl restart keycloak

としても、以下のエラーになって、443 ポートが起動しません。

standalone.sh[2932]: #033[0m#033[31m02:16:47,162 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("add") failed - address: ([
standalone.sh[2932]:    ("subsystem" => "undertow"),
standalone.sh[2932]:    ("server" => "default-server"),
standalone.sh[2932]:    ("https-listener" => "https")
standalone.sh[2932]: ]) - failure description: {"WFLYCTL0080: Failed services" => {"org.wildfly.undertow.listener.https" => "WFLYUT0082: Could not start 'https' listener.
standalone.sh[2932]:    Caused by: java.net.SocketException: Permission denied"}}
standalone.sh[2932]: #033[0m#033[0m02:16:47,218 INFO  [org.jboss.as.server] (ServerService Thread Pool -- 43) WFLYSRV0010: Deployed "keycloak-server.war" (runtime-name : "keycloak-server.war")
standalone.sh[2932]: #033[0m#033[0m02:16:47,232 INFO  [org.jboss.as.controller] (Controller Boot Thread) WFLYCTL0183: Service status report
standalone.sh[2932]: WFLYCTL0186:   Services which failed to start:      service org.wildfly.undertow.listener.https: WFLYUT0082: Could not start 'https' listener.

非 root ユーザ(keycloak)で起動していて、ウェルノウンポート(1024 未満のポート)にバインドできないためです。

# sysctl -w net.ipv4.ip_unprivileged_port_start=443
net.ipv4.ip_unprivileged_port_start = 443
# cat /proc/sys/net/ipv4/ip_unprivileged_port_start
443

で起動できるようになります。(この場合、非 root ユーザでも 443 以上のポートでバインド可)
しかし、再起動すると、元に戻るため、恒久的にそうするには、以下の処置が必要です。

# vi /etc/sysctl.d/99-rootless.conf
net.ipv4.ip_unprivileged_port_start=443
# sysctl --system
# systemctl restart keycloak
# ss -ant | grep :443
LISTEN 0      128    192.168.12.10:443        0.0.0.0:*

起動しました。

【ssコマンド】

socket statistics の略でnetstatのようにネットワークの状態を確認できるコマンドです。netstat -ant | grep :443 でも確認できます。

-a:現在のすべての接続を表示する

-n:一切の名前解決を行わない

-t:TCPポートを表示する

firewall の 443 を開けておきます。

# firewall-cmd --add-port=443/tcp --zone=public --permanent
# firewall-cmd --reload

ブラウザからhttps://kctest.contoso.com/にアクセスしてみます。
kctest.contoso.comは、Keycloak サーバーの IP アドレスに名前解決できる必要があります。

kctest.contoso.comにアクセス

ヨシ!


DB を postgreSQL に変更

DBをpostgreSQLに変更 図

OpenID Provider(OP) での作業になります。


Keycloak の DB は、デフォルトでは、H2 という Java ベースのリレーショナル・データベースが使われています。
公式ドキュメントでは、「プロダクション用の外部データベースに置き換えることを強くお勧めします。」と書かれていますので、PostgreSQL に変更しようと思います。
H2 のままにする場合、このセクションを読み飛ばしても構いません。


PostgreSQL13 をインストールします。

# dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm
# dnf -qy module disable postgresql
# dnf install -y postgresql13-server
# /usr/pgsql-13/bin/postgresql-13-setup initdb
# systemctl enable postgresql-13
# systemctl start postgresql-13

psqlコマンドで keycloak という DB、keycloak という PostgreSQL 内のユーザーを作成します。パスワードは、PASSWORD です。

# su - postgres
$ psql -d postgres
postgres=# CREATE USER keycloak WITH PASSWORD 'PASSWORD' CREATEDB;
CREATE ROLE
postgres=# CREATE DATABASE keycloak OWNER keycloak;
CREATE DATABASE
postgres=# \q
$ exit

PostgreSQL 用の JDBC ドライバをダウンロードします。

# mkdir -p /opt/drivers/jdbc
# wget https://jdbc.postgresql.org/download/postgresql-42.3.1.jar -P /opt/drivers/jdbc

jboss-cli を使って、Wildfly 用の位置に JDBC ドライバを配置し、module.xmlを置きます。

# /opt/keycloak/current/bin/jboss-cli.sh
You are disconnected at the moment. Type 'connect' to connect to the server or 'help' for the list of supported commands.
[disconnected /]  module add --name=org.postgresql  --dependencies=javax.api,javax.transaction.api --resources="/opt/drivers/jdbc/postgresql-42.3.1.jar"

以下の事を手動で行っても同じことです。

# mkdir -p /opt/keycloak/current/org/postgresql/main
# cp /opt/drivers/jdbc/postgresql-42.3.1.jar /opt/keycloak/current/org/postgresql/main/
# vi /opt/keycloak/current/org/postgresql/main/module.xml
<?xml version='1.0' encoding='UTF-8'?>

<module xmlns="urn:jboss:module:1.1" name="org.postgresql">

    <resources>
        <resource-root path="postgresql-42.3.1.jar"/>
    </resources>

    <dependencies>
        <module name="javax.api"/>
        <module name="javax.transaction.api"/>
    </dependencies>
</module>

続けて、standalone/configuration/standalone.xmlに設定を書き込んでいきます。

[disconnected /] connect
[standalone@localhost:9990 /] /subsystem=datasources/jdbc-driver=postgresql:add(driver-name=postgresql,driver-module-name=org.postgresql,driver-class-name=org.postgresql.Driver)
{"outcome" => "success"}

以下の事を手動で行っても同じことです。(以降同様で、xml の変更箇所だけ示します。)
★ の行が追加箇所です。(★ は要りません。)

# vi /opt/keycloak/current/standalone/configuration/standalone.xml
    <drivers>
      <driver name="h2" module="com.h2database.h2">
        <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
      </driver>
<driver name="postgresql" module="org.postgresql">
<driver-class>org.postgresql.Driver</driver-class>
</driver>
    </drivers>
  </datasources>

続けて、(jboss-cli で connect した状態で、)H2 データベース関連の設定を削除します。

[standalone@localhost:9990 /] /subsystem=datasources/data-source=KeycloakDS:remove
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}

★ の行が削除箇所です。

      </security>
    </datasource>
<datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}">
<connection-url>jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
    <drivers>
      <driver name="h2" module="com.h2database.h2">

続けて、(jboss-cli で connect した状態で、)PostgreSQL データベース関連の設定を追加します。
postgresql://<ホスト>:<ポート>/<DB名>
user-name=<DBユーザー名>,password="<DBユーザーパスワード>"
の部分は適切に書き換える必要があります。

[standalone@localhost:9990 /] /subsystem=datasources/data-source=KeycloakDS:add(driver-name=postgresql,enabled=true,use-java-context=true,connection-url="jdbc:postgresql://localhost:5432/keycloak",jndi-name="java:jboss/datasources/KeycloakDS",user-name=keycloak,password="PASSWORD",max-pool-size=20)
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}
[standalone@localhost:9990 /] quit

★ の行が追加箇所です。(★ は要りません。)

      </security>
    </datasource>
<datasource jndi-name="java:/jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
<connection-url>jdbc:postgresql://host:port/database</connection-url>
<driver>postgresql</driver>
<pool>
<max-pool-size>20</max-pool-size>
</pool>
<security>
<user-name>keycloak</user-name>
<password>PASSWORD</password>
</security>
</datasource>
    <drivers>
      <driver name="h2" module="com.h2database.h2">

# systemctl restart keycloak

これで H2→PostgreSQL 切り替え完了です。


OpenLDAP データ準備

OpenLDAPデータ準備 図

Relying Party(RP) での作業になります。


Keycloak 自身でユーザーが管理されていますが、既に OpenLDAP にユーザー情報がある場合、そのまま活用できます。「既に OpenLDAP にユーザー情報がある」状態を作り出すところからやっていきます。OpenLDAPを使わない場合、この作業は必須ではありませんので、このセクションごと読み飛ばしても構いません。


*,dc=example,dc=comの初期データを作成したいため、ホスト名を変更します。

# hostnamectl set-hostname ldap.example.com
# apt install -y slapd ldap-utils

管理者パスワードを聞かれますので、passwordとします。
dn: dc=example,dc=com
dn: cn=admin,dc=example,dc=com
が自動登録されます。


登録ユーザーは、ldapuser1(パスワード:password)とします。

パスワードハッシュを得ておきます。(LDIFのuserPassword: に書く内容です。)

# slappasswd
New password: password
Re-enter new password: password
{SSHA}X71E7EoclYHZtbknkruD7JlPl6aE98RH

LDIF を作成します。

# vi add.ldif
dn: ou=people,dc=example,dc=com
objectClass: organizationalUnit
ou: people

dn: uid=ldapuser1,ou=people,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
cn: Ldap
sn: User1
userPassword: {SSHA}X71E7EoclYHZtbknkruD7JlPl6aE98RH
loginShell: /bin/bash
homeDirectory: /home/ldapuser1
uidNumber: 3000
gidNumber: 3000
mail: ldapuser1@example.com

ldapaddで登録します。

# ldapadd -x -D cn=admin,dc=example,dc=com -w "password" -f add.ldif
adding new entry "ou=people,dc=example,dc=com"

adding new entry "uid=ldapuser1,ou=people,dc=example,dc=com"

ldapuser1の登録完了です。


Keycloak 初期設定

Keycloak初期設定 図1

OpenID Provider(OP) での作業になります。


Keycloak 管理者admin(パスワード:password)を作成します。

# /opt/keycloak/current/bin/add-user-keycloak.sh -r master -u admin -p password
Added 'admin' to '/opt/keycloak/current/standalone/configuration/keycloak-add-user.json', restart server to load user
# systemctl restart keycloak

Keycloak初期設定 図2

PC端末での作業になります。


https://kctest.contoso.com/にアクセスして、「Administration Console」をクリック、admin(パスワード:password)でログインします。

「Administration Console」をクリック


admin(パスワード:password)でログイン


左上の「Master」の箇所から「Add realm」をクリックします。
「Add realm」をクリック


ちなみに「レルム(Realm)」は、以下のように各種設定をまとめた入れ物のようなイメージで良いと思います。
「レルム(Realm)」は、以下のように各種設定をまとめた入れ物のようなイメージ


Name: test
とし、「Create」をクリックします。
「Create」をクリック


「Clients」 → 「Create」をクリックします。
「Clients」 → 「Create」をクリック


Client ID: keycloaktestapp
Client Protocol: openid-connect
Root URL: https://192.168.11.9/
とし、「Save」をクリックします。
Client ID は、任意のアプリ名、Root URL は、今回 https://192.168.11.9/info.php を Web アプリに見立てているため、https://192.168.11.9/です。
「Clients」 → 「Create」をクリック 「Save」をクリック


Client ID: keycloaktestapp
Consent Required: ON
Access Type: confidential
Valid Redirect URIs:
https://192.168.11.9/*

https://192.168.11.9/redirect_uri
とし、「Save」をクリックします。
Consent Required は、ログインするユーザーに「メールアドレスをアプリに渡して良いか?」のような確認画面を表示するかどうかになります。
Access Type は、Web アプリの場合、confidential、モバイルアプリ、SPA、デスクトップアプリの場合、public、SPA、Web API のようなアクセストークンだけで認証チェックを行いたいアプリケーションの場合、bearer-onlyになります。ただし、アプリの用途だけで決めず、厳密な意味を理解して設定した方が良いと思います。今回、厳密な意味の説明は省略します。
Valid Redirect URIs は、OpenID Connect の都合上、リダイレクトされる URL で(404 Not found になるような)Web アプリ側で意味の無い URL を指定します。
「Clients」 → 「Create」をクリック 「Save」をクリック 「Save」をクリック


「Save」をクリックした直後、「Credentials」タブをクリックして、表示される Secret をメモしておきます。これは、mod_auth_openidc の設定で必要になります。
「Save」をクリックした直後、「Credentials」タブをクリックして、表示される Secret をメモ


Keycloak-OpenLDAP 連携

Keycloak-OpenLDAP連携 図

PC端末での作業になります。


Keycloak を使って OpenLDAP のユーザーで SSO できるようにします。
OpenLDAPを使わない場合、この作業は必須ではありませんので、このセクションごと読み飛ばしても構いません。


「User Federation」をクリックして、「Add provider...」のところから「ldap」を選択します。
「User Federation」をクリックして、「Add provider...」のところから「ldap」を選択


Import Users: ON
Edit Mode: WRITABLE
Vender: Other
User Object Classes:
inetOrgPerson, organizationalPerson

inetOrgPerson, posixAccount, shadowAccount
Connection URL: ldap://192.168.11.9:389
Users DN: ou=people,dc=example,dc=com
Bind DN: cn=admin,dc=example,dc=com
Bind Credential: password
とし、「Save」をクリックします。
Import Users は、ONにすると、Keycloak の DB にインポートされます。今回、自らインポートの操作は行わないため、ユーザーがログインしたタイミングでインポートされます。(インポートされたことは、Users 画面で分かります。)
Edit Mode:WRITABLEは、Keycloak の管理画面から OpenLDAP のデータを書き換えることができるという意味です。今回ログインを試すだけなので、READ_ONLYでも構いません。UNSYNCEDとした場合は、Keycloak に取り込まれて、管理画面から書き換えることができるけれど、OpenLDAP 側には反映されないという意味です。
User Object Classes の部分は、ldapuser1のオブジェクトクラスを入力しましたが、LDAP データによって異なると思います。

「ldap」を選択 「Save」をクリック


Keycloak ユーザー作成

「Users」→「Add user」をクリックします。 「Users」→「Add user」をクリック


Username: testuser
Email: testuser@contoco.com
First Name: TEST
Last Name: User
Email Verified: ON
Required User Actions: 選択無し
とし、「Save」をクリックします。
Email Verified は、ユーザー情報email_verified=1になります。(Required User Actions: Verify Emailにしても Email は送信されません。)
Required User Actions は、初回ログイン時にワンタイムパスワード設定や Email 確認など必要にします。今回何も無しにしたいので、空欄です。
「Users」→「Add user」をクリック 「Save」をクリック


「Credentials」タブをクリックします。
パスワードを入力して、
Temporary: OFF
とし、「Set Password」をクリックします。
Temporary は、ONにすると、初回ログイン時にパスワード変更を求められますので、これを無しにしています。
「Set Password」をクリック


mod_auth_openidc 設定

mod_auth_openidc設定 図

Relying Party(RP) での作業になります。


Webアプリ側(https://192.168.11.9/)Relying Party(RP)の設定を行います。
Apache2 のインストールから mod_auth_openidc の設定になりますが、内容が「AD FS 構成から mod_auth_openidc による OpenID Connect 認証成功まで全手順」の記事と重複するため、そちらをご確認ください。
Apache2 インストール
mod_auth_openidc の設定

設定の説明はこちらにあります。


いきなり設定作業から入ります。
※Keycloak サーバーkctest.contoso.comの名前解決ができない場合、hosts の登録が必要です。

# vi /etc/apache2/mods-available/auth_openidc.conf
OIDCRedirectURI https://192.168.11.9/redirect_uri
OIDCCryptoPassphrase password
OIDCProviderMetadataURL https://kctest.contoso.com/auth/realms/test/.well-known/openid-configuration
OIDCScope "openid"
OIDCSSLValidateServer Off
OIDCResponseType code
OIDCClientID keycloaktestapp
OIDCClientSecret da7e3f22-82f1-49e4-ad00-3dc9c0133329
OIDCPKCEMethod S256
OIDCSessionInactivityTimeout 300
OIDCHTMLErrorTemplate /etc/apache2/auth_openidc_error.html
OIDCDefaultLoggedOutURL https://192.168.11.9/loggedout.html
OIDCClaimPrefix OIDC_CLAIM_
OIDCRemoteUserClaim preferred_username
OIDCPassClaimsAs both
OIDCAuthNHeader X-Remote-User

OIDCProviderMetadataURL のkctest.contoso.comは、Keycloak サーバー名、/test/は、レルム名です。
OIDCClientID のkeycloaktestappは、Keycloak で設定した Client ID です。
OIDCClientSecret は、Keycloak で設定中に出てきた Secret です。

# systemctl restart apache2

ログイン確認 Scope について

ログイン確認 図

PC端末での作業になります。


https://192.168.11.9/info.phpにアクセスします。
最初のユーザー名とパスワードを入力する画面は、Keycloak サーバーkctest.contoso.comの画面です。

Keycloakログイン確認1


Keycloakログイン確認2


Keycloakログイン確認3


成功です!(OpenLDAPを使う場合、LDAPのユーザーldapuser1でもログイン成功です!)


ヨシ!


ところで、mod_auth_openidc の設定で、
OIDCScope "openid email"
としていないのに、
OIDC_CLAIM_emailの値が取れています。
これは、どういうことかというと、mod_auth_openidc の要求に関わらず、Keycloak の方で、情報を渡すかどうか決めているようです。
Keycloak の方で、情報を渡すかどうか決めている


Client Scopes > email > Mappers > email
にて、
Add to ID token だけ ON の場合、OIDC_CLAIM_email あり。
Add to access token だけ ON の場合、OIDC_CLAIM_email 無し。
Add to userinfo だけ ON の場合、OIDC_CLAIM_emailあり。
となりました。
Add to ID token


他、
Clients > keycloaktestapp > Client Scopes > Setup

email を外すと、OIDC_CLAIM_email 無しになりました。
無しの状態で、OIDCScope "openid email"を設定すると、mod_auth_openidc側でエラーになります。
email を外すと、OIDC_CLAIM_email 無し


...
SSO(シングルサインオン)の良さを全く活かしていませんが、ここまでとします。


loading...