Keycloakで統合Windows認証を試した

# お品書き
1\. やること
2\. 検証構成
3\. Active Directoryの設定
4\. クライアントの設定
5\. Keycloakの設定
6\. 動作確認
7\. まとめ


# 1.やること
Keycloakアドベントカレンダー12日目の今回は、Keycloakで統合Windows認証を試してみます。
統合Windows認証は、Windowsドメインにログイン済みの端末からブラウザ(HTTPプロトコル)経由でKerberos認証を実施する仕組みです。
この仕組みを利用すると、Active Directory(以下,AD)サーバーから配布されるセッション・チケットを元にKerberos認証が行われるため、ブラウザからはID/PWを送信せずにユーザー認証が行えます。このようにブラウザ経由でKerberos認証を実現するためのプロトコルを「SPNEGO(The Simple and Protected GSS-API Negotiation Mechanism)」 といいます。
詳細なシーケンスはこの[過去記事](URL:https://qiita.com/yagiaoskywalker/items/4d3c1c682aba29f89056)に記載があるのでご確認ください。

※KerberosはTCP 88番ポートで行われる認証・認可プロトコル

# 2.検証構成
|役割|OS|アプリケーション|FQDN|
|:-:|:-:|:-:|:-:|
| Keycloakサーバ | Ubutu 22.04.3 LTS | Keycloak ver.22.0.2   | kc-server.example.com |
| ADサーバ | Windows Server 2022 | Active Directory, DNS  | {EC2のホスト名}.example.com |
| クライアント端末 | Windows Server 2022 | ブラウザ(Edge)  | {EC2のホスト名}.example.com |

※AWSのEC2で検証した都合上、クライアント端末をWindows Serverで代用しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630716/52a3f06c-632e-cd29-1f7b-121d38e1a939.png)


 # Active Directoryの設定
1. ドメイン,ログイン用ユーザ作成(ドメイン名：example.com ユーザ名：test-user)
2. DNSの構成
Keycloakサーバの正引き、逆引きが可能なように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630716/a4a446c1-d767-6875-9308-2ec19f7e7927.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630716/8f08344a-c33a-8e8a-1b7a-7030f32f8fad.png)


3. Kerberos認証用ユーザー作成
KeycloakサーバーからKerberos認証実行時に利用されるマップユーザーを作成します。
今回はActive Directory上に「kc-kerberos」というユーザーを作成します。
この時にKerberosの認証の暗号化方式を「AES128 or AES256」に指定します。(理由は後述)
パスワードは任意ですが「パスワードを無期限にする」のチェックをつけておく必要があります。パスワード有効期限が切れたことで、Kerberos認証用ユーザーのパスワードを変更してしまった場合に、keytabファイルも再作成が必要になってしまうためです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630716/d27bab0c-beeb-43ab-2b57-45fcd3b3c8e7.png)


4. keytabファイルの作成
KeycloakサーバーがHTTPサービスへのログインを行う際に必要なkeytabファイルを生成します。
Windows のコマンドプロンプトから、以下のktpassコマンドを実行し、keytabファイルを生成します。
作成したkeytabファイルはKeycloakサーバーの任意のパスにコピーしておきます。

```cmd
ktpass ^
-out kc-kerberos.HTTP.keytab ^
-princ HTTP/kc-server.example.com@EXAMPLE.COM ^
-ptype KRB5_NT_PRINCIPAL ^
-mapuser kc-kerberos ^
-pass xxxxxxxxx
-crypto All
```

|オプション	|説明|
|---|---|
|-out|	出力するkeytabファイル名を指定します。|
|-princ|	プリンシパル名を指定します。命名ルール： HTTP/{KeycloakサーバーのFQDN(Aレコード)}@{Active Directoryドメイン名}|
|-ptype|	KRB5_NT_PRINCIPALを指定を指定します。|
|-mapuser|	Kerberos認証用マップユーザー名を指定します。Kerberos認証時のHTTPサービスチケットはこのマップユーザーを経由して発行されるようになります。そのため、マップユーザーを削除したり、パスワードを変更したりすることは基本的にできません。|
|-pass|	マップユーザーのパスワードを指定します。|
|-crypto|	keytabファイルの暗号化形式を {DES-CBC-CRC/DES-CBC-MD5/RC4-HMAC-NT/AES256-SHA1/AES128-SHA1/All} の中から選択します。指定しなかった場合は、デフォルトで RC4-HMAC-NT になります。|

