Keycloakのインストール方法をわかりやすく手順化してみた

#はじめに

シングルサインオン（SSO）について調査していた際に、認証・認可の仕組みを提供する
ソフトウェアとして「OpenAM」や「Keycloak」を見つけたので、
ひとまず「Keycloak」で何が出来そうか検証するため、AWSのEC2にインストールしてみました。

ちょっとハマったところもあったので、今回はその際の手順を下記に記載します。
これから使ってみようと思っている方の参考になれば幸いです。

#環境
[Keycloakのシステム要件](https://www.keycloak.org/docs/latest/server_installation/index.html#system-requirements)

[AWS EC2]（OpenID Provider）
・CentOS 7
・MEM 2GB
・HDD 8GB
・Java 8 JDK
・MySQL 5.7（KeycloakにはH2というDBが組み込まれていますがMySQLに変更するため）
・Keycloak 4.8.3.Final（スタンドアローン・モードで起動します）

[AWS EC2]（Relying Party）
・CentOS 7
・MEM 512MB
・HDD 8GB
・Apache HTTP Server 2.4

##サーバー構成

Keycloakをスタンドアローン（同サーバーにMySQLもインストール）で動作させ、
アプリケーションサーバーの認証領域にアクセスがきた際に、認証・認可をKeycloakで行わせる。
Keycloakの認証プロトコルはデフォルトで「OIDC」か「SAML」が利用できるようなので、
今回は「OIDC」を使用します。

また、アプリケーションサーバーとKeycloakサーバーは前にロードバランサー（ELB）を置き、
外部の通信はHTTPS、内部の通信はHTTPで動くような構成としています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/270976/aad94130-0c98-e207-a784-eaed8ec33559.png)

#Keycloakのインストール（スタンドアローン・モード）

Keycloakをインストールするサーバーにログインします。

##Java 8 JDKインストール

```
# sudo yum update -y
# sudo yum install java-1.8.0-openjdk
```

##Keycloak本体のダウンロードと展開

Keycloakのインストールはダウンロードして展開するだけです。

```
# cd /opt
# sudo wget https://downloads.jboss.org/keycloak/4.8.3.Final/keycloak-4.8.3.Final.tar.gz
# sudo tar xfpz keycloak-4.8.3.Final.tar.gz
# sudo mv keycloak-4.8.3.Final keycloak
```
##MySQLにKeycloak用のユーザーとDBを作成する
ここで作成したDBにKeycloak起動時にテーブルが作成されるようにします。
※ユーザー名やパスワードは適宜変更してください。
※既存のH2を使用する場合はMySQL関係の記述は無視して大丈夫です。
※MySQLのインストールは省略します。

```
create user 'keycloak'@'%' identified by 'keycloak';
create database keycloak character set utf8 collate utf8_unicode_ci;
grant all privileges on keycloak.* to 'keycloak'@'%';
```


##MySQLドライバー設定

```
# sudo mkdir /opt/keycloak/modules/system/layers/keycloak/com/mysql
# sudo mkdir /opt/keycloak/modules/system/layers/keycloak/com/mysql/main
# sudo cd /opt/keycloak/modules/system/layers/keycloak/com/mysql/main
# sudo wget https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.42.zip
# sudo unzip mysql-connector-java-5.1.42.zip
# sudo cp mysql-connector-java-5.1.42/mysql-connector-java-5.1.42-bin.jar ./
# sudo vi module.xml
```

[module.xml]

```xml

<?xml version="1.0"?>
<module xmlns="urn:jboss:module:1.3" name="com.mysql">
    <resources>
        <resource-root path="mysql-connector-java-5.1.42-bin.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
        <module name="javax.transaction.api"/>
    </dependencies>
</module>
```

##Keycloakの設定

スタンドアローンで起動する際の設定は「/opt/keycloak/standalone/configuration」にある、
「standalone.xml」のファイルに設定を記載します。

###MySQLの定義

MySQLの設定を記述する際のハマったポイントとして、下記のDBの文字コード指定箇所が、
「jdbc:mysql://localhost:3306/keycloak?useSSL=false&amp;characterEncoding=UTF-8」
「UTF-8」を**大文字で書かないとエラーになる**ので要注意です。

