- 記事一覧 >
- ブログ記事
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
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 サーバーを設定して、時刻がずれないようにします。
#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
# データベースの種類=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
# 注意: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-file
とhttps-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
でログインできたら、ひとまずは、成功です。
ヨシ!
IdP:Keycloak サービス追加
./kc.sh --verbose start
で問題無いことが確認できたため、CTRL + C
で止めます。
systemctl
で keycloak を起動する設定を追加します。
# vi /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
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 をクリックします。
Realm name に作成するレルムの名前を入力して、Create をクリックします。
ここでは、TestRealm
とします。
IdP:Keycloak 一般ユーザー作成
レルム:TestRealm を選択して、Keycloak の DB(PostgreSQL)にユーザーを作成します。
ここで作成するユーザーは、レルム:TestRealm 内に作成された Keycloak 独自管理下のユーザーです。
Users をクリックして、Add user をクリックします。
Username に作成するユーザー名を入力します。
ここでは、testuser
とします。
確認メール不要としたいため、Email verified は、Yes
とします。
Create をクリックします。
Credentials タブをクリックして、パスワードを設定します。
Set password をクリックします。
設定したいパスワードを入力します。
ここで、Temporary を On
にすると、初回ログイン時にパスワードの変更を求められますので、Off
にしておきます。
Save をクリックします。
テストユーザーの準備完了です。
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
<?php
phpinfo();
ここまで実施して、動作確認します。 なお、この時点では、mod_auth_mellon の設定をしていないため、SSO 認証無しです。
https://kcapp.example.com/
https://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
<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 のメタデータをダウンロードします。
Keycloak 管理コンソールから TestRealm に移動して、 Clients をクリックして、Import client をクリックします。
Browse... クリックし、先ほどダウンロードしたファイルを選択します。
インポートされるため、ひとまず、何も変更せずに、Save をクリックします。
Keycloak に SAML クライアントが登録されました。
その他、設定は全てデフォルトとします。
Valid redirect URIs は、認可後リダイレクトされる URI を入力します。デフォルトは、*
です。
パスだけ設定する場合は、Root URL からの相対パスとなります。
今回、認可後リダイレクトされる URI は、https://kcapp.example.com/mellon/postResponse
になるため、https://kcapp.example.com/mellon/postResponse
が自動的に設定されています。
SAML 認証動作確認
testuser でログインしてみます。
今回、単一アプリの認証が通ることだけ確認して、SSO の確認は行いません。
https://kcapp.example.com/
へアクセスします。
↓(そのまま URL を書き換えて)
https://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
その他、SP、IdP の時刻が大幅にずれていないか確認が必要です。
IdP:Keycloak SAML 同意画面
Keycloak の設定によって、同意画面(Consent)を表示することもできます。
Clients → https://kcapp.example.com
→ Consent required を On
に設定して、Save をクリックします。
アプリにログインしてみます。
同意画面が追加されました!
同意した事実は、Keycloak 管理コンソールから TestRealm に移動して、
Users → testuser → 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 に移動して、エンタープライズ アプリケーション をクリックします。
+新しいアプリケーション をクリックします。
+独自のアプリケーション作成 をクリックします。
お使いのアプリの名前は何ですか?
のところを KeycloakTEST
とします。ギャラリーに見つからないその他のアプリケーションを統合します (ギャラリー以外)
にチェックが入った状態とし、作成 をクリックします。
シングル サインオンの設定 のところの 作業の開始 をクリックします。
SAML をクリックします。
編集 をクリックします。
識別子 (エンティティ ID):https://kctest.contoso.com/realms/TestRealm
応答 URL (Assertion Consumer Service URL):https://kctest.contoso.com/realms/TestRealm/broker/saml/endpoint
とし、保存 をクリックします。
識別子 (エンティティ ID)は、mod_auth_mellon で出てきた ENTITY_ID と考え方は同じで、一意の識別子です。何でも良いですが、この後 Keycloak の設定画面で初期設定された状態で表示されるのがこの URL です。
応答 URL (Assertion Consumer Service URL) もこの後 Keycloak の設定画面で固定のエンドポイント 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 entity descriptor の設定のところに、先ほど Azure AD に表示されていてコピーした アプリのフェデレーション メタデータ URL をペーストします。
ここで、Keycloak → https://login.microsoftonline.com/...
とサーバーサイドでアクセスが行きます。
Keycloak がインターネットに出られない場合、プロキシ経由で出る必要があります。
No valid metadata was found at thie URL:'Network response was not OK.'
となった場合、そういうことです。
↓
ここでは、プロキシ経由でインターネットへ出る設定を行います。
緑色のチェックマークが付いた場合、必要のない作業ですので、読み飛ばしてください。
# vi /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="'
の直後にドットが無く、これをベースに設定しても効きませんでした。ドットが必要でした。
# 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 をクリックします。
いろいろ自動登録されますので、ひとまず、Save をクリックします。
SAML Azure AD 認証動作確認1
https://kcapp.example.com/
へアクセスすると、
Or sing in with
saml
が追加されていますので、saml をクリックします。
saml の表記は、Keycloak の Identity providers → saml → General settings - Alias 設定の文字列になります。
Azure AD でおなじみのサインイン画面が表示されるようになります。
ヨシ!っといきたいところですが、
Keycloak の Identity providers → saml → Advanced settings - First login flow
の設定が first broker login
となっているため、最初に Username, Email, First name, Last name の登録を迫られます。
今回は、ここで止まって欲しくないので、First login flow の設定を変更します。
First login flow は、ユーザーが初めて外部 IdP からログインした後に使用されるワークフローを選択します。
デフォルトでは、この設定は
first broker login
を指していますが、独自のフローを作成して設定することも可能です。
IdP/SP:Keycloak Flow 追加
First login flow に簡略化されたフローを指定したいため、オリジナルのフローを作成します。
※フローについての細かい説明は省略します。
Keycloak 管理コンソールから TestRealm に移動して、 Authentication をクリックして、Create flow をクリックします。
Name に None
を入力して、Create をクリックします。
Add execution をクリックします。
Create User If Unique
にチェックを入れて、Add をクリックします。
Create User if Unique ステップは、Keycloak アカウント(今回は、
testuser
一人)と email が一致した場合、そのユーザーと特定し、それ以外の場合は、新規に Keycloak アカウント 作成という意味です。
Requirement を Alternative
と変更します。(変更した時点でシステムに反映されます。)
再び、
Identity providers → saml → Advanced settings - First login flow
に戻ると、None
が選択可能になっているため、None
を選択して、Save をクリックします。
SAML Azure AD 認証動作確認2
https://kcapp.example.com/
へアクセスし、saml をクリックします。
Azure AD のサインイン画面が表示され、サインインします。
↓(そのまま URL を書き換えて)
https://kcapp.example.com/info.php
へアクセスします。
アプリが表示されました!
ヨシ!
しかし、実は、Keycloak の Users を見ると、Azure AD が決めた ID で強引に登録されています。誰が誰だか分かりません。
・・・あとは頑張ればなんとかなりそうだし、ヨシ!
その他、宣伝、誹謗中傷等、当方が不適切と判断した書き込みは、理由の如何を問わず、投稿者に断りなく削除します。
書き込み内容について、一切の責任を負いません。
このコメント機能は、予告無く廃止する可能性があります。ご了承ください。
コメントの削除をご依頼の場合はTwitterのDM等でご連絡ください。