:::note information
-princで指定する {KeycloakサーバーのFQDN(Aレコード)} は、DNS上のAレコードである必要があります。たとえば、Aレコード(kc-server-internal.example.com)、CNAMEレコード(kc-server.example.com)というようなDNS定義をしている場合は、AレコードのFQDNを指定する必要があります。
:::

:::note warn
暗号化形式の**RC4-HMAC-NT**ですが、Keycloakを稼働させているJDKのセキュリティポリシーが変更になりデフォルトで使用が不可になっております。
https://backstage.forgerock.com/knowledge/kb/article/a22578720
:::

クライアントからRC4-HMAC-NT形式でHTTPチケットを送信した場合にKeycloakで下記のlogが出ます。
```
2023-12-06 01:39:24,998 WARN  [org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator] 
(executor-thread-366) SPNEGO login failed: java.security.PrivilegedActionException: 
GSSException: Failure unspecified at GSS-API level (Mechanism level: Encryption type RC4 
with HMAC is not supported/enabled)
```

# 4\. クライアントの設定
SPNEGO経由でKerberos認証を実行する場合、ブラウザがNegotiationヘッダを送信しても問題ないFQDNかどうかを明示しておく必要があります。そのため、ブラウザ(Edge)で以下の追加設定が必要です。

1\. Edgeの設定画面より「Internet Options」を開く
2\. Securityタブ内の「Local internet」を選択し「Sites」をクリック
3\. リストの中に「http://kc-server.example.com」 を追加
※検証環境なので、http通信を想定しております。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630716/427de2b3-da59-75d0-75fd-fadf0b710a57.png)
4\. ブラウザの再起動

# 5\. Keycloakの設定
1\. Keycloakの管理コンソールにログイン
2\. 左メニューバーから、demoレルムを選択
※レルム名は個人の環境で任意
3\. 左メニューバーで「User federation」をクリック
4\. 左上の 「Add new provider」 からKerberosを選択
5\. 以下のような設定値を入力し、save ボタンをクリック
UI display name: 任意
Kerberos realm: 大文字のドメイン名
Server principal: HTTP/KeycloakサーバのFQDN@大文字のドメイン名
KeyTab: {keytabファイルへのフルパス}
Debug: On(デバッグ不要の場合は、OFFのままでOK)
Allow password authentication: Off
Update first login: Off

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630716/dcf5a00c-f383-c45c-16a8-9bff33dbc28c.png)

# 6\. 動作確認
## ログイン確認
1\. クライアント端末をexample.comドメインに参加
2\. ドメイン所属ユーザー(test-user)でログイン
3\. http://kc-server.example.com:8080/realms/demo/account にアクセスし、右上の「Sign in」をクリック
4\. 2でログインしたユーザー名で、Keycloakにログイン
※Keycloakのログイン画面が表示されることなくユーザー詳細画面が表示されます 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630716/c6b4c821-4d53-d61b-0826-5647dae622c8.png)


## パケットキャプチャによるチケット挙動の確認
Keycloakからのチケット確認(WWW-Authenticate: Negotiate ヘッダ)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630716/c6a8351e-95e4-4fb6-596e-08f37a882e0a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630716/80e47fa2-c952-2170-1c15-9708ab139d09.png)


クライアントからADサーバへのチケット要求・応答
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630716/58a42bd7-5ff4-ae02-ca91-8c2e21156613.png)

Keycloakへのチケット送信(Authorization: Negotiateヘッダ)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630716/19ff1e36-c399-4c53-40c3-fc5dc7a2e6ae.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3630716/2a27413f-9d4b-d17b-e0b8-dfb74ce3130d.png)

# 7\. まとめ
[前回の記事](https://qiita.com/yagiaoskywalker/items/4d3c1c682aba29f89056)からKeycloakのバージョンがかなり変わってしまったので、今回はアップデート記事として執筆しました！
チケットの暗号化方式がデフォルトだと使えなくなる事象が発生したので、お気を付けください。