Keycloakのアップグレードについて・・・Keycloakを少しでも長く使い続けるために

# はじめに
システムを構築する上で考慮する項目のひとつに、システムの耐用年数があります。耐用年数はサービス要件であったり、減価償却期間であったりで変化するかと思いますが、一般的には5年以上の耐用年数を想定しているのではないでしょうか。システムを長期にわたって使い続けるには、バグ改修や脆弱性への対応、新しい認証・認可プロトコルへの対応などをするため、アップデートを行わなければならないのが当たり前となってきています。Keycloakは、認証・認可というシステムの重要な役割を担っているため、積極的なアップグレードが必要となります。

![lifecycle6.png](https://qiita-image-store.s3.amazonaws.com/0/208407/ce0f645c-70c3-765e-329f-4a286e3b24a7.png)

そこで今回は、Keycloakの導入を検討されている方や興味のある方のために、Keycloakを少しでも長く利用するため、Keycloakのアップグレードに必要な計画（基礎知識）から手順までを解説します。


# Keycloakのアップグレード計画（基礎知識）
## Keycloakのシステム要件
バージョンによりシステム要件が変更となることがあります。Keycloakをアップグレードする場合は、利用するバージョンのインストールガイドを参照してシステム要件を確認します。

**Keycloakのシステム要件(バージョン3.4)**

  - Javaが動作するOS
  - Java 8 JDK
  - RAM 512M以上
  - 1G以上のディスクスペース
  - DB PostgreSQL,MySQL,Oracleなどの外部の共有データベース *1
  - マシン上のネットワークマルチキャストサポート *1  
\*1 クラスタ構成で動作させる際の要件  

最新のシステム要件は、「[Keycloak - Documentation | Server Installation - System Requirements](http://www.keycloak.org/docs/latest/server_installation/index.html#system-requirements)」を参照してください。

## Keycloakのライフサイクル
Keycloakのコミュニティーとしての[サポートポリシー](http://www.keycloak.org/support.html)では、パッチの提供は行っておらず、脆弱性やバグ修正にはバージョンアップで対応しています。そのため、利用者は必要に応じて新しいバージョンへアップグレードする必要があります。

パッチが必要な場合は、「Red Hat Single Sign-On（以下RH SSO）」という商用版があり、パッチの提供を受けることができます。参考として、RH SSOのライフサイクルとアップグレードについて簡単に紹介します。

また、[NRI OpenStandia](http://openstandia.jp/)では、Keycloakの独自サポートを行っております。興味がある方は[こちら](http://openstandia.jp/)をご参照ください。  

#### RH SSOのライフサイクル
Keycloakの商用版であるRH SSOでは、技術的なQ&Aやパッチの提供といったRed Hat社の商用サポートを受けることができます。RH SSOのライフサイクルは以下のリンクから確認することができます。
[Red Hat JBoss Middleware Product Update and Support Policy](https://access.redhat.com/support/policy/updates/jboss_notes)

RH SSOのライフサイクルは、以下の通りとなっています。(2018年1月時点)  

|Family|GA|End of Full Support|End of Maintenance Support|
|:--|:--|:--|:--|
|7.x|Jun 2016|Jun 2019|Jun 2021|

RH SSOが利用するKeycloakのバージョンは、以下の通りとなっています。(2018年1月時点)  

|RH SSO Version|Keycloak Version|
|:--|:--|
|7.1|2.5.5|
|7.0|1.9.8|

上記ライフサイクルより、RH SSOはメジャー・バージョンのリリースから5年間のサポート利用が可能となっています。5年以上の耐用年数やサービスの開始時期を考慮した場合、サポート期限によるメジャーアップグレード(RH SSO 7.x⇒8.x)を考慮しておく必要があります。また、サポートを受ける場合においても、脆弱性の発見などによるアップグレードが発生しうることは想定しておいたほうが良いでしょう。

#### RH SSOのアップグレードについて
RH SSOのアップグレードには、コミュニティ版のKeycloakにはないマイクロアップグレードという種別があります。Red Hat社の提供するパッチを適用するアップグレード種別です。それ以外にも、メジャーアップグレード、マイナーアップグレードの種別があります。それぞれアップグレードのための対応方法が異なります。ここでは概要のみ説明します。

| アップグレード種別 | 例 | 概要 |
| :-- | :-- | :-- |
| メジャーアップグレード | RH SSO 7.x ⇒ RH SSO 8.x | アプリケーションやカスタム・サーバー・エクステンションの一部を書き直す必要のあるAPIの変更が行われている可能性があります。 |
| マイナーアップグレード | RH SSO 7.0 ⇒ RH SSO 7.1 | パブリックAPIではないAPIが使用されていない限り、アプリケーションやカスタム・サーバー・エクステンションにコード変更の必要がありません。 |
| マイクロアップグレード | RH SSO 7.1.0 ⇒ RH SSO 7.1.1 | アプリケーションやカスタム・サーバー・エクステンションにコード変更の必要がありません。変更された配布物の置き換えのみのアップグレードです。パッチで配布物の反映のみを行います。 |

:warning: バージョンにより異なる可能性がありますので、アップグレードするRH SSOのバージョンのドキュメントを確認してください。
:warning: 本記事後半のアップグレード手順は、コミュニティ版のKeycloakのアップグレード手順です。RH SSOのアップグレードについては、[RH SSOのドキュメント](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/)を参照してください。

# Keycloakのアップグレード

Keycloakのアップグレードは、Keycloakサーバー ⇒ Keycloakアダプターの順で行います。「[Keycloak - Upgrading](http://www.keycloak.org/docs/latest/upgrading/index.html)」ではまず最初に、アップグレードする順番を守るように記述されています。  
「Keycloak - Upgrading」の[4.Migration Changes](http://www.keycloak.org/docs/latest/upgrading/index.html#migration-changes)の章には、バージョンごとの変更点が記載されています。アップグレードを行う場合は、必ずどのような変更が行われたかを確認し、対応する必要があるかを判断する必要があります。また、アップグレードのベスト・プラクティスとしてプロダクション環境でアップグレードを行う前に検証環境でアップグレードの確認を行うことが推奨されています。

## アップグレードするサーバー構成
今回アップグレードを行うために、Keycloak、MySQL、Tomcatをまとめたオールインワン・サーバーを用意しました。KeycloakとKeycloakクライアント・アダプター、外部共有データベースのアップグレードを試します。メジャーバージョンのバージョンアップを含むバージョン2.5.5からバージョン3.4.3へのアップグレードを行い、手順を確認します。Keycloakサーバーは、スタンドアロン・モードで動作しています。
設定については、以下の「[Keycloak by OpenStandia Advent Calendar 2017](https://qiita.com/advent-calendar/2017/keycloak-by-openstandia)」の記事を参考としています。
Tomcatクライアントの設定は、「[Keycloakのクライアント・アダプターを試してみる（Tomcat編）](https://qiita.com/yagiaoskywalker/items/c7e9433734f2880b1aa7)」の通りのユーザー、ロール、クライアント設定としています。FQDNは、`test-keycloak1.example.com`としています。
MySQLの設定については、「[Keycloakを冗長構成で動かしてみる 外部共有データベースの設定](https://qiita.com/yoonis/items/4f4a9df0f6f8e858bd4a#%E5%A4%96%E9%83%A8%E5%85%B1%E6%9C%89%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%81%AE%E8%A8%AD%E5%AE%9A)」を参考としました。

| |Keycloak|OS|構成|
|:--|:--|:--|:--|
|アップグレード前|KeycloakServer 2.5.5Final|CentOS 7.4|・MySQL CommunityServer 5.7<br>  ・Tomcat 8.5.23<br>  ・Tomcat 8用クライアント・アダプター(OpenID Connect版) 2.5.5|
|アップグレード後|KeycloakServer 3.4.3Final|CentOS 7.4|・MySQL CommunityServer 5.7<br>  ・Tomcat 8.5.23<br>  ・Tomcat 8用クライアント・アダプター(OpenID Connect版) 3.4.3.Final|

![upgrade-to2.png](https://qiita-image-store.s3.amazonaws.com/0/208407/b7efa2eb-a898-f3a0-83be-45955e931901.png)


```txt:directory
/opt/
 ├ keycloak-2.5.5.Final/
 ├ apache-tomcat-8.5.23/
/var/
 ├ lib/mysql
```

## Keycloakサーバーのアップグレード手順

### 1. アップグレードするKeycloakサーバーへのアクセスを停止
アップグレードするKeycloakサーバーへのアクセスを遮断します。その後、すべてのトランザクションが完了していることを確認し、トランザクションディレクトリ `data/tx-object-store` を削除します。

```txt:トランザクションの確認
$ /opt/keycloak-2.5.5.Final/bin/jboss-cli -c
# トランザクション・ログストアを更新
[standalone@localhost:9990 /] /subsystem=transactions/log-store=log-store/:probe
# 存在するトランザクションを確認 - コマンドの結果resultがないことを確認
[standalone@localhost:9990 /] /subsystem=transactions/log-store=log-store:read-children-names(child-type=transactions)
{
    "outcome" => "success",
    "result" => []
}
```

### 2. アップグレードするバージョンの配布物のダウンロード
[Keycloakのダウンロードページ](http://www.keycloak.org/downloads.html)からアップグレードするバージョンの配布物をダウンロードします。

### 3. 配布物の解凍
既存のインストール先とは異なるようにアップグレードするバージョンの配布物を解凍します。ここでは、既存のインストール先は`/opt/keycloak-2.5.5.Final`で、新規インストール先は`/opt/keycloak-3.4.3.Final`とします。

```txt:directory
/opt
 ├ keycloak-2.5.5.Final
 ├ keycloak-3.4.3.Final
```

### 4. 設定ディレクトリのコピー
設定ファイルやKeyStoreファイルなどを含む現行のKEYCLOAK_HOME/standaloneディレクトリを、新規インストール先のstandaloneディレクトリへ上書きコピーします。

```
$ cp -pfr /opt/keycloak-2.5.5.Final/standalone/ /opt/keycloak-3.4.3.Final/
```


### 5. modulesディレクトリのコピー
modulesディレクトリへ追加したカスタムモジュールを解凍したmodulesディレクトリへコピーします。MySQLコネクターをインストールしていましたので新規インストール先へディレクトリごとコピーします。

```
$ cp -pfr /opt/keycloak-2.5.5.Final/modules/system/layers/keycloak/com/mysql \
 /opt/keycloak-3.4.3.Final/modules/system/layers/keycloak/com/mysql
```

### 6. アップグレード・スクリプトの実行
アップグレード・スクリプトを実行することで、バージョンアップによる変更をKeycloakの設定ファイルへ反映します。手順は下記の通り行います。  

  1. デフォルトの設定ファイル(standalone.xml、standalone-ha.xml、domain.xml)以外を使用している場合は、アップグレード・スクリプトを編集して設定ファイル名を変更します。アップグレード・スクリプトは以下の通りです。  
    - スタンドアロン・モードの場合  `/opt/keycloak-3.4.3.Final/bin/migrate-standalone.cli`
    - スタンドアロン・高可用性モードの場合  `/opt/keycloak-3.4.3.Final/bin/migrate-standalone-ha.cli`
    - ドメイン・モードの場合  `/opt/keycloak-3.4.3.Final/bin/migrate-domain.cli`
    - ドメイン・クラスタ・モードの場合 `/opt/keycloak-3.4.3.Final/bin/migrate-domain-clustered.cli`  
  1. Keycloakサーバーを停止
  1. アップグレード・スクリプトの実行  
    `/opt/keycloak-3.4.3.Final/`で下記コマンドを実行します。  
    - スタンドアロン・モードの場合  
      `bin/jboss-cli.sh --file=bin/migrate-standalone.cli`  
    - スタンドアロン・高可用性モードの場合  
      `bin/jboss-cli.sh --file=bin/migrate-standalone-ha.cli`  
    - ドメイン・モードの場合  
      `bin/jboss-cli.sh --file=bin/migrate-domain.cli`  
    - ドメイン・クラスタ・モードの場合  
      `bin/jboss-cli.sh --file=bin/migrate-domain-clustered.cli`  


### 7. データベースの更新
  1. 変更内容の確認  
  データベース・スキーマの変更があるかどうかは、アップグレードするバージョンの[Keycloakのソースコード](https://github.com/keycloak/keycloak)の「`keycloak/model/jpa/src/main/resources/META-INF/jpa-changelog-(authz-)*.xml`」から確認することができます。データベースの`DATABASECHANGELOG`テーブルに現在までに適用されたchange-log情報が格納されていますので、ソースコードのchange-logのバージョンと比較して適用されていないchange-logの変更が行われます。
  1. データベースのバックアップ  
  データベースごとのバックアップ方法に従い、データベースをバックアップします。MySQLの場合はmysqldump, PostgreSQLの場合はpg_dump, Oracleの場合はexp,expdpといったバックアップを実施します。
  1. データベースのアップグレード  
  データベースのアップグレードは、Keycloakサーバーをアップグレード後、Keycloakサーバー起動時に自動的に行われます。
自動でデータベースのアップグレードを行いたくない場合は、設定により手動アップグレードを行うことができます。以下にスタンドアロン・モードの設定箇所を抜き出してみます。`migrationStrategy`のvalueが`update`の場合、自動アップグレードとなります。手動アップグレードを行う場合は、`migrationStrategy`のvalueを`manual`に変更してください。デフォルトでは、`update`に設定されています。

```standalone.xml  
  <spi name="connectionsJpa">
    <provider name="default" enabled="true">
        <properties>
            ...
-           <property name="migrationStrategy" value="update"/>
+           <property name="migrationStrategy" value="manual"/>
        </properties>
    </provider>
  </spi>
  ```

  CLIから設定を変更することも可能です。CLIを使用して、以下のコマンドを実行します。手動アップグレードを行う場合は、`migrationStrategy`のvalueを`manual`に変更してください。以下に標準の設定ファイル`standalone.xml`を使用しているスタンドアロン・モードの場合のコマンドを示します。

```txt:CLI
$ $KEYCLOAK_HOME/bin/jboss-cli.sh
[disconnected /] embed-server --server-config=standalone.xml
[standalone@embedded /] /subsystem=keycloak-server/spi=connectionsJpa/provider=default/:map-put(name=properties,key=migrationStrategy,value=manual)
```  

データベース・スキーマのアップグレードが行われると、Keycloakサーバー初回起動ログに以下のように出力されます。

```
20:26:12,993 INFO  [org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider] (ServerService Thread Pool -- 55) Updating database. Using changelog META-INF/jpa-changelog-master.xml
```

`migrationStrategy`のvalueを`manual`に設定している場合、更新クエリを出力し、サーバーを終了します。デフォルトでは、Keycloakインストールディレクトリ直下のkeycloak-database-update.sql に更新クエリが出力されます。
:thought_balloon: サーバー終了のシグナル受信後にエラーが出力されましたが、更新クエリは出力されていました。シグナル受信によるサーバー起動の中断によりエラーが出力されるようです。

```
20:45:26,913 INFO  [org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider] (ServerService Thread Pool -- 57) Updating database. Using changelog META-INF/jpa-changelog-master.xml
20:45:27,178 INFO  [org.jboss.as.server] (Thread-2) WFLYSRV0220: Server shutdown has been requested via an OS signal
```

出力された更新クエリをMySQLへ適用します。

```
# mysql -u root -p < /opt/keycloak-3.4.3.Final/keycloak-database-update.sql
Enter password:
```

### 8. テーマの移行
カスタム・テーマを使用している場合は、カスタム・テーマのディレクトリを新規インストール先のテーマディレクトリへコピーします。しかし、APIの変更などにより正常に動作しなくなる可能性があるため、変更のマージ作業が必要です。下記のテンプレート、メッセージファイル、スタイルの移行作業を行ったファイルを新規のテーマディレクトリへ配置します。

```txt:directory
/opt
 ├ keycloak-2.5.5.Final
   ├ themes
     ├ base
       ├ login
       ├ admin
     ├ keycloak
       ├ login
       ├ admin
     ├ custom-theme
       ├ login
```

**テンプレートの移行**
テンプレートをカスタマイズしている場合、既存と新規のベースとしたテンプレートの差分を比較してカスタム・テンプレートに変更をマージする必要があります。Keycloak-2.5.5とKeycloak-3.4.3で取得したloginテーマの差分の例を以下に抜き出します。loginテーマをベースとして作成したカスタム・テンプレートを使用している場合、このような差分をカスタム・テンプレートへマージする作業が必要です。

```
diff keycloak-2.5.5.Final/themes/base/login/register.ftl keycloak-3.4.3.Final/themes/base/login/register.ftl
6c6
<         ${msg("registerWithTitleHtml",(realm.displayNameHtml!''))}
---
>         ${msg("registerWithTitleHtml",(realm.displayNameHtml!''))?no_esc}
（以下略）
```

**メッセージファイル（言語ファイル）の移行**
メッセージファイルに変更を加えたときもテンプレートと同様にマージする必要があります。機能追加などでメッセージが追加されていることや、追加で翻訳されていることがあるためです。追加されたキーに対する重複なども確認が必要です。

**スタイル（CSS）の移行**
テンプレートと同様に、既存と新規のベースとしたテーマのスタイルを比較してカスタマイズしたテーマのスタイルへ適用するかを判断します。

```
diff keycloak-2.5.5.Final/themes/keycloak/login/resources/css/login.css keycloak-3.4.3.Final/themes/keycloak/login/resources/css/login.css
34d33
<     display:block;
（以下略）
```

テンプレート、メッセージファイル、スタイルのマージが完了したカスタム・テーマを新規のthemesディレクトリへ配置します。

### 9 Keycloakサーバーの起動
新規Keycloakサーバーを起動します。

```
$ cd /opt/keycloak-3.4.3.Final
$ bin/standalone.sh -b=0.0.0.0
```  

## Keycloakアダプターのアップグレード手順
Keycloakサーバーのアップグレードが完了した後に、Keycloakアダプターのアップグレードを行います。

### 1. Tomcatの停止
### 2. Tomcatディレクトリのバックアップ
### 3. アップグレードするバージョンの配布物をダウンロード
[Keycloakのダウンロードページ](http://www.keycloak.org/downloads.html)からアップグレードするバージョンの配布物をダウンロードします。
### 4. 古いアダプターの削除
古いアダプターの配布物(`keycloak-tomcat8-adapter-dist-2.5.5.Final.tar.gz`)を使用して削除を行ってみます。以下のような感じでしょうか。
  
```
$ cd $TOMCAT_HOME/lib
$ for file in $(tar -tzf /path/keycloak-tomcat8-adapter-dist-2.5.5.Final.tar.gz); \ 
  do [[ -f $file ]] && rm $file || echo "$file does not exist"; done
```

### 5. アップグレードするバージョンの配布物を解凍
$TOMCAT_HOME/libへ配布物を解凍します。

  ```
$ cd $TOMCAT_HOME/lib
$ tar -xzf /path/keycloak-tomcat8-adapter-dist-3.4.3.Final.tar.gz
  ```

### 6. Tomcatの起動

## アップグレード後の確認

- 管理コンソールへのログイン
管理コンソールへログインすることができ、レルムも引き継がれています。
![admin-console-realm.png](https://qiita-image-store.s3.amazonaws.com/0/208407/572b06ce-6f97-674a-f351-f117ae6ad112.png)  

- Tomcatアダプターの確認
`http://test-keycloak1.example.com:8080/examples/` へアクセスします。
下記の通り、カスタムログイン画面が表示されました。
![login.png](https://qiita-image-store.s3.amazonaws.com/0/208407/d39718f9-1605-241c-371e-71e299adb1d6.png)
- ユーザー・ロール確認
user001でログインします。
Tomcatの`/examples/`へアクセスすることができました。
![tomcat-example2.png](https://qiita-image-store.s3.amazonaws.com/0/208407/8169106b-f885-1a7f-4ff2-36657d9d8914.png)  
Tomcatの`/examples/websocket/echo.xhtml`へアクセスしてみます。  
![403error.png](https://qiita-image-store.s3.amazonaws.com/0/208407/06b8ca5a-ea6b-6e44-2daa-a76c26b529aa.png)  
ちゃんと`403 Forbidden`となり、ロールによる制御もきいているようです。

# 最後に
アップグレードには労力がかかりますが、セキュリティを担保するためにはどうしても避けて通れない作業となります。脆弱性のあるシステムを使い続けることは、個人情報の漏洩やサイバー攻撃への直接・間接的な加担など、企業のコンプライアンスに関わる重大なインシデントを引き起こす可能性があります。計画的にソフトウェアのアップグレードを行う必要があります。  
どのソフトウェアのアップグレードにおいても、検証環境を準備して事前に確認を行い、プロダクション環境のアップグレード時の障害リスクを低減しておく必要があります。アップグレードが失敗する、既存の機能がデグレードするなどのアップグレード起因による障害が発生しないことを事前に確認しておくことが大切です。また、アップグレード作業において障害が発生した場合の対策（バックアップからの切り戻し）を事前に準備しておくことも大切です。  
Keycloakは、アップグレード・スクリプトを提供するなど、アップグレードを行う前提で開発が進められており、比較的簡単にアップグレードを行うことができました。なお、今回実施したアップグレード手順は検証用の環境で実施したものであり、環境やバージョンにより手順や変更対象が異なる可能性があります。プロダクション環境のアップグレードを実施する場合は、実施前に同等の検証環境を用意し、アップグレードするバージョンのドキュメントにしたがって手順等の検証を行うことが大切です。

# 参考URL
Keycloak
http://www.keycloak.org/
Keycloak - Documentation
http://www.keycloak.org/documentation.html
NRI OpenStandia Keycloak日本語ドキュメント - アップグレード
http://keycloak-documentation.openstandia.jp/master/ja_JP/upgrading/index.html
Red Hat Single Sign-On Component Details
https://access.redhat.com/articles/2342881
Red Hat Single Sign-On (7.1) Upgrading Guide
https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.1/html/upgrading_guide/

NRI OpenStandiaでは、「[Keycloak by OpenStandia Advent Calendar 2017](https://qiita.com/advent-calendar/2017/keycloak-by-openstandia)」にKeycloakの機能紹介や実際の動作などについて掲載しております。未読の方はぜひこの機会にご覧ください。