Keycloakを用いて外部ID連携を試してみる

**本記事は以下のような読者を想定しています**

- 認証認可の初学者
- Keycloak と Azure AD をID連携させたい方


はじめに
---

本記事では **Keycloak を用いて外部ID連携を実装** します。
ID連携というのは自サービスのユーザー認証を外部へ任せることです。例えば本記事内でも使用する Keycloak というソフトウェアを用いると自社サービスへアクセスするためのユーザー認証を Google や Facebook などのアカウント提供者に任せることができます。

ID連携をすることで例えば以下のようなメリットが得られます。

- ユーザー自身が管理するID/PWが少なくなる。
- アカウント管理の負担が減る。

ここでは Keycloak と　Azure AD を用いてID連携をしてみたいと思います。TwitterやGoogleなどのアカウントを用いたソーシャルログインやLDAPサーバーを用いたID連携の記事は既にあるのですが、Azure AD と連携させた記事がなかったため、こちらを使用することにしました。そのため Keycloak と Azure AD との**連携手順を示すという技術検証が主な目的**となります。
下図が制作物のイメージになります。
Azure AD 内に作成したユーザーを用いて認証の必要なWebページにログインできるようになっています。

![overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/7716c43b-a780-daf3-cf17-b5fd34b7c4a5.png)

