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

Ubuntu 22にKeycloak 22をインストールして、Identity providers=Azure ADでSAML

(更新) (公開)

はじめに

この記事に「SSO とは」「SAML とは」「Keycloak とは」等々、用語の説明はありません。

Ubuntu 22.04.3 LTS に Keycloak 22.0.5(Quarkus 版) をインストールして、SAML による SSO(シングルサインオン/Single Sign On)環境を作成しました。
さらに作業を進めて、Identity providers に Azure AD(Azure Active Directory/Microsoft Entra ID)を追加して、Azure AD のアカウントで認証することに成功しました。
アプリ - Keycloak - Azure AD の場合、Keycloak は、仲介サービス(Identity Broker)として機能します。

Azure AD(Azure Active Directory)は、Microsoft Entra ID に名称が変わりましたが、この記事では、Azure AD 表記のままでいきます。


今回作成したのは、以下の2パターンです。

●基本パターン
SP(Service Provider): Apache & mod_auth_mellon & php
IdP(Identity Provider): Keycloak
User federation: Keycloak の DB(PostgreSQL14)

基本パターン 図


●Azure AD利用パターン
SP(Service Provider): Apache & mod_auth_mellon & php
Identity Broker: Keycloak
IdP(Identity Provider): Azure AD
User federation: Azure AD

Azure AD利用パターン 図


Identity Broker(Keycloak)は、mod_auth_mellon から見ると、IdP で、Azure AD から見ると、SP でもあります。


この2パターンの環境構築について、Keycloak インストールから全手順を紹介していきます。


Keycloak に関しては、Docker, Podman, Kubernetes 等コンテナでデプロイではなく、ソースコードを Ubuntu の /opt/keycloak にビルドしてデプロイします。

Keycloak は、v17 までアプリケーションサーバーとして、Wildfly を使っていたのですが、v17 から Quarkus を利用するようになったようです。今回、Wildfly ではなく、Quarkus 前提の手順です。

Quarkus(カーカス)は、Red Hat 社が開発しているオープンソースの Java フレームワークです。

コンテナ化・サーバレス化した開発環境に最適化されており、アプリケーションの起動時間や応答時間を速くし、省メモリで実行することができます。

Quarkus の主な機能は次のとおりです。

・柔軟な開発モデル

・省メモリ

・高速起動

・繰り返しタスクの自動化


【検証環境】

●Keycloak

 ・Ubuntu 22.04.3 LTS

  ・Keycloak 22.0.5

  ・PostgreSQL 14.9

 

●Apache & mod_auth_mellon & php

 ・Debian Bullseye with Raspberry Pi Desktop 2022-07-01(Debian version: 11)

  ・Apache 2.4.56

  ・libapache2-mod-auth-mellon 0.17.0-1+deb11u1

  ・PHP 7.4.33

 

● クラウド:Azure AD(Azure Active Directory/Microsoft Entra ID)


この記事では、とにかく動作するまでの最低限の設定しか行いません。ログアウトのことは考えません。

本記事情報の設定不足、誤りにより何らかの問題が生じても、一切責任を負いません。


IdP:Keycloak インストール

OS(Ubuntu 22.04.3 LTS)を標準のインストール方法でインストールした直後とします。

全て root 権限で実行しています。そのため、sudo は省略しています。

hosts 登録しないといけないとか当たり前のことは省略しています。

Keycloak 22.0.5 をインストールします。


apt を最新化します。

# apt update -y && apt upgrade -y

必要パッケージと時刻合わせに使う chrony をインストールします。

SAML 認証では、IdP(Identity Provider)と SP(Service Provider)の間で時刻が大きくずれていると問題が生じることがあります。

これは、SAML アサーション(認証情報)には有効期限が含まれており、その有効期限が IdP と SP で異なる解釈をされる可能性があるからです。

# apt install software-properties-common ca-certificates chrony -y
# vi /etc/chrony/chrony.conf
# systemctl restart chrony.service

ここで、chrony.conf は、以下のように NTP サーバーを設定して、時刻がずれないようにします。

/etc/chrony/chrony.conf
#pool ntp.ubuntu.com        iburst maxsources 4
#pool 0.ubuntu.pool.ntp.org iburst maxsources 1
#pool 1.ubuntu.pool.ntp.org iburst maxsources 1
#pool 2.ubuntu.pool.ntp.org iburst maxsources 2
pool ntp.nict.jp iburst

Java ランタイム環境と開発環境をインストールします。

# apt install openjdk-17-jre-headless openjdk-17-jdk-headless -y

keycloak-22.0.5.tar.gz をダウンロードして、展開し、/opt/keycloak に配置します。

