- 記事一覧 >
- ブログ記事
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 の構造
【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 の位置が意味不明ですが、あくまでテスト環境ですので、特に意味は無く、適当に決めました。
ユーザー
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 インストール
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 対応
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 アドレスに名前解決できる必要があります。
ヨシ!
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 データ準備
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 初期設定
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
PC端末での作業になります。
https://kctest.contoso.com/
にアクセスして、「Administration Console」をクリック、admin
(パスワード:password)でログインします。
左上の「Master」の箇所から「Add realm」をクリックします。
ちなみに「レルム(Realm)」は、以下のように各種設定をまとめた入れ物のようなイメージで良いと思います。
Name: test
とし、「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/
です。
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 を指定します。
「Save」をクリックした直後、「Credentials」タブをクリックして、表示される Secret をメモしておきます。これは、mod_auth_openidc の設定で必要になります。
Keycloak-OpenLDAP 連携
PC端末での作業になります。
Keycloak を使って OpenLDAP のユーザーで SSO できるようにします。
OpenLDAPを使わない場合、この作業は必須ではありませんので、このセクションごと読み飛ばしても構いません。
「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 データによって異なると思います。
Keycloak ユーザー作成
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 確認など必要にします。今回何も無しにしたいので、空欄です。
「Credentials」タブをクリックします。
パスワードを入力して、
Temporary: OFF
とし、「Set Password」をクリックします。
Temporary は、ON
にすると、初回ログイン時にパスワード変更を求められますので、これを無しにしています。
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
の画面です。
成功です!(OpenLDAPを使う場合、LDAPのユーザーldapuser1
でもログイン成功です!)
ヨシ!
ところで、mod_auth_openidc の設定で、OIDCScope "openid email"
としていないのに、OIDC_CLAIM_email
の値が取れています。
これは、どういうことかというと、mod_auth_openidc の要求に関わらず、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
あり。
となりました。
他、
Clients > keycloaktestapp > Client Scopes > Setup
で
email を外すと、OIDC_CLAIM_email
無しになりました。
無しの状態で、OIDCScope "openid email"
を設定すると、mod_auth_openidc側でエラーになります。
...
SSO(シングルサインオン)の良さを全く活かしていませんが、ここまでとします。
その他、宣伝、誹謗中傷等、当方が不適切と判断した書き込みは、理由の如何を問わず、投稿者に断りなく削除します。
書き込み内容について、一切の責任を負いません。
このコメント機能は、予告無く廃止する可能性があります。ご了承ください。
コメントの削除をご依頼の場合はTwitterのDM等でご連絡ください。