```xml

<subsystem xmlns="urn:jboss:domain:datasources:5.0">
    <datasources>
        <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
            <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
            <driver>h2</driver>
            <security>
                <user-name>sa</user-name>
                <password>sa</password>
            </security>
        </datasource>
        <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
-            <connection-url>jdbc:h2:${jboss.server.data.dir}/keycloak;AUTO_SERVER=TRUE</connection-url>
-            <driver>h2</driver>
-            <security>
-                <user-name>sa</user-name>
-                <password>sa</password>
-            </security>
+            <connection-url>jdbc:mysql://localhost:3306/keycloak?useSSL=false&amp;characterEncoding=UTF-8</connection-url>
+            <driver>mysql</driver>
+            <pool>
+                <min-pool-size>5</min-pool-size>
+                <max-pool-size>15</max-pool-size>
+            </pool>
+            <security>
+                <user-name>keycloak</user-name>
+                <password>keycloak</password>
+            </security>
        </datasource>
        <drivers>
            <driver name="h2" module="com.h2database.h2">
                <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
            </driver>
+            <driver name="mysql" module="com.mysql">
+                <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
+            </driver>
        </drivers>
    </datasources>
</subsystem>
```
###HTTPS通信に変更する
今回外部からのアクセスはHTTPS通信のみ許可しています。デフォルト設定ではKeycloakへ
HTTPS通信した後、認証のやり取り（リダイレクト）でHTTP通信に戻ってしまうため設定を変更します。
ここもなかなか気づかなかった...。

```xml
<subsystem xmlns="urn:jboss:domain:undertow:7.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other">
    <buffer-cache name="default"/>
    <server name="default-server">
-        <http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true"/>
+        <http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true" proxy-address-forwarding="true"/>
        <https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true"/>
        <host name="default-host" alias="localhost">
            <location name="/" handler="welcome-content"/>
            <http-invoker security-realm="ApplicationRealm"/>
        </host>
    </server>
```
###IPの設定
KeycloakサーバーのIPアドレスに変更します。

```xml
<interfaces>
    <interface name="management">
        <inet-address value="${jboss.bind.address.management:[KeycloakサーバーのIP]}"/>
    </interface>
    <interface name="public">
        <inet-address value="${jboss.bind.address:[KeycloakサーバーのIP]}"/>
    </interface>
</interfaces>
```
## 起動してみる
Keycloakサーバーへのアクセスはhttp（80番）のみ許可しているので80番ポートで立ち上げます。
「Ctl+C」でサーバーを止められます。（エラーが出るようであれば何処かに誤りが...）

```
# sudo /opt/keycloak/bin/standalone.sh -Djboss.http.port=80
```
起動に成功すると下記のような状態になると思います。

```
00:05:57,830 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://10.10.xx.xx:9990/management
00:05:57,830 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://10.10.xx.xx:9990
00:05:57,831 INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: Keycloak 4.8.3.Final (WildFly Core 6.0.2.Final) started in 18883ms - Started 578 of 835 services (557 services are lazy, passive or on-demand)
```

## サービスに登録する
上記コマンドで起動するとコンソールが操作できないのでサービスとして登録しておきます。

```
# sudo vi /etc/systemd/system/keycloak.service
```
[keycloak.service]

```
[Unit]
Description=Jboss Application Server
After=network.target
[Service]
Type=idle
Environment=JBOSS_HOME=/opt/keycloak
JBOSS_LOG_DIR=/var/log/keycloak/ "JAVA_OPTS=-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true"
User=root
Group=root
ExecStart=/opt/keycloak/bin/standalone.sh -Djboss.http.port=80
TimeoutStartSec=600
TimeoutStopSec=600
[Install]
WantedBy=multi-user.target
```
設定ファイルの再読み込み

```
# sudo systemctl daemon-reload
```
サービスの自動起動有効化

```
# sudo systemctl enable keycloak
```
サービスの起動

```
# sudo systemctl start keycloak
```
(補足)

```
## 再起動
# sudo systemctl restart keycloak
## 停止
# sudo systemctl stop keycloak
## ステータス確認
# sudo systemctl status keycloak
```

## Keycloak管理者作成
事前にKeycloakの管理ユーザーを登録しておきます。ユーザーID/PWDは適宜入力してください。

```
# sudo /opt/keycloak/bin/add-user-keycloak.sh -r master -u xxxxx -p yyyyy
```

# Keycloakの設定

Keycloakを起動したら下記URLにアクセスし、赤まる箇所をクリックしてログインします。
https://[KeycloakサーバーのFQDN]/auth/