今回の検証で使用する [Keycloak](https://www.keycloak.org/) はオープンソースのアイデンティティ・アクセス管理ソフトウェアで、こちらの記事（[Keycloakとは](https://qiita.com/daian183/items/30f01e162e03567ff21b)）で概要がつかめるかと思います。Azure AD は主にクラウドサービス向けのアイデンティティ・アクセス管理サービスです。Azure AD の概要については [Azure Active Directory とは](https://docs.microsoft.com/ja-jp/azure/active-directory/fundamentals/active-directory-whatis) をご覧ください。

また、こちらが完成形のgifアニメーションになります。以下のステップで認証の必要なWebページへアクセスできる様子が確認できます。

1. 認証が必要なプライベートページ（Apacheにて提供）にアクセス
2. 「Azure AD」のログインボタンが表示される
3. Azure AD のログイン画面に飛ばされる
4. Azure AD に登録したユーザーを用いてログイン
5. プライベートページへのアクセスが許可される

![demo2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/208ec006-248e-a216-4973-5b1327eb98d4.gif)

**目標**
今回の検証を行うにあたり、下記項目を達成することを目標とします。

- 認証プロトコルである OpenID Connect の認証フローを理解する
- Apache 上に認証が必要なページ作成し、Keycloak 内に作成したユーザーでログインしてアクセスする。
- Keycloakの基本的な扱い方を習得する
- 外部ID連携とはどのようなものかを理解し、実際に Keycloak と Azure AD を連携させてみる。

本記事は初学者を対象としているため、手順を1から10まで示し、不明点を調べるための労力を最小限に抑えられるように心がけています。分かりにくい、分からないといった点がありましたら編集リクエストをお願いします。

## 1. 制作物の概要
### 1.1 ID連携の全体像
本記事における登場人物は以下の4名です。

- ユーザー
- Apache Httpd (RP : Relying Party)
- Azure AD (OP : OpenID Provider)
- Keycloak (RP 兼 OP)

ここで、RPやOPといった呼称は [OpenID Connect](http://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html) のプロトコルで定義されており、RPは認証される側、OPは認証する側を表します。Keycloak は Apache から見ると OP であり Azure AD から見ると RP の役割を果たします。
RP、OP は [OAuth2.0](https://openid-foundation-japan.github.io/rfc6749.ja.html) の認証プロトコル内では別の表記が使われており、OpenID Connectとの対応は以下のようになっています。

|  | OpenID Connect | OAuth2.0 |
|:--|:-:|:-:|
| 認証される側 | Relying Party (RP) | Client |
| 認証する側 | OpenID Provider (OP) | Authorization Server |

下図が本記事で制作するものの概略図です。認証フローの詳細については [3.1 OpenID Connect の認証フロー](#31-openid-connect-の認証フロー) をご参照ください。
構築までの全体の流れとしては次のようになります。

1. Apache でWebサーバーを建てる
2. Keycloakサーバーを建てる
3. AzureAD のテナントを作成して Keycloak と連携させる
4. AzureAD に登録したユーザーを用いてApacheのリソースにアクセスする

![Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/2f5a4b5a-16b9-6ae9-39b4-a3319654ae22.png)

ユーザーのアカウント情報は Azure AD 内にて管理されており、Keycloak はユーザーの認証を Azure AD に委譲します。従ってこのシステムにおいて Keycloak は仲介者の役割を果たします。このようなKeycloakの機能は [Identity Broker](https://keycloak-documentation.openstandia.jp/review/ja_JP/server_admin/#_identity_broker) と呼ばれます。

### 1.2 開発環境
使用したソフトウェアの一覧を示します。

| ソフトウェア | バージョン | 備考 |
|:--|:-:|:-:|
| Ubuntu Server | 18.04 LTS | ホスト名 : hostname |
| Apache Httpd | 2.4.29 |   |
| Keycloak | 11.0.2 |   |
| openjdk | 11.0.8 |   |
| PHP | 7.2.24 | ヘッダー情報を表示するために使用するのでOptional |

## 2. 環境構築
本章ではID連携を実現するために必要な Apache と Keycloak の環境構築を行います。
![Qiita_sec2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/9502ca67-c094-0fb1-e312-b3988ee81fcc.png)

### 2.1 Apache Httpd のインストール
はじめに、認証が必要なWebページをホストするため [Apache Httpd](https://httpd.apache.org/) をインストールします。

```bash:ApacheHttpdのインストール
$ sudo apt update
$ sudo apt install apache2
```

インストールが完了したら下記URLからデフォルトページにアクセスしてみます。なお、このとき表示されるデフォルトページは`/var/www/html/index.html`です。

Apacheのデフォルトページ ： http://hostname/

このようなページが表示されるとOKです。
<img width="50%" alt="apache_default_page.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/d5c2ead9-9470-f1e5-1f0d-681ceff35841.png">
[](![apache_default_page.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/d5c2ead9-9470-f1e5-1f0d-681ceff35841.png))

現状では Apache 上のリソースに http でしかアクセスできないので、https でこのページにアクセスできるようにモジュール (mod-ssl) を有効化します。https の設定は、後に Azure AD を連携させるために必須となります。
下記コマンドで mod-ssl を有効化すると、https で Apache のデフォルトページにアクセスできるようになります。

```bash:mod-sslの有効化
$ sudo a2enmod ssl
$ sudo a2ensite default-ssl
$ sudo systemctl restart apache2
```
http を https に書き換えた URL ([https://hostname/](https://hostname/)) にアクセスしてみます。
今回は外部SSL証明書を使用していないので警告画面が表示されますが Apache のデフォルトページが表示されるかと思います。

以上で Apache の準備は完了です。

### 2.2 Keycloakのインストール
つぎに [Keycloak](https://www.keycloak.org/) をインストールします。 Keycloakのインストールは [公式サイトのチュートリアル](https://www.keycloak.org/getting-started/getting-started-zip) にしたがって進めていきます。

まず Keycloak を使用するためには OpenJDK が必要なのでインストールします。ここでは keycloak-11.0.2 を使用しているため OpenJDK 1.8 以降のバージョンが必要となります。

```bash:OpenJDKのインストール
$ sudo apt install default-jdk
$ java --version
openjdk 11.0.8 2020-07-14
OpenJDK Runtime Environment (build 11.0.8+10-post-Ubuntu-0ubuntu118.04.1)
OpenJDK 64-Bit Server VM (build 11.0.8+10-post-Ubuntu-0ubuntu118.04.1, mixed mode, sharing)
```

OpenJDK がインストールできたら次に Keycloak をインストールします。
Keycloak のインストールは下記コマンドでバイナリファイルをダウンロードして展開するだけです。

```bash:Keycloakのインストール
$ wget -P /tmp/ https://downloads.jboss.org/keycloak/11.0.2/keycloak-11.0.2.tar.gz
$ sudo tar -xzvf /tmp/keycloak-11.0.2.tar.gz -C /opt/
$ ls /opt
keycloak-11.0.2
```

ファイルの展開が完了したら早速起動してみます。

```bash:Keycloakの起動
$ cd /opt/keycloak-11.0.2
$ bin/standalone.sh -b 0.0.0.0
```

`-b 0.0.0.0`のオプションは localhost 以外のドメインを使用してのアクセスを許可するために必要です。

起動できたら、下記URLにアクセスしてみます。http、https のどちらでも良いですが、本記事ではこれ以降 https に統一します。
なお、Keycloak のデフォルトのポート番号は `http:8080`、`https:8443` です。
http://hostname:8080/auth
https://hostname:8443/auth

このように「Welcome to Keycloak」のページが表示されるかと思います。
<img width="50%" alt="welcome_to_keycloak.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/1e10019d-21d4-bae6-1e01-f1f62c05758e.png">
[](![welcome_to_keycloak.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/1e10019d-21d4-bae6-1e01-f1f62c05758e.png))

Keycloak の動作確認はできましたが、毎回 `bin/standalone.sh` で起動するのは面倒なので Keycloak をサービスへ登録します。
`Ctrl+C`で一度　Kycloak　を終了させて serviceファイルを作成します。

```bash:keycloak.serviceファイルの作成
$ sudo vi /etc/systemd/system/keycloak.service
```

keycloak.service に以下のように記述します。
ディレクトリ名の `keycloak-11.0.2` やユーザー名、グループ名は適宜変更してください。

```:/etc/systemd/system/keycloak.service
[Unit]
Description=Jboss Application Server
After=network.target

[Service]
Type=idle
Environment=JBOSS_HOME=/opt/keycloak-11.0.2
JBOSS_LOG_DIR=/var/log/keycloak "JAVA_OPTS=-Xms1024m -Xmx20480m -XX:MaxPermSize=768m"
User=ubuntu
Group=ubuntu
ExecStart=/opt/keycloak-11.0.2/bin/standalone.sh -b=0.0.0.0
TimeoutStartSec=600
TimeoutStopSec=600

[Install]
WantedBy=multi-user.target
```

記述できたら保存してサービスを開始します。

```bash:keycloak.serviceの開始
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now keycloak
$ systemctl status keycloak
```

### 2.3 Keycloakの管理者アカウントの作成
ここでは Keycloak の管理者ユーザーを作成します。以下のコマンドを実行して管理者を作成します。ユーザー名とパスワードはどちらも`admin`としておきます。
`master`というのは管理者用の Realm を指しています。

- username : `admin`
- password : `admin`

```bash
$ bin/add-user-keycloak.sh -r master -u admin -p admin
$ sudo systemctl restart keycloak
```

Keycloak の管理者コンソール ([https://hostname:8443/auth/admin](https://hostname:8443/auth/admin)) へアクセスします。

管理者コンソールは、デフォルトでは https でしかアクセスできないですが以下のコマンドを実行することで http でもログインできるようになります。
特に必要がなければ設定しなくても大丈夫です。

```bash:管理者コンソールへhttpでアクセスする
$ bin/kcadm.sh config credentials --server http://hostname:8080/auth --realm master --user admin --password admin
$ bin/kcadm.sh update realms/master -s sslRequired=NONE
```

管理者コンソールへアクセスするとログイン画面が出てくるので、先ほど作成した管理者アカウントでログインします。

- username : `admin`
- password : `admin`

<img width="60%" alt="keycloak_admin_login.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/7e972237-efae-62eb-b0a1-940d329de6bf.png">
[](![keycloak_admin_login.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/7e972237-efae-62eb-b0a1-940d329de6bf.png))

ログイン後、このよう管理者用のページが表示されると管理者の作成は完了です。
<img width="60%" alt="keycloak_admin_login_page.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/ef01beea-91ed-3e52-def2-4f07d771ed07.png">
[](![keycloak_admin_login_page.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/ef01beea-91ed-3e52-def2-4f07d771ed07.png))

### 2.4 Realmとログインユーザーの作成
Keycloak では Realm と呼ばれる単位でユーザーの管理等をします。
Realm について公式サイトでは次のように説明されています。

> realms
> A realm manages a set of users, credentials, roles, and groups. A user belongs to and logs into a realm. Realms are isolated from one another and can only manage and authenticate the users that they control.
> https://www.keycloak.org/docs/latest/server_admin/ より引用

Realm とユーザーの作成方法は [公式サイト](https://www.keycloak.org/getting-started/getting-started-zip) にも載っているので、ここでは簡単に説明します。

まず管理者コンソールの左上にある `Master` から `Add realm` を選択し、新規に Realm を作成します。
<img width="75%" alt="keycloak_add_realm.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/ee51e2a9-1c9f-9f9a-4c8c-6fbad2c59220.png">

本記事では下図のように、 Realm 名を `myrealm` として作成します。
<img width="35%" alt="keycloak_add_myrealm.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/2a035c4d-b9d2-4b05-566a-3a5aa24fc1f5.png">

以上で Realm の作成は終了です。
ついでに、今作成した Realm に検証用のユーザーを作成します。
左側のメニューから `Users` > `Add user` を選択します。
<img width="60%" alt="keycloak_add_user.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/cd0a43a1-ca76-b20b-f63d-51e884b6ad4b.png">

ここでは下記テストユーザーを作成しました。
username : `testuser`
password : `password`

なお、パスワードの設定は `Credentials` タブから行えます。
初回ログイン時のパスワード変更を無効にするため`Temporary`は`OFF`にセットします。
<img width="60%" alt="keycloak_add_user_password.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/85517c1a-f998-7f24-2a87-55326cd4271d.png">

設定を保存して検証用ユーザーの作成は完了です。


## 3. クライアントの作成
本章では Keycloak のクライアントとして Apache を登録します。
これにより Apache は Keycloak へユーザーの認証を要求することが可能となります。

![Qiita_sec3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/af98a700-fe17-b0bb-7a21-4f54ffc9b034.png)

### 3.1 OpenID Connect の認証フロー

クライアントを作成する前に、本記事で利用する OpenID Connect の認証フローを確認しておきます。
認証フローは下の図のようになり、Apache-Keycloak間、Keycloak-AzureAD間でそれぞれ認可コードフローが利用されます。
Keycloak は Apache から見ると OP、Azure AD から見ると RP になります。また Apache と Azure AD との直接の通信がないため、 Apache は Azure AD の存在を気にする必要はありません。

![OIDC_Flow_v2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/86cb8fda-03c3-9b8b-8b0e-7278a3157b85.png)


図中に示される各エンドポイントは、それぞれ次のような役割を持っています。
- Authorization Endpoint : 認可コードを得るためのURIエンドポイント
- Token Endpoint         : 認可コードとトークンを交換するためのURIエンドポイント

簡単に流れを追うと次のようになります。

| 番号 | 概要 |
|:-:|:--|
| (1) | ユーザーがリソースへのアクセスを要求 |
| (2) | Apache はユーザーを Keycloak へリダイレクト |
| (3) | Keycloak は Azure AD のログインボタンを提示 |
| (4) | ユーザーは Azure AD でのログインを選択 |
| (5) | Keycloak は Azure AD に認証を委譲し、ユーザーを Azure AD のログイン画面へリダイレクト |
| (6) | ユーザーはクレデンシャル(ID/PW)を提示して認証を行う |
| (7) | 認証が成功すると Azure AD はユーザーに認可コード(Authorization Code)を付与してリダイレクトにより Keycloak へ戻す |
| (8)-(9) | Keycloak は認可コードを用いて Azure AD からIDトークン/アクセストークンを取得 |
| (10) | Keycloak は取得したトークンを検証 |
| (11)-(13) | は上記のKeycloak-AzureAD間と同様の流れで、Apache は Keycloak からIDトークン/アクセストークンを得る |
| (14) | Apache はIDトークンをもとにユーザーにアクセス許可を与える |


### 3.2 Keycloak に Apache を登録

myrealm のメニューから `clients` > `Create` を選択します。
<img width="80%" alt="keycloak_create_client.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/4789260c-705e-f051-8578-122e74c0781b.png">

クライアント名を適当に設定し、プロトコルを選択して保存します。
Client ID : `apachehttp`
Client Protocol : `openid-connect`

<img width="80%" alt="keycloak_create_client2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/02ac6ace-3647-5775-87cc-cb09f7c63e01.png">


作成されたクライアントの設定画面でアクセスタイプとリダイレクトURIを以下のように設定します。
この Redirect URIs は認証が成功したときに使用され、 [3.1 OpenID Connect の認証フロー](#31-openid-connect-の認証フロー) の図中における(11)に相当します。
Access Type   : `confidential`
Redirect URIs : `https://hostname/private/callback`
 
<img width="70%" alt="keycloak_create_client_setting.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/11a7d98a-7aa8-0614-755c-e47575d76fef.png">

｀Access Type` を `confidential` に変更し、一度変更を保存すると`Credentials`タブが現れるのでSecretをコピーしておきます。このSecretはクライアントを認証するためのものでランダムな値です。
以下の情報は後にApache側の設定で使用します。

 - client : `apachehttp`
 - secret : `354faff6-9a5c-45b7-8da4-62194804b793`

![keycloak_create_client_credentials.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/9909025b-6006-0827-fb6f-2dd930d476d8.png)

### 3.3 ApacheをKeycloakのクライアントとして設定
Apache はデフォルトでは OpenID Connect に対応していないので mod-auth-openidc をインストールして有効化します。
mod-auth-openidc が　Apache　の代わりに OpenID Connect の通信を担ってくれます。

```bash:mod-auth-openidcのインストールと有効化
$ sudo apt install libapache2-mod-auth-openidc
$ sudo a2enmod auth_openidc
$ sudo systemctl restart apache2
```

つづいて、mod-auth-openidc の confファイルを編集し、Keycloak のクライアントとして使用できるように設定します。

```bash:confファイルの編集
$ sudo vi /etc/apache2/mods-enabled/auth_openidc.conf
```

confファイルの末尾に以下を追記します。

```xml:/etc/apache2/mods-enabled/auth_openidc.conf

OIDCProviderMetadataURL       https://hostname:8443/auth/realms/myrealm/.well-known/openid-configuration
OIDCClientID                  apachehttp
OIDCClientSecret              354faff6-9a5c-45b7-8da4-62194804b793
OIDCResponseType              code
OIDCScope                     "openid"
OIDCSSLValidateServer         Off
OIDCProviderTokenEndpointAuth client_secret_basic

OIDCRedirectURI               https://hostname/private/callback
OIDCCryptoPassphrase          passphrase
OIDCPreservePost              On

# 認証が必要なディレクトリを設定
<Location /private>
   AuthType         openid-connect
   Require          valid-user
</Location>

# 認証が不要なディレクトリを設定
<Location /public>
   OIDCUnAuthAction pass
   AuthType         openid-connect
   Require          valid-user
</Location>
```

それぞれのパラメータの意味は次のとおりです

| パラメータ名 | 意味 |
|:--|:--|
| OIDCProviderMetadataURL | OIDCプロバイダのメタデータURL。このURLにアクセスするとエンドポイントなどの情報を見ることができる。 |
| OIDCClientID | OIDCのクライアントID |
| OIDCClientSecret | OIDCのクライアントSecret |
| OIDCResponseType | どのOIDCフローを使うか。デフォルトは"code"で、サポートされているフローについては OIDCProviderMetadataURL から "response_types_supported" の項目で確認可能。 |
| OIDCScope | 取得する認証情報/ユーザー情報の部分集合を指定。デフォルトは"openid"でこちらも OIDCProviderMetadataURL から "claim_types_supported" の項目で確認可能。 |
| OIDCSSLValidateServer | SSLサーバー証明書の検証を行うか否か。デフォルトは"On"ですが、今回は検証なので"Off"と設定。 |
| OIDCProviderTokenEndpointAuth |  トークンエンドポイントの認証方法。デフォルトは"client_secret_basic" |
| OIDCRedirectURI | OIDCクライアントへのリダイレクトURI。認証が成功したときに使用され、 [3.1 OpenID Connect の認証フロー](#31-openid-connect-の認証フロー) の図中における(11)に相当。 |
| OIDCCryptoPassphrase | cookieとキャッシュエントリの暗号化に使用する文字列 |
| OIDCPreservePost | POSTデータを保存するか否か。デフォルトは"Off" |

また、`/private` 以下のリソースへのアクセスは認証が必要で、`/public` 以下のリソースへはアクセスの認証が不要であるように設定しています。これらのディレクトリは後ほど作成します。

追記したら保存し、 Apache を再起動させます。

```bash:Apacheの再起動
$ sudo systemctl restart apache2
```

ここでアクセス先のリソースを `/public` と `/private` のディレクトリに用意します。

```bash
$ sudo mkdir /var/www/html/public
$ sudo sh -c "echo '<h1>Welcome to public page</h1>' > /var/www/html/public/index.html"

$ sudo mkdir /var/www/html/private
$ sudo sh -c "echo '<h1>Welcome to private page</h1>' > /var/www/html/private/index.html"
```

では、以下のページにアクセスしてみます。
認証なし： https://hostname/public/
認証あり： https://hostname/private/

認証の必要な `/private` へアクセスすると、Keycloak のログイン画面へ遷移します。
ここで先ほど作成した下記検証用ユーザーでログインするとprivateページが表示されるかと思います。
Chromeを使用していてログインできないという方はブラウザを変えてみてください。mod_auth_openidc と Chrome の互換性の問題 （[mod_auth_openidcとChromeのバージョン問題（SameSite=Noneの互換性）](https://qiita.com/henatyokotraveler/items/1906d2e3b18ab1ddfe99)）に引っかかっている可能性があります。

username : `testuser`
password : `password`

<img width="50%" alt="apache_login_private.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/d1e537a2-4c84-148b-77c5-1cf8a2432f8a.png">

アクセスできました。
なお、上記の検証用ユーザーは Keycloak 内に作成したものであり Azure AD 内のユーザーではありません。Azure AD 内のユーザーを用いたログインは次のセクションで行います。
<img width="50%" alt="apache_login_private_page.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/b4266168-00dd-cc35-6c62-e092cc442899.png">


## 4. AzureADとKeycloakのID連携の設定
本章では Keycloak のIDプロバイダ(IdP)として、Azure AD と連携させます。
前準備として Azure 上で Active Directory のテナントを作成しておきます。ここではテナント作成時に設定するOrganization名は `tenantname` としています。

![Qiita_sec4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/ebb84370-fcc0-ad1d-a18a-655233b81708.png)

### 4.1 AzureADへのアプリケーション登録

作成した Azure AD のテナントにアクセスします。
<img width="60%" alt="azure_ad.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/f5ee1d6d-4879-8271-0393-d662f3b77dbf.png">

左のメニューから `App registrations` > `New resistration` を選択します。
<img width="60%" alt="azure_ad_appregistration.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/80f09168-f675-22ec-6f20-be27484f43d6.png">

適当にアプリケーション名を設定して登録を完了します。
ここでは `KeycloakIdp` としていますが、自分で認識できる名前であればなんでも良いです。
<img width="60%" alt="azure_ad_register.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/00c3d7a7-f8aa-adaf-7bb4-13ebc9a4fddd.png">

### 4.2 Keycloak へ AzureAD の設定を追加

Keycloak に Azure AD を登録するためのIDプロバイダーを作成します。管理者画面から `Identity Providers` > `OpenID Connect v1.0` を選択します。

IDプロバイダーを作成すると設定画面が出てくるので適当にAlias名を設定します。ここでは以下のようにしておきます。
Alias : `AzureAD`
このときAlias名にスペースが入らないように注意してください。スペースが入っていると後に出てくる Redirect URL にもスペースが入り、Azure AD 側で正しく認識してくれません。

<img width="60%" alt="keycloak_idp_create.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/d2389dd1-1a8a-98f2-b3b8-46002c04a02d.png">

Alias名を設定した後、`Redirect URI` をコピーしておきます。
ここで Redirect URL が `https://` または `http://localhost` で始まっていることを確認してください。`http://` であるなら、再度httpsで管理者コンソールへログインし直します。これは Azure AD で設定できる Redirect URI に制限があるためです。
この Redirect URI は Azure AD でのユーザー認証が成功した際のレスポンスに使用され、 [3.1 OpenID Connect の認証フロー](#31-openid-connect-の認証フロー) の図中における(7)に相当します。

続いて今コピーした Redirect URI を Azure AD へ登録します。
Azure AD の画面から、`Add a Redirect URI` を選択します。
<img width="60%" alt="azure_ad_set_redirecturl.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/3671147e-b425-6d9c-3ad7-072cfe25f74b.png">

`Add Platform` > `web` の順番で選択します。
<img width="40%" alt="azure_ad_set_app.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/59c41993-1d3f-a463-9b76-68d109ca0108.png">

<img width="40%" alt="azure_ad_set_app_config.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/9c64b438-edf6-d5f8-69ab-80bb75af080e.png">

Redirect URI の設定画面が出てくるので、先ほど Keycloak のIDプロバイダー画面でコピーした Redirect URL を設定します。
最後に `Cinfigure` ボタンを押して設定を保存します。

<img width="60%" alt="azure_ad_set_redirecturl_ok.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/2ec28578-d9fb-e9ef-cab7-f39972999fad.png">

つぎに Azure AD の情報を Keycloak に登録するため、Azure AD の画面から `Endpoint` を選択します。
<img width="60%" alt="azure_ad_endpoint.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/06994d5d-b576-50d3-769e-8776484482b8.png">

下の図のように、各プロトコルのエンドポイントが表示されるので、`OpenID Connect metadata document` のエンドポイントをコピーします。
このエンドポイントには Azure AD の情報が格納されており、アクセスすると "token_endpoint"、"authorization_endpoint"、"response_types_supported"、"scopes_supported"などの情報を確認できます。
<img width="60%" alt="azure_ad_endpoint_copy.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/87f11bf1-3099-d5b0-4d9b-03d1975233fa.png">

再び Keycloak の Identity Provider の画面に戻り、設定の最下部にある `Import from URL` へコピーしたURLを入力し、`Import` ボタンを押します。
<img width="60%" alt="keycloak_azuread_import.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/4a8cca78-a660-9bf5-f47b-468ebf121f8b.png">

Importが成功すると、設定が自動で入力されます。
残りの必須項目は以下の通り入力します。

- Client Authentication : `Client secret sent as basic auth`
- Client ID : Azure AD に表示されている値をコピー&ペースト(下図)
- Client Secret : Azure AD 上で以下の手順で作成したもの

![keycloak_azuread_appid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/717efa85-d700-5ca7-74ec-6e588c8fceaa.png)

Azure AD で Secret key を取得するため、メニュー中の `Certificates & secrets` > `New client secret` を選択します。

<img width="60%" alt="keycloak_azuread_make_secret.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/e928d085-d45e-ba79-36b7-3615c220c503.png">

必要な設定は特にないのでそのまま `Add`。必要であればDescriptionを記入してください。
<img width="60%" alt="keycloak_azuread_make_secret2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/c58f9638-fcf1-2218-de46-39a1e71d394e.png">

Client Secret が作成されるので Keycloak のIDプロバイダーの設定画面にコピペします。以上で Keycloak の設定は終了なので、このまま保存します。

<img width="100%" alt="keycloak_azuread_make_secret_ok.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/e98c3b98-c520-b322-daf6-846b50ec8002.png">

### 4.3 Azure上でログインユーザーの作成
ここではAzure AD に新しいユーザーを作成します。
メニューの`Users` タブから `New user` を選択してユーザーを追加します。
<img width="60%" alt="azure_ad_user_add.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/aef52b33-7af7-55b8-6fab-c6d5e28635b7.png">

以下の通りでユーザーを作成しました。
User name : `idpuser`
Name      : `test name`
Password  : `Keycloak0`

<img width="60%" alt="azure_ad_user_add2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/bd683a5e-493e-2972-24cb-a72543a8dbba.png">

`Create`ボタンを押すと新しいユーザーの作成は完了です。

### 4.4 連携の確認

https://hostname/private
へアクセスします
するとログイン画面に `Azure AD` と表示されていることがわかります。
<img width="50%" alt="azure_ad_login.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/ab65de77-4d15-0a9c-7682-4ddd56e05c40.png">

表示されている `Azure AD` ボタンをクリックすると Azure AD のログイン画面が表示されるので、先ほど Azure AD 内に作成した下記のユーザーでログインします。ユーザー名には`@`以降も必要ですので注意してください。また、初回ログインではパスワードの変更を求められるので適当に変更します。

Username : `idpuser@tenantname.onmicrosoft.com`
Password : `Keycloak0`

ユーザー情報のアップデートも求められるので、適当に入力してアップデートします。
するとprivateページが表示されます。
<img width="50%" alt="apache_login_private_page.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/923e60ec-0f2a-19be-6602-c5ecaaddb03f.png">


以上で Keycloak と Azure AD の認証連携は全て完了です。

なお、Azure AD で管理されているユーザーでログインした際、Keycloak のデフォルトの動作では下図のようにユーザー情報は Keycloak 内のデータベースへ登録されます。
<img width="70%" alt="enrolled_user.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/27daa530-e92f-36d0-f018-6193f6f81415.png">

今回、Keycloak は email または username によりアカウントの紐づけを行っていますが、これらの情報が衝突した時、Keycloakは下2つの選択肢を提示します。
・アカウント情報のアップデートを要求する。
・アカウントを既存のアカウントに紐付ける。

例えば Keycloak 内に登録した usename と同一の username を持つ Azure AD のユーザーでログインしたとき、Keycloak は下のようなページを表示します。
<img width="50%" alt="user_conflict.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/ca1c991c-8e86-fd1d-3aff-267fcdefd87e.png">

ただし、これは Keycloak のデフォルトの挙動であり、カスタマイズ可能なポイントとなっています。詳細は下記URLをご確認ください。
https://keycloak-documentation.openstandia.jp/review/ja_JP/server_admin/#_identity_broker_first_login


## 5. HTTPヘッダーの表示（Optional）
[3.1 OpenID Connectの認証フロー](#31-openid-connect-の認証フロー)の図中(8)(9)(12)(13)で取得したIDトークンにはユーザーの認証情報が含まれています。そこで本章では Keycloak から Apache へ渡されるIDトークンにどのような認証情報が含まれているかを確認します。
具体的には、php を用いてhttpヘッダー情報を表示することによりこれを確認します。

なおhttpヘッダーへの情報の埋め込みは mod_auth_openidc によって行われます。ヘッダーへ情報を埋め込むか埋め込まないか等の設定ついては mod_auth_openidc のconfファイルに下記のような設定項目があります。
( https://github.com/zmartzone/mod_auth_openidc/blob/master/auth_openidc.conf )

```:auth_openidc.conf
# Define the way in which the claims and tokens are passed to the application environment:
# "none": no claims/tokens are passed
# "environment": claims/tokens are passed as environment variables
# "headers": claims/tokens are passed in headers (also useful in reverse proxy scenario's)
# "both": claims/tokens are passed as both headers as well as environment variables (default)
# When not defined the default is "both"
# The access token is passed in OIDC_access_token; the access token expiry is passed in OIDC_access_token_expires.
# The refresh token is only passed in OIDC_refresh_token if enabled for that specific directory/location (see: OIDCPassRefreshToken)
#OIDCPassClaimsAs [none|headers|environment|both]
```

### 5.1 phpのインストール
はじめに下記コマンドで Apache に php と mod-php をインストールします。

```bash:php/mod-phpのインストール
$ sudo apt install php libapache2-mod-php
```

インストールが完了したら php の動作確認のため`phpinfo.php`ファイルを作成してこちらのページにアクセスします。

```bash:phpinfo.phpの作成
$ sudo vi /var/www/html/public/phpinfo.php
```

```php:/var/www/html/public/phpinfo.php
<?php
phpinfo();
?>
```

phpinfo.phpのページ (https://hostname/public/phpinfo.php) にアクセスして下の画面が表示されると php の動作確認は完了です。

<img width="60%" alt="phpinfo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/49ef7692-123f-d56f-cb9c-4be7e7aa3da9.png">

### 5.2 HTTPヘッダーを表示する

php の動作確認ができたので、httpリクエストとレスポンスのヘッダ情報を表示させてみます。
先ほどと同様にして`headers.php`ファイルを作成し、そこにヘッダー情報を取得するphpを記述します。

```bash:headers.phpの作成
$ sudo vi /var/www/html/private/headers.php
```

```php:/var/www/html/private/headers.php
<?php
echo "</br>----- REQUEST HEADERS -----</br>";
foreach (apache_request_headers() as $name => $value) {
    echo ">> $name : $value </br>";
}

echo "</br>----- RESPONSE HEADERS -----</br>";
flush();
foreach (apache_response_headers() as $name => $value) {
    echo ">> $name : $value </br>";
}
?>
```

記述できたら保存して、headers.php (https://hostname/private/headers.php) へアクセスします。
するとこのようにヘッダーの中に埋め込まれたユーザーに関する情報を確認することができます。
それぞれの意味についてはこちら( http://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html#Claims )で確認できます。

<img width="60%" alt="php_header_request.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/705474/6fb137bb-4b48-9770-aebe-2e71dee8375f.png">


## おわりに
本記事では Keycloak と Azure AD を用いてID連携の検証を行いました。
Azure AD の対応しているプロトコルが OAuth2.0、SAML、OpenID Connect、WS-Federation　ということだったので、今回は Apache-Keycloak間、Keycloak-AzureAD間の両方で OpenID Connect (の認可コードフロー) を利用しました。

Apache の mod_auth_openidc の confファイルの設定以外は基本的にGUI上での設定になるので想定していたよりも容易に連携ができるんだなという印象を受けました。始める前は設定ファイルをテキストエディタで開いてごちゃごちゃと細かい設定が必要になると思っていましたので。
Azure AD に登録する Redirect URI は https:// または http://localhost でなければならない点や mod_auth_openidc と Chrome の互換性の問題などハマりポイントはありましたがこの2点に気をつければ初心者でも比較的簡単にID連携を行えるのではないかと思います。

本記事では、KeycloakとAzureADの連携手順を示しましたが、こちらの記事では認証・認可機能を一から作っているようです。
[新人社員がSpring Securityで認証・認可機能を一から作ってみた]( https://qiita.com/y-yamagata/items/7232b9969fcb7ce85b54 )

参考
---
Keycloak公式チュートリアル
https://www.keycloak.org/getting-started/getting-started-zip

OpenID Connect
http://openid-foundation-japan.github.io/openid-connect-core-1_0.ja.html
https://www.atmarkit.co.jp/ait/articles/1804/14/news004.html
https://www.ogis-ri.co.jp/otc/hiroba/technical/openid-connect/chap1.html
https://backstage.forgerock.com/docs/am/6/oidc1-guide/

Ubuntuへのサービス登録
https://qiita.com/ryota_i/items/69ded3fd950c7f9b70f5
https://qiita.com/ymasaoka/items/c46c6f5aed175bb7fd13

adminコンソールのHTTPアクセスを許可
https://www.ipride.co.jp/blog/2229

ApacheHttpのクライアント設定
https://qiita.com/ryota_i/items/69ded3fd950c7f9b70f5

mod-auth-openidcの有効化と設定
https://zoomadmin.com/HowToInstall/UbuntuPackage/libapache2-mod-auth-openidc
https://gluu.org/docs/gluu-server/3.1.1/integration/sswebapps/openidc-rp/
https://qiita.com/ryota_i/items/69ded3fd950c7f9b70f5

phpのヘッダ取得関数
https://www.php.net/manual/ja/function.apache-request-headers.php
https://www.php.net/manual/ja/function.apache-response-headers.php

Keycloakのクライアントアダプター
https://thinkit.co.jp/article/14839

本記事内で使用している画像は
[Diagrams.net (https://app.diagrams.net/)](https://app.diagrams.net/)を用いて作成しています。