Keycloakの設定をファイルから読み込む

[OpenID Connectを使ったアプリケーションのテストのためにKeycloakを使ってみる](https://qiita.com/shibukawa/items/fd78d1ca6c23ce2fa8df)の続編です。

ローカルで気軽にテストするには、グローバル変数の親玉たるRDBがいると不便なことも多いです。Keycloakはオンメモリ動作もサポートしていて、前回のエントリーではそれを利用しました。あとは、設定ファイルを読み込んでいつでも状態が復元できると最高ですよね？今回はデータを読み込んで再利用する方法を試して見ます。

**2020/11/10:** コンテナの置き場が変わっていたので更新

# Realmの情報をエクスポートするには？

管理画面をみるとExportというページがあります。これを使えばOKでしょうか？

<img width="1476" alt="Screen Shot 2019-11-08 at 16.58.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6105/cbb76c56-0593-dc49-92f7-bbe826341608.png">

試してみると、secretがマスクされており、これをそのまま読み込んでも復元はされなそうです。また、ユーザー情報も出力されていないため、もしスコープ違いのユーザーのテストをしようとユーザーを作ったとしても、この方法ではデータが消えてしまいます。

```json
 "clients": [
    {
      "id": "6a2d9368-df11-4d6a-b6ad-b1a03a557a6f",
      "clientId": "testapp",
      "rootUrl": "http://localhost:8080",
      "adminUrl": "http://localhost:8080",
      "surrogateAuthRequired": false,
      "enabled": true,
      "clientAuthenticatorType": "client-secret",
      "secret": "**********",
      "redirectUris": [
        "http://localhost:8080/*"
      ],
      "webOrigins": [
        "http://localhost:8080"
      ],
      :
```

# エクスポート可能なようにローカルをマウントしつつ実行

[公式ドキュメント](https://www.keycloak.org/docs/latest/server_admin/index.html#_export_import)のエクスポートの情報や、[DockerのREADME](https://github.com/keycloak/keycloak-containers/blob/master/server/README.md)に書かれている情報を元にエクスポートします。

エクスポートするにはホストとコンテナでストレージを共有しておく必要があります。前回の起動オプションに ``-v`` オプションをつけて、コンテナ内部の``/tmp``フォルダを、現在の作業フォルダにマッピングしておきます。

```console
$ docker run -d --rm -p 18080:8080 --name keycloak \
  -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin \
  -v $(pwd):/tmp quay.io/keycloak/keycloak
```

# 新しいRealmを作成

masterのままエクスポートしてもインポート時に「すでにあるよ」と言われてインポートが実行されないので、新しいRealmを作ります。

次にエクスポートを実行します。エクスポートといっても、普通のkeycloakのウェブサーバーを起動するときに、「ついでにエクスポートしてよ」と指示することでファイルにエクスポートされる仕組みになっています。ウェブサーバーを起動する場合にポート番号が同じだとダメなので、port-offset=100をつけて、現在稼働しているポートとは違うポートになるようにします。Dockerのページの説明をコピペしてもスクリプトの起動パスの/opt/jboss/がなくて実行に失敗してしまうので、↓のように実行してください。どうやってPRを送れば良いんだろうか。

```console
docker exec -it keycloak /opt/jboss/keycloak/bin/standalone.sh \
  -Djboss.socket.binding.port-offset=100 \
  -Dkeycloak.migration.action=export \
  -Dkeycloak.migration.provider=singleFile \
  -Dkeycloak.migration.realmName=testissuer \
  -Dkeycloak.migration.usersExportStrategy=REALM_FILE \
  -Dkeycloak.migration.file=/tmp/testissuer_realm.json
```

1つのJSONファイルとして出力する、ユーザー情報もREALMと一緒に出力する、出力対象は``master``realmといったことをここでは指定しています。ファイルを分けたりもできますが、そのあたりは公式ドキュメントを参照してください。ぞろぞろとコンソールにいろいろログが出てきますが、先ほど書いたように、もう一つサーバーを起動して待ちになってしまうので、つぎのようなメッセージが出たらCtrl-Cを押して止めます。

```
09:00:12,148 INFO  [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server
09:00:12,153 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management
09:00:12,153 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990
09:00:12,155 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: Keycloak 7.0.1 (WildFly Core 9.0.2.Final) started in 26874ms - Started 682 of 987 services (701 services are lazy, passive or on-demand)
```

これで、Dockerコマンドを起動したフォルダにmaster_realm.jsonというファイルができています。これをみると、シークレットもマスクされておりませんし、ユーザー情報もエクスポートされています。

ここまでのステップは、開発環境を作る人が1回作業すればOKです。

# エクスポートしたRealm情報を読み込みつつDockerコンテナを起動

先ほどエクスポートしたファイルを再びマウントしつつ、``KEYCLOAK_IMPORT``環境変数でそのコンテナ内部のパスを設定すると、起動時に読み込みます。

```console
$ docker run -d --rm -p 18080:8080 --name keycloak \
  -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin \
  -e KEYCLOAK_IMPORT=/tmp/testissuer_realm.json \
  -v $(pwd)/testissuer_realm.json:/tmp/testissuer_realm.json \
  quay.io/keycloak/keycloak
```

他のサービスと一緒にdocker-composeで起動したいよ、という方はこちらをどうぞ。[このDockerコマンドラインからcomposeのyamlを生成するサービス](https://composerize.com/)を使ってみましたが便利ですね（$(pwd)のところはピリオドに置き換えないと動かなかったですが）。

```yaml:docker-compose.yml
version: '3.3'
services:
    keycloak:
        ports:
            - '18080:8080'
        container_name: keycloak
        environment:
            - KEYCLOAK_USER=admin
            - KEYCLOAK_PASSWORD=admin
            - KEYCLOAK_IMPORT=/tmp/testissuer_realm.json
        volumes:
            - ./testissuer_realm.json:/tmp/testissuer_realm.json
        image: quay.io/keycloak/keycloak
```

起動してみると、自分で作ったユーザーもサービスも読み込まれていることがわかります。これでCI環境で使ってみるとか、開発環境として配ってローカルで起動するのもバッチリですね。