ログインID/PWDは上記「Keycloak管理者作成」で作成したユーザーです。
![2.png](https://qiita-image-store.s3.amazonaws.com/0/270976/331321ef-79b0-1c93-834e-873e6aea2eed.png)

##日本語化
Realm SettingのThemesのinternationalization Enabledを「ON」に変更します。
変更が反映されない際は右上のアカウントを選択しManage accountに移動して
上部の言語を変更してみてください。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/270976/c31661f6-e7b8-a855-bc15-760f692848a1.png)

##レルムの作成
左上の「Master」の箇所からレルムの追加をクリックします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/270976/44862ff4-9ce5-9882-4216-5dbb3550358f.png)

##クライアントの追加
次に認証を行うクライアントを登録します。今回はopenid-connectを使用します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/270976/f7a11f05-e33a-101f-0ab6-282bafa51f41.png)
###クライアントの詳細設定
クライアントを追加したら、詳細情報を設定します。
アクセスタイプを「confidential」に変更し、アプリケーションサーバーのリダイレクトURLを
設定します。今回、アプリケーションサーバーで認証が必要なディレクトリを「private」配下とし、
リダイレクトURIには認証が掛かっている「private」配下を指定します。
※ アプリケーションサーバーのcallback配下には何も置かない、ディレクトリも作らない
![image.png](https://qiita-image-store.s3.amazonaws.com/0/270976/b10b93d3-db6c-314f-7573-841e0c505a3c.png)

設定が終わったらアプリケーションサーバーに登録するシークレットキーをコピーしておきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/270976/11d94b7a-87d3-3cd5-6c29-d5405ecaa833.png)

##ユーザーの作成
Keycloak管理メニューの「ユーザー」タブからフロントログインのテスト用ユーザーを作成しておく。
※「レルムの設定」 → 「ログイン」タブから「ユーザー登録」を「オン」にしておくことで
フロント画面からユーザー登録も行えるようになります。

#アプリケーションサーバー（Relying Party）の設定
アプリケーションサーバーにログインしApacheの設定を行います。

##Apacheの設定
ApacheにOIDCモジュールをインストールし設定を行う。

```
# sudo yum install mod_auth_openidc
# sudo vi /etc/httpd/conf.d/auth_openidc.conf
```
[auth_openidc.conf]
下記の設定をコメントを外しながら記載していく。

```
# Keycloakのクライアント設定で設定したリダイレクトURI
OIDCRedirectURI https://[アプリケーションサーバーFQDN]/private/callback
OIDCCryptoPassphrase passphrase
OIDCProviderMetadataURL https://[KeycloakサーバーFQDN]/auth/realms/authtest/.well-known/openid-configuration
OIDCProviderTokenEndpointAuth client_secret_basic
OIDCSSLValidateServer On
OIDCResponseType code
OIDCClientID authtest
OIDCScope "openid"
# Keycloakのクライアント設定のクレデンシャルで取得したシークレットキー
OIDCClientSecret xxxxxx-xxxxxx-xxxxxx-xxxx

# confの一番下あたりに認可ディレクトリを記載
<Location /private>
   AuthType         openid-connect
   Require          valid-user
</Location>
```
[httpd.conf]に[auth_openidc.conf]を読み込ませる

```
# sudo vi /etc/httpd/conf/httpd.conf
```
[httpd.conf]の一番下あたりに追記しておく

```
# OIDConnect
Include conf.d/auth_openidc.conf
```

Apacheの再起動

```
# sudo service httpd restart
```
# フロントからアクセスしてみる

ApacheのDocumentRootに適当なHTMLを置き、privateにリンクを付ける。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/270976/dcfaab09-fe1b-f61c-48e3-0a3e32fd9e91.png)

リンクをクリックすると認証が掛かっているためログイン画面が表示される。
URLからログイン画面のドメインがKeycloakサーバーになっていることを確認する。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/270976/cc4c41af-58ba-f774-221f-1e3551e8f15b.png)
ログインID/PWDを入力すると無事認証が通り、認証領域の画面が開けました！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/270976/25d8b959-9970-e0a9-172c-c4557e3f150b.png)

#おわりに
Keycloakには多要素認証や監査機能（アクセスの記録）など多くの機能を標準で備えていそうです。
また、ユーザーフェデレーションもカスタマイズ可能で、ユーザー管理は既存会員DBを利用
（[ユーザー・ストレージSPI](https://keycloak-documentation.openstandia.jp/master/ja_JP/server_development/index.html#_user-storage-spi)）し、認証・認可のみKeycloakを利用するなんて使い方も出来そうです。

インストール自体は比較的容易に出来ますが、本格的に使いこなすにはちゃんとした知識が必要ですね。