# wget https://github.com/keycloak/keycloak/releases/download/22.0.5/keycloak-22.0.5.tar.gz
# tar zxvf keycloak-22.0.5.tar.gz
# mv keycloak-22.0.5 keycloak
# mv keycloak /opt/

PostgreSQL 14 をインストールして、DB=keycloak、 User=keycloak, Password=PASSWORD を作成します。

# apt install postgresql -y
# su - postgres
$ psql -V
psql (PostgreSQL) 14.9 (Ubuntu 14.9-0ubuntu0.22.04.1)
$ psql -d postgres
CREATE USER keycloak WITH PASSWORD 'PASSWORD' CREATEDB;
CREATE DATABASE keycloak OWNER keycloak;
\q
$ exit

keycloak.conf にデータベースの種類、データベース名、データベースユーザー名等設定します。

# vi /opt/keycloak/conf/keycloak.conf
/opt/keycloak/conf/keycloak.conf
# データベースの種類=PostgreSQL
db=postgres
# データベースへの接続に使用するユーザー名=keycloak
db-username=keycloak
# データベースへの接続に使用するパスワード=PASSWORD
db-password=PASSWORD
# データベースへの接続URL
db-url=jdbc:postgresql://localhost/keycloak
# ヘルスチェック(サービスの健康状態を確認する機能)有効
health-enabled=true
# メトリクス(サービスのパフォーマンスを測定するデータ)有効
metrics-enabled=true

keycloak ユーザーと keycloak グループを作成します。(最後に /opt/keycloak の Owner:Group のパーミッションを keycloak:keycloak とします。)

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

https:// で Keycloak の管理コンソールにアクセスするため、自己署名証明書を作成します。 今回、Keycloak の URL は、https://kctest.contoso.com とします。

Keycloak の管理コンソール とは、GUIの Keycloak 設定画面のことです。

# openssl req -newkey rsa:2048 -nodes -keyout server.key.pem -x509 -days 3650 -out server.crt.pem
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Aichi
Locality Name (eg, city) []:Toyota
Organization Name (eg, company) [Internet Widgits Pty Ltd]:ITC
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:kctest.contoso.com
Email Address []:
# mv server.crt.pem /opt/keycloak/conf/
# mv server.key.pem /opt/keycloak/conf/

keycloak.conf に先ほどのホスト名、証明書、秘密鍵を設定します。

# vi /opt/keycloak/conf/keycloak.conf
/opt/keycloak/conf/keycloak.conf
# 注意:confの前に / の追加が必要。(コメントを外すだけでは、NG)
https-certificate-file=${kc.home.dir}/conf/server.crt.pem
# 注意:confの前に / の追加が必要。(コメントを外すだけでは、NG)
https-certificate-key-file=${kc.home.dir}/conf/server.key.pem
hostname=kctest.contoso.com
# 443ポートを使用する設定を追加します。※デフォルトは、8443です。
https-port=443

keycloak.conf の https-certificate-filehttps-certificate-key-file について、上記コメントにもありますが、初期状態でコメントアウトされている

${kc.home.dir}conf

のままの場合、/opt/keycloakconf を参照しようとしてエラーになりました。


ビルドして、手動起動します。
ビルドする際に、Keycloak 管理コンソールの管理者ユーザー名とパスワードを設定します。
管理者ユーザー名: admin
管理者パスワード: KYC_PASS

# cd /opt/keycloak/bin/
# export KEYCLOAK_ADMIN=admin
# export KEYCLOAK_ADMIN_PASSWORD=KYC_PASS
# ./kc.sh --verbose build
# ./kc.sh --verbose start

https://kctest.contoso.com/ にアクセスして、
管理者ユーザー名: admin
管理者パスワード: KYC_PASS
でログインできたら、ひとまずは、成功です。

Administration Console


Sign in to your account


master realm


ヨシ!


IdP:Keycloak サービス追加

./kc.sh --verbose start で問題無いことが確認できたため、CTRL + C で止めます。


systemctl で keycloak を起動する設定を追加します。

