keycloakをAWS上にインストール・RDSと連携まで

# この記事について
開発中のソフトウェアのログインにKeycloakを使用するので、セットアップ中に起こった問題とそれらに対するトラブルシューティングを備忘録として残す第二弾です。今回はAWS上にリリース版(Github版ではない)のkeycloakをインストールし、RDSと連携させる手順を説明します。RDSはMySQLを使用しました。
バージョンとクラス
keycloak: 6.0.1
AWS EC2: t2.micro
RDS: db.t2.micro, MySQL
日付: 2019/11/22



## 目次
- [AWSの設定(VPC)](#AWSの設定(VPC))
- [AWSの設定(EC2)](#AWSの設定(EC2))
- [AWSの設定(RDS)](#AWSの設定(RDS))
- [インストール各種](#インストール各種)
- [MySQLの設定](#MySQLの設定)
- [keycloakの設定](#keycloakの設定)



## AWSの設定(VPC)
まず最初に、AWSサーバーがインターネットからアクセスできるようVPCを使ってネットワークを構築していきます。Amazon VPC(Vitual Private Cloud)を使用すると、定義したAWSアカウント専用の仮想ネットワーク内で AWS リソースを起動できます。設定の流れはVPCのIP アドレス範囲を指定して、サブネットを追加し、セキュリティグループを関連付けて、ルートテーブルを設定するといった具合です。

**サブネットとは**
サブネットは、VPC の IP アドレスの範囲です。AWS リソースは、指定したサブネット内に起動できます。インターネットに接続する必要があるリソースにはパブリックサブネットを、インターネットに接続しないリソースにはプライベートサブネットを使用してください。

**インターネットにアクセスする**
デフォルト VPC にはインターネットゲートウェイが含まれ、各デフォルトサブネットはパブリックサブネットです。デフォルトサブネット内に起動するインスタンスにはそれぞれ、プライベート IPv4 アドレスとパブリック IPv4 アドレスが割り当てられています。これらのインスタンスは、このインターネットゲートウェイを介してインターネットと通信できます。インターネットゲートウェイを使用すると、インスタンスは Amazon EC2 ネットワークエッジを介してインターネットに接続できます。
![default-vpc-diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504005/72a954cf-be29-51a1-db0c-90400a4a15eb.png)
デフォルトでは、デフォルト以外のサブネットで起動した各インスタンスにはプライベート IPv4 アドレスが割り当てられていますが、パブリック IPv4 アドレスは割り当てられていません。
![nondefault-vpc-diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504005/09a8df11-74f7-3cb7-31f0-0b481022f401.png)
デフォルト以外のサブネットで起動するインスタンスのインターネットアクセスを有効にするには、インターネットゲートウェイをその VPC (デフォルト VPC でない場合) にアタッチし、インスタンスに Elastic IP アドレスを関連付けます。
![internet-gateway-diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504005/b0b483f8-5a60-e666-c40d-d7d3b8da2317.png)

**1. VPCの作成**
AWSマネジメントコンソールから、VPCを選択
ダッシュボードのVPCから、VPCの作成をクリック
適当に名前をつけ(わかりやすいようにkeycloak_vpcとか)、IPv4 CIDR ブロックにはまずは10.0.0.0/16を入れます
10.0.0.0/16が既に使われていた場合は10.1.0.0/16や20.0.0.0/16などでIPの数字をいい感じに上げます

**2. サブネットの作成**
サブネットにはパブリックなものと、プライベートなものがあります。前述したように、インターネットに接続したい場合はパブリックサブネットが必要になります。それに加え今回はインターネットには直接接続ししないデータベースも作るので、プライベートサブネットも必要になります。といっても初期設定でできる事はあまりありません。ダッシュボードからサブネット、サブネット作成で名前を仮にkeycloak_publicとkeycloak_privateにします。VPCは先ほど作成したkeycloak_vpcに関連付けします。アベイラビリティゾーンはここで設定したものを後の設定でも一貫してください。IPv4 CIDR ブロックは、VPCのIPアドレスの3番目の数字をひとつ大きくした数字を使い、ポートは24から使用できます。(例: VPCが10.0.0.0/16ならサブネットは10.0.1.0/24[keycloak_public]と10.0.2.0/24[keycloak_private])

**3. インターネットゲートウェイの接続**
次にインターネットへ接続するためにインターネットゲートウェイを作成します。同じくダッシュボードのインターネットゲートウェイから、インターネットゲートウェイの作成をクリックしてください。名前をkeycloak_gateとしてさくせいします。次に、インターネットゲートウェイ作成ボタンの隣にあるアクションというボタンから、VPCにアタッチを選択して先ほど作ったkeycloak_vpcに接続します。これでVPCからインターネットへアクセスする入口ができましたが、それをインスタンス(サブネット)に繋げるルートがありません。

**4. ルートテーブルの作成**
そこで、インターネットの入口からVPCの中身を繋ぐルートを作ります。ダッシュボードのルートテーブルからルートテーブルの作成をクリックしてください。名前をkeycloak_routeとしてVPCはkeycloak_vpcを選びます。次に作成ボタンの隣のアクションからルートの編集に行きます。
![スクリーンショット 2019-11-22 13.30.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504005/1f28f8d8-94d9-a9e5-bb91-2c20e744420a.png)
デフォルトで上の様な設定になっていると思います。10.0.0.0/16はVPCのIPアドレスです。ここに送信先を0.0.0.0/0、ターゲットをkeycloak_vpcとしたルートを追加します。これで、インターネットゲートウェイからサブネットにIPの制限なく通信することができます。そして、画面の下の方にサブネットの関連付けというタブがあるので、keycloak_publicに関連付ければ、keycloak_publicサブネットからはインターネットにアクセスできます。

これでVPCの準備は完了です。


##AWSの設定(EC2)
Amazon Elastic Compute Cloud (Amazon EC2) は、AWSクラウドでサイズが変更できるコンピューティングキャパシティーを提供します。必要な数の仮想サーバーを起動して、セキュリティおよびネットワーキングの設定と、ストレージの管理を行います。Amazon EC2 では、要件変更や需要増に対応して迅速に拡張または縮小できるため、サーバートラフィック予測が不要になります。インスタンスと呼ばれる仮想コンピューティング環境で開発・デプロイをしていきます。

**1. インスタンスの作成**
以下の設定で作成していきます
AMI: Amazon Linux 2 AMI (HVM), SSD Volume Type
インスタンスタイプ: 汎用t2.micro(無料利用枠)
ネットワーク: keycloak_vpc
サブネット: keycloak_public
自動割り当てパブリック IP: 有効
作成したら名前をkeycloak_serverとします。


**2. Elastic IP**
これでインスタンスは作成し、VPCにも繋いでいるのでインターネットへのアクセスも可能です。しかし、現時点ではインスタンスを起動する度にパブリックIPアドレスが変わってしまうという欠点があります。これを回避するために、Elastic IPによってインスタンスのパブリックIPを固定します。ダッシュボードからネットワーク&セキュリティにElastic IPがあります。ここからElastic IPアドレスの割り当てをクリック、新たにパブリックIPアドレスを生成します。生成したIPを選択し、アクションタグのElastic IPアドレスの関連付けからkeycloak_serverに関連付けます。インスタンス画面に戻るとパブリックDNS(IPv4)とIPv4パブリックIPが固定されているはずです。



**セキュリティグループ**
実世界でパケットフィルタリングを構成するのは、ルーターやサーバー、もしくは専用のファイアウォール機器だが、AWSでは、インスタンスに対して、構成する「セキュリティグループ」がこの機能を担う。先ほどインスタンスに対して作ったセキュリティグループ(launch-wizard-<数字>)を見ると、デフォルトの構成でinboundを見ると、ポート22にたいして全ての通信(0.0.0.0/0)を許可する、という設定があり、それ以外の設定はないことがわかります。
![スクリーンショット 2019-11-22 17.52.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/504005/4a15ad68-7b4e-287f-72b2-7f1523511176.png)
デフォルトのこの設定では、webサーバーなどをインスタンスに立てたとしても通信できないので、ソフトウェアのインストールとともに、セキュリティグループの構成も変更していきます。最低限必要なのは以下の数個でしょうか。

|タイプ|プロトコル|ポート範囲|ソース|
|:--:|:--:|:--:|:--:|
|HTTP|TCP|80|<自分のIPアドレス>|
|HTTP|TCP|80|< Elastic IP>|
|カスタムTCP|TCP|8080|< Elastic IP>|
|SSH|TCP|22|<自分のIP>|
|SSH|TCP|22|< Elastic IP>|
|MYSQL|TCP|3306|0.0.0.0/0|
|HTTPS|TCP|443|0.0.0.0/0|

接続できなかったり、必要があれば随時追加してください。



## AWSの設定(RDS)
本稼働ではkeycloakは膨大な量のユーザーの情報を保管する可能性があります。EC2サーバーだけではおそらくパンクしてしまうので、Amazonが提供しているデータベースサービスのRDSへデータを保存します。
RDSを作成するには、EC2のダッシュボードではなくAWS マネジメントコンソールに行きます。RDSという項目があるのでクリックして、RDSのダッシュボードに行きます。データベースからデータベースの作成をクリックします。以下の設定で作成します。

作成方法: 標準方法
エンジン: MySQL
バージョン: 5.7.22(ここはデフォルト)
テンプレート: お好みのスペックで
名前: keycloak-rds
マスターユーザー名: admin
パスワード: 適当に
VPC: keycloak_vpc
サブネット: 新規作成
パブリックアクセス可能: はい(重要)
VPCセキュリティグループ: Default + 新規作成(内容はEC2のものと同じ)
アベイラビリティゾーン: EC2と同じ
ポート: 3306

**RDSパラメータグループ設定**
これでデータベースができました。しかしこのまま接続しても文字コードのエラーがでてしまいます。なぜなら、RDSのデフォルトは日本語に対応しているUTF-8ではなく、ラテン語に設定されているからです。

```
mysql> show variables like 'character%';
+--------------------------+-------------------------------------------+
| Variable_name            | Value                                     |
+--------------------------+-------------------------------------------+
| character_set_client     | utf8                                      |
| character_set_connection | utf8                                      |
| character_set_database   | latin1                                    |
| character_set_filesystem | binary                                    |
| character_set_results    | utf8                                      |
| character_set_server     | latin1                                    |
| character_set_system     | utf8                                      |
| character_sets_dir       | /rdsdbbin/mysql-5.7.22.R5/share/charsets/ |
+--------------------------+-------------------------------------------+
8 rows in set (0.00 sec)
```

普通ならば/etc/my.cnfをいじって設定を変更しますが、AWSのSQLの場合それができないのでダッシュボードのパラメータグループから新規にパラメータグループを作成します。作成したら、そのパラメータグループを選択してパラメータの編集をします。
"character"で検索をかけると8つ程パラメータが出てくるので、character_set_filesystem(デフォルトでbinary)以外をutf-8に変更します。

```
mysql> show variables like 'character%';
+--------------------------+-------------------------------------------+
| Variable_name            | Value                                     |
+--------------------------+-------------------------------------------+
| character_set_client     | utf8                                      |
| character_set_connection | utf8                                      |
| character_set_database   | utf8                                      |
| character_set_filesystem | binary                                    |
| character_set_results    | utf8                                      |
| character_set_server     | utf8                                      |
| character_set_system     | utf8                                      |
| character_sets_dir       | /rdsdbbin/mysql-5.7.22.R5/share/charsets/ |
+--------------------------+-------------------------------------------+
8 rows in set (0.00 sec)
```

これで日本語のデータが保存可能になります。
データベースの変更タグから、keycloak-rdsのパラメータグループの変更もお忘れなく。



## インストール各種
**JDK8のインストール**

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

**keycloakのインストール**

```
$ cd /opt
$ sudo wget https://downloads.jboss.org/keycloak/6.0.1/keycloak-6.0.1.zip
$ sudo unzip keycloak-6.0.1.zip
$ sudo mv keycloak-6.0.1 keycloak
```

**keycloakのSQLドライバー(Java Database Connector)のインストール**

```
$ 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
```

```xml:/opt/KEYCLOAK_HOME/modules/system/layers/keycloak/com/mysql/main/module.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>
```

**MySQLのインストール**

```
$ sudo yum install mysql-community-server -y
$ mysqld --version
```

インストールにエラーが出たら下の参考文献をご覧ください(私はなぜかここでつまづいて結構時間取られました)


## MySQLの設定
keycloakからログインする為のユーザーとデータベース作成

```
#EC2コンソールからRDSに接続します
#ユーザーネームとパスワードはRDS作成時に作ったものです
$ mysql -h <keycloak-rdsのエンドポイント> -P 3306 -u admin -p
<password>

#keycloakからログインする時用のユーザー作成
mysql> create user 'keycloak-user' identified by '<パスワード>';

#keycloakのデータ保存用のデータベース作成
mysql> create database keycloakDB character set utf8 collate utf8_unicode_ci;

#keycloak-userにkeycloakDB上の全権限付与
mysql> grant all privileges on keycloakDB.* to 'keycloak-user';

mysql> exit
```


## keycloak内の設定

**1. 外部IP、書き込み権限とログ**

```
#keycloak用のなにかではあったが詳しくは不明(ないとうまく動作しない)
$ export EXTERNAL_IP=$(curl -s 169.254.169.254/latest/meta-data/local-ipv4)

#書き込み権限
$ sudo chmod 777 -R ./

#ログ用ディレクトリ作成
$ sudo mkdir /var/log/keycloak
```

**2. サーバーコンフィグファイルの設定**

```xml:/opt/KEYCLOAK_HOME/standalone/configuration/standalone-ha.xml
#データベースへの接続
<datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true" statistics-enabled="${wildfly.datasources.statistics-enabled:${wildfly.statistics-enabled:false}}">
    <connection-url>jdbc:mysql://<keycloak-rdsのエンドポイント>:3306/keycloakDB?characterEncoding=UTF-8&amp;useSSL=false</connection-url>
    <driver>mysql</driver>
    <security>
        <user-name>keycloak-user</user-name>
        <password><パスワード></password>
    </security>
</datasource>
<drivers>
    <driver name="mysql" module="com.mysql">
        <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
    </driver>
    <driver name="h2" module="com.h2database.h2">
        <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
    </driver>
</drivers>

.
.
.

#KeycloakサーバーのIPアドレスに変更
<interfaces>
        <interface name="management">
            <inet-address value="${jboss.bind.address.management:<EC2プライベートIP>}"/>
        </interface>
        <interface name="public">
            <inet-address value="${jboss.bind.address:<EC2プライベートIP>}"/>
        </interface>
        <interface name="private">
            <inet-address value="${jboss.bind.address.private:<EC2プライベートIP>}"/>
        </interface>
</interfaces>
```

**3. ログインと通信設定**

```:/opt/KEYCLOAK_HOME/
#初回ログイン用にアドミンユーザー作成
$ ./bin/add-user-keycloak.sh -r master -u admin -p admin

#起動
$ ./bin/standalone.sh --server-config=standalone-ha.xml -b <EC2のパブリックDNS> -Djboss.node.name=<EC2のパブリックDNS> -Djboss.bind.address.private=<EC2のパブリックDNS>

#アドミンとして認証情報を設定する
$ ./bin/kcadm.sh config credentials --server http://<プライベートIP>:8080/auth --realm master --user admin --password admin

#SSL requiredをNONEに変更
$ ./bin/kcadm.sh update realms/master -s sslRequired=NONE
change https listener
```

**4. https通信への変更**
一旦Control Cでサーバーを落とし、以下をして再起動します
proxy-address-forwarding="true"を追加

```xml:/opt/KEYCLOAK_HOME/standalone/configuration/standalone-ha.xml
<http-listener name="default" socket-binding="http" proxy-address-forwarding="true" redirect-socket="https" enable-http2="true"/>
```

**5. ログイン**
```http://<IPv4パブリックIP>:8080/auth```にアクセス

完了です



### 参考文献
[Keycloak 開発入門](#https://qiita.com/t-mogi/items/dc13c1c71030fcf84ad6#gui%E3%81%AE%E5%A4%89%E6%9B%B4)
[AWSのEC2で行うAmazon Linux2（MySQL5.7）環境構築](#https://qiita.com/2no553/items/952dbb8df9a228195189)
[Keycloakのインストール方法をわかりやすく手順化してみた](#https://qiita.com/ryota_i/items/69ded3fd950c7f9b70f5)