# vi /etc/systemd/system/keycloak.service
/etc/systemd/system/keycloak.service
# 汎用オプション
[Unit]
# サービスの説明書き
Description=Keycloak Application Server
# ネットワークとsyslogサービスが起動して実行された後にこのサービスを開始
After=syslog.target network.target
# 固有のオプション
[Service]
# 実行したタイミングで起動完了と判断
Type=simple
# 停止完了までに待機する時間
TimeoutStopSec=0
# systemctl stopコマンドでSIGTERMシグナルを送る
KillSignal=SIGTERM
# サービスが停止されたときにメインプロセスのみが強制終了
KillMode=process
# 成功とみなされる終了ステータス=143
SuccessExitStatus=143
# 最大ロックメモリアドレス空間
LimitMEMLOCK=infinity
# systemd がサービスを停止した後、残りのプロセスにSIGKILLシグナルを送信しない
SendSIGKILL=no
# 作業ディレクトリ
WorkingDirectory=/opt/keycloak/
# 実行に使用されるユーザーとグループ
User=keycloak
Group=keycloak
# オープンファイル記述子の最大数
LimitNOFILE=102642
# ログをコンソールとファイルに出力するオプションを指定して起動
# ログの出力先は、/opt/keycloak/data/log/keycloak.log
ExecStart=/opt/keycloak/bin/kc.sh start --log=console,file
# インストールに関する情報
[Install]
# システムがマルチユーザーモードで起動するときに自動的に起動する
WantedBy=multi-user.target
# chown keycloak: -R /opt/keycloak
# systemctl enable keycloak.service
# systemctl start keycloak.service
(しばらくしてから確認)
# systemctl status keycloak.service
× keycloak.service - Keycloak Application Server
     Loaded: loaded (/etc/systemd/system/keycloak.service; enabled; vendor preset: enabled)
     Active: failed (Result: exit-code) since Sat 2023-11-25 17:18:55 JST; 43s ago
    Process: 1774 ExecStart=/opt/keycloak/bin/kc.sh start --log=console,file (code=exited, status=1/FAILURE)
   Main PID: 1774 (code=exited, status=1/FAILURE)
        CPU: 16.515s

11月 25 17:18:54 ubuntu-22043 kc.sh[1774]: 2023-11-25 17:18:54,266 INFO  [org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory] (main) Node name: ubuntu-22043-6245, S>
11月 25 17:18:55 ubuntu-22043 kc.sh[1774]: 2023-11-25 17:18:55,119 INFO  [org.infinispan.CLUSTER] (main) ISPN000080: Disconnecting JGroups channel `ISPN`
11月 25 17:18:55 ubuntu-22043 kc.sh[1774]: 2023-11-25 17:18:55,162 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Failed to start server in (production) mode
11月 25 17:18:55 ubuntu-22043 kc.sh[1774]: 2023-11-25 17:18:55,163 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Unable to start HTTP server
11月 25 17:18:55 ubuntu-22043 kc.sh[1774]: 2023-11-25 17:18:55,163 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: io.quarkus.runtime.QuarkusBindException: Por>
11月 25 17:18:55 ubuntu-22043 kc.sh[1774]: 2023-11-25 17:18:55,163 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Port(s) already bound: 443: 許可がありません
11月 25 17:18:55 ubuntu-22043 kc.sh[1774]: 2023-11-25 17:18:55,164 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) For more details run the same command passing the '>
11月 25 17:18:55 ubuntu-22043 systemd[1]: keycloak.service: Main process exited, code=exited, status=1/FAILURE
11月 25 17:18:55 ubuntu-22043 systemd[1]: keycloak.service: Failed with result 'exit-code'.
11月 25 17:18:55 ubuntu-22043 systemd[1]: keycloak.service: Consumed 16.515s CPU time.

systemctl start keycloak.service ですんなり起動して、ヨシ!っと思ったら、エラー停止しました。
エラー:ERROR: Port(s) already bound: 443: 許可がありません.
非特権(非 root)ユーザ(keycloak)で起動していて、ウェルノウンポート(1024 未満のポート)にバインドできないため、エラーです。


# sysctl net.ipv4.ip_unprivileged_port_start
net.ipv4.ip_unprivileged_port_start = 1024

1024 以上しか非特権ユーザーのアクセスが許されていません。

# sysctl -w net.ipv4.ip_unprivileged_port_start=443

で 443 未満に変更します。
さらに、この設定を恒久化します。

# vi /etc/sysctl.d/99-sysctl.conf
/etc/sysctl.d/99-sysctl.conf
net.ipv4.ip_unprivileged_port_start=443

反映して、再スタートします。

# sysctl --system
# systemctl start keycloak
# systemctl status keycloak
● keycloak.service - Keycloak Application Server
     Loaded: loaded (/etc/systemd/system/keycloak.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2023-11-25 17:31:25 JST; 10s ago
   Main PID: 1928 (java)
      Tasks: 52 (limit: 9387)
     Memory: 291.1M
        CPU: 14.350s
     CGroup: /system.slice/keycloak.service
             mq1928 java -Dkc.config.built=true -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.err.encoding=UTF-8 -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8 -XX:+ExitOnOutOfMemoryError -Djava.security.egd=file:/dev/urandom -XX:+UseParallelGC -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED -Dkc.home.dir=/opt/keycloak/bin/.. -Djboss.ser>

11月 25 17:31:29 ubuntu-22043 kc.sh[1928]: 2023-11-25 17:31:29,829 INFO  [org.infinispan.LIFECYCLE] (jgroups-7,ubuntu-22043-12067) [Context=offlineSessions] ISPN100002: Starting rebalance with members [ubuntu-22043-46092, ubuntu-22043-12067], phase READ_OLD_WRITE_ALL, topology id 12
11月 25 17:31:29 ubuntu-22043 kc.sh[1928]: 2023-11-25 17:31:29,831 INFO  [org.infinispan.LIFECYCLE] (jgroups-7,ubuntu-22043-12067) [Context=offlineSessions] ISPN100010: Finished rebalance with members [ubuntu-22043-46092, ubuntu-22043-12067], topology id 12
11月 25 17:31:29 ubuntu-22043 kc.sh[1928]: 2023-11-25 17:31:29,848 INFO  [org.infinispan.LIFECYCLE] (jgroups-10,ubuntu-22043-12067) [Context=sessions] ISPN100002: Starting rebalance with members [ubuntu-22043-46092, ubuntu-22043-12067], phase READ_OLD_WRITE_ALL, topology id 12
11月 25 17:31:29 ubuntu-22043 kc.sh[1928]: 2023-11-25 17:31:29,850 INFO  [org.infinispan.LIFECYCLE] (jgroups-10,ubuntu-22043-12067) [Context=sessions] ISPN100010: Finished rebalance with members [ubuntu-22043-46092, ubuntu-22043-12067], topology id 12
11月 25 17:31:29 ubuntu-22043 kc.sh[1928]: 2023-11-25 17:31:29,862 INFO  [org.infinispan.LIFECYCLE] (jgroups-10,ubuntu-22043-12067) [Context=work] ISPN100002: Starting rebalance with members [ubuntu-22043-46092, ubuntu-22043-12067], phase READ_OLD_WRITE_ALL, topology id 12
11月 25 17:31:29 ubuntu-22043 kc.sh[1928]: 2023-11-25 17:31:29,864 INFO  [org.infinispan.LIFECYCLE] (non-blocking-thread--p2-t5) [Context=work] ISPN100010: Finished rebalance with members [ubuntu-22043-46092, ubuntu-22043-12067], topology id 12
11月 25 17:31:30 ubuntu-22043 kc.sh[1928]: 2023-11-25 17:31:30,035 INFO  [org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory] (main) Node name: ubuntu-22043-12067, Site name: null
11月 25 17:31:30 ubuntu-22043 kc.sh[1928]: 2023-11-25 17:31:30,784 INFO  [io.quarkus] (main) Keycloak 22.0.5 on JVM (powered by Quarkus 3.2.7.Final) started in 4.791s. Listening on: https://0.0.0.0:443
11月 25 17:31:30 ubuntu-22043 kc.sh[1928]: 2023-11-25 17:31:30,786 INFO  [io.quarkus] (main) Profile prod activated.
11月 25 17:31:30 ubuntu-22043 kc.sh[1928]: 2023-11-25 17:31:30,786 INFO  [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, jdbc-h2, jdbc-mariadb, jdbc-mssql, jdbc-mysql, jdbc-oracle, jdbc-postgresql, keycloak, logging-gelf, micrometer, narayana-jta, reactive-routes, resteasy, resteasy-jackson, smallrye-context-propagation, smallrye-health, vertx]

https://kctest.contoso.com/ にアクセスして、起動確認します。


アクセスして、起動確認


ヨシ!


IdP:Keycloak レルム作成

まず、テスト用にレルムを作成します。

「レルム(Realm)」は、以下のように各種設定をまとめた入れ物のようなイメージで良いと思います。master レルムが最初からあります。

レルム イメージ 図


管理コンソールの "master" と表示されているところをクリックして、Create Realm をクリックします。

Create Realm


Realm name に作成するレルムの名前を入力して、Create をクリックします。 ここでは、TestRealm とします。

レルム Create


レルム作成成功


IdP:Keycloak 一般ユーザー作成

レルム:TestRealm を選択して、Keycloak の DB(PostgreSQL)にユーザーを作成します。
ここで作成するユーザーは、レルム:TestRealm 内に作成された Keycloak 独自管理下のユーザーです。


Users をクリックして、Add user をクリックします。

Add user


Username に作成するユーザー名を入力します。
ここでは、testuser とします。
確認メール不要としたいため、Email verified は、Yes とします。
Create をクリックします。

ユーザー Create


Credentials タブをクリックして、パスワードを設定します。

Credentials


Set password をクリックします。

Set password


設定したいパスワードを入力します。
ここで、Temporary を On にすると、初回ログイン時にパスワードの変更を求められますので、Off にしておきます。
Save をクリックします。

パスワード入力


Save password


テストユーザーの準備完了です。


SP:アプリ環境作成

・Debian Bullseye with Raspberry Pi Desktop 2022-07-01(Debian version: 11)
の OS インストール直後からスタートして、
・Apache 2.4.56
・PHP 7.4.33
・libapache2-mod-auth-mellon 0.17.0-1+deb11u1
をインストールします。

OS インストール方法は、別記事「Raspberry Pi OS を VMware-workstation-16.1.1 にインストール」を参考にしてください。※バージョンが少し古いですが、手順は同じです。


ここで、SAML クライアント、つまり、アプリ(SP)側の URL は、https://kcapp.example.com/ であるという前提として進めます。


https://kcapp.example.com/
で Apache のデフォルト画面(index.html
https://kcapp.example.com/info.php
phpinfo() の画面を表示する Web サーバーを構築し、それを「アプリ」とします。

全て root 権限で実行しています。そのため、sudo は省略しています。

hosts 登録しないといけないとか当たり前のことは省略しています。

# apt -y update
# apt -y install apache2
# apt -y install libapache2-mod-auth-mellon
# a2enmod auth_mellon
# a2enmod ssl
# a2ensite default-ssl
# openssl genrsa -aes128 2048 > server.key
# openssl req -new -key server.key > server.csr
# openssl x509 -in server.csr -days 365 -req -signkey server.key > server.crt
# openssl rsa -in server.key -out server.key
# cp -p server.crt /etc/ssl/certs/server.crt
# cp -p server.key /etc/ssl/private/server.key
# chmod 400 /etc/ssl/private/server.key
# vi /etc/apache2/sites-available/default-ssl.conf
    SSLCertificateFile      /etc/ssl/certs/ssl-cert-snakeoil.pem
    SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
を以下に変更
    SSLCertificateFile      /etc/ssl/certs/server.crt
    SSLCertificateKeyFile /etc/ssl/private/server.key
# apt -y install php-common libapache2-mod-php php-cli
# systemctl restart apache2
# vi /var/www/html/info.php
/var/www/html/info.php
<?php
  phpinfo();

ここまで実施して、動作確認します。 なお、この時点では、mod_auth_mellon の設定をしていないため、SSO 認証無しです。


https://kcapp.example.com/

kcapp.example.comアクセス


https://kcapp.example.com/info.php

kcapp.example.com info.phpアクセス


OK!


SP:mod auth_mellon 設定

Apache の conf に mod_auth_mellon の設定を追加します。 ここでは、簡略化のため、既に最初から存在する defult-ssl.conf に VirtualHost の設定を追加します。

設定に指定されている各ファイルは、この後作成します。

# vi /etc/apache2/sites-available/default-ssl.conf
/etc/apache2/sites-available/default-ssl.conf
<IfModule mod_ssl.c>
	<VirtualHost *:443>
		ServerAdmin webadmin@kcapp.example.com
		ServerName kcapp.example.com
		DocumentRoot /var/www/html

		SSLEngine on
		SSLCertificateKeyFile /etc/apache2/saml/https_kcapp.example.com.key
		SSLCertificateFile /etc/apache2/saml/https_kcapp.example.com.cert
		<Location />
			# SAML認証に関するエンドポイントのパス
			# エンドポイント=IdPとSPがSAML認証の要求や応答をやり取りするためのURL
			MellonEndpointPath "/mellon"
			# IdPのメタデータファイルのパス
			# メタデータ=IdPやSPの設定や機能を記述したXMLファイル
			MellonIdPMetadataFile /etc/apache2/saml/idp_metadata.xml
			# SPの秘密鍵ファイルのパス
			# 秘密鍵=SAML認証の通信を暗号化するための鍵
			MellonSPPrivateKeyFile /etc/apache2/saml/https_kcapp.example.com.key
			# SPの証明書ファイルのパス
			# 証明書=SPの秘密鍵に対応する公開鍵を含むファイル
			MellonSPCertFile /etc/apache2/saml/https_kcapp.example.com.cert
			# SPのメタデータファイルのパス
			MellonSPMetadataFile /etc/apache2/saml/https_kcapp.example.com.xml

			# SAML認証を使用する
			AuthType "Mellon"
			Require valid-user
			# SAML認証を有効にする
			MellonEnable "auth"
		</Location>
	</VirtualHost>
...(既存設定)

SP:SAML 認証メタデータ作成

秘密鍵、証明書、SAML の詳細な設定を行うメタデータ(XML ファイル)の配置が必要になるのですが、mellon_create_metadata.sh を使って、一気に終わらせます。
そのため、メタデータの内容に関する説明は省略します。

# mkdir /etc/apache2/saml
# cd /etc/apache2/saml
# ENTITY_ID=https://kcapp.example.com
# BASE_URL=https://kcapp.example.com/mellon
# curl -O https://raw.githubusercontent.com/latchset/mod_auth_mellon/main/mellon_create_metadata.sh
# chmod 755 mellon_create_metadata.sh
# ./mellon_create_metadata.sh ${ENTITY_ID} ${BASE_URL}
Output files:
Private key:               https_kcapp.example.com.key
Certificate:               https_kcapp.example.com.cert
Metadata:                  https_kcapp.example.com.xml

Host:                      kcapp.example.com

Endpoints:
SingleLogoutService:       https://kcapp.example.com/mellon/logout
AssertionConsumerService:  https://kcapp.example.com/mellon/postResponse
# ls
https_kcapp.example.com.cert  https_kcapp.example.com.key  https_kcapp.example.com.xml  mellon_create_metadata.sh

【ENTITY_ID】

SAMLのEntity IDは、アプリケーション(SP)を一意に識別するためのものです。SAML 認証では、IdP と SP はそれぞれのメタデータを交換します。メタデータとは、IdP や SP の設定や機能を記述した XML ファイルです。メタデータには、ENTITY_ID が含まれており、IdP と SP が互いに認識するために使用されます。

URL形式であることが推奨されますが、URL形式であることは必須ではありません。

Keycloak で設定する Client ID と同一にします。(今回この後自動的に同一になります。)

【BASE_URL】

BASE_URL は、SP のエンドポイントのベースとなる URL です。エンドポイントとは、IdP と SP が SAML 認証の要求や応答をやり取りするための URL です。エンドポイントには、以下のような種類があります。

SingleLogoutService:ログアウト処理を行うエンドポイント

AssertionConsumerService:認証応答を受け取るエンドポイント

SingleSignOnService:認証要求を送るエンドポイント

BASE_URL は、アプリケーションで使用しない URL パスを指定する必要があります。

カレントディレクトリに
https_kcapp.example.com.cert
https_kcapp.example.com.key
https_kcapp.example.com.xml
が作成されます。


idp_metadata.xml がまだありません。Keycloak から取得します。
取得先は、https://kctest.contoso.com/realms/[Realm名(今回は、TestRealm)]/protocol/saml/descriptor です。

# curl -k -o /etc/apache2/saml/idp_metadata.xml \
https://kctest.contoso.com/realms/TestRealm/protocol/saml/descriptor

設定を反映します。

# systemctl reload apache2

IdP:Keycloak SAML 設定

Keycloak 管理コンソールにて、SAML クライアントの設定を行います。
ここまで、SAML クライアント、つまり、アプリ(SP)側の URL は、https://kcapp.example.com/ であるという前提として進めてきました。
SAML クライアント(mod_auth_mellon のサーバー)は既に構築済みのため、mod_auth_mellon のサーバーからクライアントメタデータをダウンロードして、それを Keycloak へインポートして登録します。
これにより、本来、Keycloak 管理コンソールで設定が必要な URL の設定や Signing keys config の登録など、省略することになります。


https://kcapp.example.com/mellon/metadata から SP のメタデータをダウンロードします。

SP のメタデータをダウンロード


Keycloak 管理コンソールから TestRealm に移動して、 Clients をクリックして、Import client をクリックします。

Import client


Browse... クリックし、先ほどダウンロードしたファイルを選択します。

Browse... クリック


ファイルを選択


インポートされるため、ひとまず、何も変更せずに、Save をクリックします。

Save クリック


Keycloak に SAML クライアントが登録されました。
その他、設定は全てデフォルトとします。
Valid redirect URIs は、認可後リダイレクトされる URI を入力します。デフォルトは、* です。
パスだけ設定する場合は、Root URL からの相対パスとなります。
今回、認可後リダイレクトされる URI は、https://kcapp.example.com/mellon/postResponse になるため、https://kcapp.example.com/mellon/postResponse が自動的に設定されています。

SAMLクライアント登録直後


SAML 認証動作確認

testuser でログインしてみます。

今回、単一アプリの認証が通ることだけ確認して、SSO の確認は行いません。


https://kcapp.example.com/ へアクセスします。

ユーザーサインイン画面


kcapp.example.comアクセス


↓(そのまま URL を書き換えて)

https://kcapp.example.com/info.php へアクセスします。

kcapp.example.com info.phpアクセス


OK!


今回の場合、SAML クライアントのメタデータをインポートしたため、特に問題無かったですが、手動でクライアントを登録する場合、以下の問題が発生するかもしれません。

 

/opt/keycloak/data/log/keycloak.log に以下のログが出力されている場合、Keycloak 側設定 Client ID と mod_auth_mellon で作成したメタデータの ENTITY_ID がずれている可能性があります。

2023-11-25 17:14:22,540 WARN [org.keycloak.events] (executor-thread-82) type=LOGIN_ERROR, realmId=167b42ad-a626-4475-9d32-3a8c97e8f6b3, clientId=null, userId=null, ipAddress=192.168.11.5, error=client_not_found, reason=Cannot_match_source_hash

 

以下の場合は、Signing keys config の Certificate が間違っている可能性があります。

2023-11-25 18:55:27,139 WARN [org.keycloak.events] (executor-thread-72) type=LOGIN_ERROR, realmId=be563de8-bb3d-49af-9073-1dfe8e859dfd, clientId=null, userId=null, ipAddress=192.168.11.5, error=invalid_signature

We are sorry...

 

その他、SP、IdP の時刻が大幅にずれていないか確認が必要です。


IdP:Keycloak SAML 同意画面

Keycloak の設定によって、同意画面(Consent)を表示することもできます。 Clientshttps://kcapp.example.comConsent requiredOn に設定して、Save をクリックします。

Consent required を On


アプリにログインしてみます。

ユーザーサインイン画面


同意画面(Consent)


同意画面が追加されました!


同意した事実は、Keycloak 管理コンソールから TestRealm に移動して、

UserstestuserConsents タブにて、確認できて、取り消すこともできます。(取り消すと、もう一度同意画面が出てきます。)

Consents確認


今回は、内部 DB にユーザー情報を登録していますが、Kerberos(Active Directory)や LDAP にもできます。

OpenLDAP を利用した例は、過去記事「Keycloak PostgreSQL OpenLDAP mod_auth_openidc で SSO 全手順」にあります。


IdP:Azure AD

Identity providers に Azure AD(Azure Active Directory/Microsoft Entra ID)を追加して、Azure AD のアカウントで認証するように変更していきます。
まず、Azure AD 側の設定を行います。


Azure ポータルから、Microsoft Entra ID に移動して、エンタープライズ アプリケーション をクリックします。

Microsoft Entra ID


エンタープライズ アプリケーション


+新しいアプリケーション をクリックします。

+新しいアプリケーション


+独自のアプリケーション作成 をクリックします。

+独自のアプリケーション作成


お使いのアプリの名前は何ですか?
のところを KeycloakTEST とします。
ギャラリーに見つからないその他のアプリケーションを統合します (ギャラリー以外) にチェックが入った状態とし、作成 をクリックします。

アプリケーション作成


シングル サインオンの設定 のところの 作業の開始 をクリックします。

シングル サインオンの設定


SAML をクリックします。

SAML


編集 をクリックします。

編集


識別子 (エンティティ ID):
https://kctest.contoso.com/realms/TestRealm


応答 URL (Assertion Consumer Service URL):
https://kctest.contoso.com/realms/TestRealm/broker/saml/endpoint
とし、保存 をクリックします。

識別子 (エンティティ ID)と応答 URL (Assertion Consumer Service URL)

識別子 (エンティティ ID)は、mod_auth_mellon で出てきた ENTITY_ID と考え方は同じで、一意の識別子です。何でも良いですが、この後 Keycloak の設定画面で初期設定された状態で表示されるのがこの URL です。

応答 URL (Assertion Consumer Service URL) もこの後 Keycloak の設定画面で固定のエンドポイント URL が表示されるからこの URL です。ここでは、両方分かっているものとします。


ここで、アプリのフェデレーション メタデータ URL をコピーして、メモっておきます。※後でも見に来れます。

アプリのフェデレーション メタデータ URL をコピー


ユーザーとグループ をクリックし、+ユーザーまたはグループの追加 をクリックします。

+ユーザーまたはグループの追加

しばらく待つか、一旦初期画面に戻って、KeycloakTEST を選択しなおさないといけないかもしれません。

続けて操作していた時、割り当てられず、エラーになりました。


割り当ての追加 画面に切り替わり、選択されていません をクリックします。

選択されていません


SAML 認証を使うユーザー/グループを選択し、選択 をクリックします。
今回は、すべてのユーザー にします。

すべてのユーザー


割り当て をクリックします。

割り当て


割り当て完了後


これで Azure AD 側は、準備完了です。


IdP/SP:Keycloak Identity providers 追加

Azure AD と紐づけて、IdP とします。
Keycloak を アプリにとっての IdP、Azure AD にとっての SP とします。


Keycloak 管理コンソールから TestRealm に移動して、
Identity providers をクリックして、SAML v2.0 をクリックします。

SAML v2.0


SAML entity descriptor の設定のところに、先ほど Azure AD に表示されていてコピーした アプリのフェデレーション メタデータ URL をペーストします。

アプリのフェデレーション メタデータ URL をペースト

ここで、Keycloak → https://login.microsoftonline.com/... とサーバーサイドでアクセスが行きます。
Keycloak がインターネットに出られない場合、プロキシ経由で出る必要があります。
No valid metadata was found at thie URL:'Network response was not OK.'
となった場合、そういうことです。

No valid metadata was found 図

プロキシ利用でOK 図


ここでは、プロキシ経由でインターネットへ出る設定を行います。
緑色のチェックマークが付いた場合、必要のない作業ですので、読み飛ばしてください。


# vi /etc/systemd/system/keycloak.service
/etc/systemd/system/keycloak.service
以下のように書き換え(http://192.168.0.158:3128 は、プロキシサーバーのこと)
ExecStart=/opt/keycloak/bin/kc.sh start --log=console,file
ExecStart=/opt/keycloak/bin/kc.sh start --log=console,file --spi-connections-http-client-default-proxy-mappings="'.*\\\.microsoftonline\\\.com;http://192.168.0.158:3128'"

余談ですが、マニュアルの Configuring outgoing HTTP requests(2023 年 11 月時点)に

bin/kc.[sh|bat] start --spi-connections-http-client-default-<configurationoption>=<value>

と説明があるのですが、proxy-mappings の具体的な記述例の

...-proxy-mappings="' の直後にドットが無く、これをベースに設定しても効きませんでした。ドットが必要でした。

マニュアルの Configuring outgoing HTTP requests ドットが必要

# systemctl daemon-reload
# systemctl restart keycloak.service

でプロキシが有効になり、緑色のチェックマークが付くはずです。

他の方法としては、keycloak.service の

[Service] セクションに

Environment="HTTP_PROXY=http://192.168.0.158:3128"

Environment="HTTPS_PROXY=http://192.168.0.158:3128"

Environment="NO_PROXY=.example.com,.contoso.com"

と記述してもプロキシ有効になりました。

※この場合、kc.sh start のオプションは変更不要です。


ここからは、プロキシうんぬん関係なく、共通の手順に戻ります。


SAML entity descriptor の URL が認識されたら、Add をクリックします。

SAML entity descriptor Add


いろいろ自動登録されますので、ひとまず、Save をクリックします。

Identity providers Save


SAML Azure AD 認証動作確認1

https://kcapp.example.com/ へアクセスすると、
Or sing in with
saml
が追加されていますので、saml をクリックします。

samlをクリック

saml の表記は、Keycloak の Identity providerssaml → General settings - Alias 設定の文字列になります。


Azure AD でおなじみのサインイン画面が表示されるようになります。


Azure ADサインイン画面1


Azure ADサインイン画面2


Azure ADサインイン画面3


ヨシ!っといきたいところですが、
Keycloak の Identity providerssaml → Advanced settings - First login flow
の設定が first broker login となっているため、最初に Username, Email, First name, Last name の登録を迫られます。

first broker loginフローの画面


今回は、ここで止まって欲しくないので、First login flow の設定を変更します。

First login flow は、ユーザーが初めて外部 IdP からログインした後に使用されるワークフローを選択します。

デフォルトでは、この設定は first broker login を指していますが、独自のフローを作成して設定することも可能です。


IdP/SP:Keycloak Flow 追加

First login flow に簡略化されたフローを指定したいため、オリジナルのフローを作成します。
※フローについての細かい説明は省略します。


Keycloak 管理コンソールから TestRealm に移動して、 Authentication をクリックして、Create flow をクリックします。

Create flow


Name に None を入力して、Create をクリックします。

Noneフロー Create


Add execution をクリックします。

Add execution


Create User If Unique にチェックを入れて、Add をクリックします。

Create User if Unique ステップは、Keycloak アカウント(今回は、testuser 一人)と email が一致した場合、そのユーザーと特定し、それ以外の場合は、新規に Keycloak アカウント 作成という意味です。

Create User If Unique Add


Requirement を Alternative と変更します。(変更した時点でシステムに反映されます。)

Alternative


再び、 Identity providerssaml → Advanced settings - First login flow に戻ると、None が選択可能になっているため、None を選択して、Save をクリックします。

Advanced settings - First login flow


SAML Azure AD 認証動作確認2

https://kcapp.example.com/ へアクセスし、saml をクリックします。

samlをクリック


Azure AD のサインイン画面が表示され、サインインします。

Azure ADサインイン画面1


Azure ADサインイン画面2


Azure ADサインイン画面3


同意画面(Consent)


kcapp.example.comアクセス


↓(そのまま URL を書き換えて)


https://kcapp.example.com/info.php へアクセスします。

kcapp.example.com info.phpアクセス


アプリが表示されました!
ヨシ!


しかし、実は、Keycloak の Users を見ると、Azure AD が決めた ID で強引に登録されています。誰が誰だか分かりません。

Users確認


・・・あとは頑張ればなんとかなりそうだし、ヨシ!


loading...