AmazonLinux2 + ALB + nginx + keycloak で環境構築する

# keycloakの環境構築前のよもやま話。

いつもQiitaに記事を書くとき、だいたい書いてることですね。

しばらく技術的なアウトプットをしていなかったのですが、2017年ごろから話題になり始めているkeycloakネタになります。

keycloakとは、認証サーバとなるのですが、OpenAMより少し機能が見劣りするものの、apacheがサポートしてるだけあって、構築が簡単であったり、やってみると意外と面白かったりする認証サーバです。 
国内では日立製作所の方が先駆者となって色々実施されてますが、国内でもkeycloakで検索するとじょじょに広がりを見せているようです。

検索ワードとしては、OpenAMが下火になり、今やkeycloakに盛り上がりがあるのが見てわかると思います。

![google trend.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13837/23df4cb5-8c7a-4fd8-ae4e-96de5bf61e2d.png)

~~認証基盤なんて既に用意してある~~
弊社にもあるのですが、ADやLDAPを連携させるにしても社内の認証システムがとっちらかってるんですよね。
整理できないかなぁという名目も含め、外部に認証サーバを公開するのはリスクがあるし、とかいろんな理由でお試し構築してみています。
できれば今のLDAP以外で自社内踏み台、案件踏み台、案件内のEC2に適用できたら楽になるんでねーのって考えています。

案件で個別にkeycloakを立て、SSOやU2Fや2FAの設定が手軽にできるようになったりするんじゃないか？というのがぼくの今の気持ちだったりします。
案件でよくCMSサーバ構築して引き渡すのですが、一部案件ではセキュリティ事故は起きていないものの、別の要因でセキュリティインシデントになりかけていた案件もありますので、手軽に導入できる基盤がないものかーと探していました。

閑話休題。(ここまでがだいたいいつも試す際に考えてること)

## keycloak本体

本記事ではまだスタンドアローンモードでしか試しておりません。
また、ALBを使う旨の話の記載をしましたが、構築そのものは知識があるものとしてご説明しますので、割愛します。（ALB構築自体は大したことないので）

本当ならNLBのほうが都合がいいんでしょうけど、まだお試しなので今はALBでやってます。
nginxが必要になる記事が多く、直接keycloakに繋げばいいじゃん、とか思ってたのですが、考えが甘かったようで、WildFlyがそもそも外部通信やリモートからのアクセスを不許可にしている、という理由を見て、オオゥ…となりました。(-B 0.0.0.0/0でもプライベートIPじゃcurlからも繋がんないよ！あくまでもlocalhostか127.0.0.1でしか繋がんないよ！)

必要なファイルのダウンロード（本体ダウンロード先）

バージョンアップを考えるとgithubがいい気がしてますが、まだ環境構築までなので調査中。
[https://github.com/keycloak/keycloak](https://github.com/keycloak/keycloak)

本家公式サイト
[https://www.keycloak.org/](https://www.keycloak.org/)

あとはkeycloakの公式サイトに書かれてますが、Client側のアダプタだったり、Proxyだったりが別途必要だったりするようです。

### 必要スペック

EC2インスタンス
インスタンスタイプ:t3.small
ディスクサイズ:20GB（も要らない）

javaなのに珍しくt3.smallで済むのかーと眺めてましたが、スモール設計で構築されているという話もあるようです。

### 構築開始

事前準備作業にnginxの最新のリポジトリを使います。

```shell
[ec2-user ~]% sudo vim /etc/yum.repos.d/nginx.repo
```

nginxの記述の内容はこんな感じです。

```vim
cat /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
```

standardモードで動かすのに必要なミドルウェアのインストール作業です。

```shell
[ec2-user ~]% sudo amazon-linux-extras enable epel java-openjdk11
[ec2-user ~]% sudo yum clean metadata
[ec2-user ~]% sudo amazon-linux-extras install epel java-openjdk11
[ec2-user ~]% sudo yum install nginx
```

githubからkeycloakを入れる場合です。

```shell
[ec2-user opt]% pwd
/opt/
[ec2-user opt]% git clone https://github.com/keycloak/keycloak.git keycloak
```

tar.gzからkeycloakを入れる場合です。

```shell
[ec2-user opt]% pwd
/opt/
[ec2-user opt]% curl -O https://downloads.jboss.org/keycloak/6.0.1/keycloak-6.0.1.tar.gz
[ec2-user opt]% tar zxvf keycloak-6.0.1.tar.gz
[ec2-user opt]% mv keycloak-6.0.1
[ec2-user opt]% ln -sf keycloak-6.0.1 keycloak
```

## systemctlで起動するための作業

次はsystemdに認識させるため、以下のファイルを作ります。

```shell
[ec2-user ~]% sudo vim /etc/systemd/system/keycloak.service
```

```vim
cat /etc/systemd/system/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=
-Xms1024m -Xmx20480m -XX:MaxPermSize=768m"
User=keycloak
Group=keycloak
ExecStart=/opt/keycloak/bin/standalone.sh -b=0.0.0.0
TimeoutStartSec=600
TimeoutStopSec=600

[Install]
WantedBy=multi-user.target
```

### 権限変更

権限を修正していきます。

```shell
[ec2-user ~]% mkdir /var/log/keycloak
[ec2-user ~]% useradd --system --user-group keycloak
[ec2-user ~]% chown -R keycloak:keycloak /opt/keycloak
[ec2-user ~]% chown -R keycloak:keycloak /opt/keycloak-6.0.1
[ec2-user ~]% chown -R keycloak:keycloak /var/log/keycloak
[ec2-user ~]% chmod -R g+w /opt/keycloak-6.0.1
[ec2-user ~]% chmod -R g+w /var/log/keycloak
```

### nginx.confの修正

nginxのconfを作ります。

```shell
[ec2-user ~]% sudo vim /etc/nginx/conf.d/keycloak.conf
```

```vim
cat /etc/nginx/conf.d/keycloak.conf
upstream keycloak-user {
  server 127.0.0.1:8080;
}

server {
    listen              80 default_server;
    server_name         yourauth.own.host;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    location / {
        proxy_pass http://keycloak-user;
        proxy_redirect http://yourauth.own.host/ /;
    }
}

upstream keycloak-management {
  server 127.0.0.1:9990;
}

server {
    listen              9900 ;
    server_name         yourmanagement.own.host;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    location / {
        proxy_pass http://keycloak-management;
        proxy_redirect http://yourmanagement.own.host/ /;
    }
}
```

### 初期アカウント作成

管理者アカウントの作成とユーザの作成です。
管理アカウントは `add-user-keycloak.sh` です
ユーザの作成は `add-user.sh` です。

add-user-keycloak.shは引数が必要ですが、add-user.shは対話式になっているので何言ってるか理解しながらやればできました。
またadd-user-keycloak.shは引数に `!` を含められませんでした。
add-user.shはユーザ名に `_` が使えませんでした。なんでだよ。

管理者アカウントの作成の作成です。

```shell
[ec2-user ~]% sudo /opt/keycloak/bin/add-user-keycloak.sh -r master -u [USERNAME] -p [PASSWORD]
```

ManagementRealmの作成です。(検証で作ったけどこっちも直さないとな…。）

```shell
[ec2-user ~]% sudo /opt/keycloak/bin/add-user.sh

What type of user do you wish to add?
 a) Management User (mgmt-users.properties)
 b) Application User (application-users.properties)
(a): a

Enter the details of the new user to add.
Using realm 'ManagementRealm' as discovered from the existing property files.
Username : test1
Password recommendations are listed below. To modify these restrictions edit the add-user.properties configuration file.
 - The password should be different from the username
 - The password should not be one of the following restricted values {root, admin, administrator}
 - The password should contain at least 8 characters, 1 alphabetic character(s), 1 digit(s), 1 non-alphanumeric symbol(s)
Password :
Re-enter Password :
What groups do you want this user to belong to? (Please enter a comma separated list, or leave blank for none)[  ]:
About to add user 'test' for realm 'ManagementRealm'
Is this correct yes/no? yes
Added user 'test1' to file '/opt/keycloak/standalone/configuration/mgmt-users.properties'
Added user 'test1' to file '/opt/keycloak/domain/configuration/mgmt-users.properties'
Added user 'test1' with groups  to file '/opt/keycloak/standalone/configuration/mgmt-groups.properties'
Added user 'test1' with groups  to file '/opt/keycloak/domain/configuration/mgmt-groups.properties'
Is this new user going to be used for one AS process to connect to another AS process?
e.g. for a slave host controller connecting to the master or for a Remoting connection for server to server EJB calls.
yes/no? yes
To represent the user add the following to the server-identities definition <secret value="????????????" />
```

ApplicationRealmの作成です。(これはいらなかったけどあとで削除できる）

```shell
[ec2-user ~]% sudo /opt/keycloak/bin/add-user.sh

What type of user do you wish to add?
 a) Management User (mgmt-users.properties)
 b) Application User (application-users.properties)
(a): b

Enter the details of the new user to add.
Using realm 'ApplicationRealm' as discovered from the existing property files.
Username : test2
Password recommendations are listed below. To modify these restrictions edit the add-user.properties configuration file.
 - The password should be different from the username
 - The password should not be one of the following restricted values {root, admin, administrator}
 - The password should contain at least 8 characters, 1 alphabetic character(s), 1 digit(s), 1 non-alphanumeric symbol(s)
Password :
Re-enter Password :
What groups do you want this user to belong to? (Please enter a comma separated list, or leave blank for none)[  ]:
About to add user 'test' for realm 'ApplicationRealm'
Is this correct yes/no? yes
Added user 'test2' to file '/opt/keycloak/standalone/configuration/application-users.properties'
Added user 'test2' to file '/opt/keycloak/domain/configuration/application-users.properties'
Added user 'test2' with groups  to file '/opt/keycloak/standalone/configuration/application-roles.properties'
Added user 'test2' with groups  to file '/opt/keycloak/domain/configuration/application-roles.properties'
Is this new user going to be used for one AS process to connect to another AS process?
e.g. for a slave host controller connecting to the master or for a Remoting connection for server to server EJB calls.
yes/no? yes
To represent the user add the following to the server-identities definition <secret value="????????????" />
```

作成した管理者やユーザのファイルは以下に出力されます。

```shell
# 管理者のファイル
[ec2-user ~]% sudo cat /opt/keycloak/standalone/configuration/keycloak-add-user.json

# ユーザのファイル
[ec2-user ~]% sudo cat /opt/keycloak/standalone/configuration/application-users.properties
[ec2-user ~]% sudo cat /opt/keycloak/domain/configuration/application-users.properties
[ec2-user ~]% sudo cat /opt/keycloak/standalone/configuration/application-roles.properties
[ec2-user ~]% sudo cat /opt/keycloak/domain/configuration/application-roles.properties
```

### keycloakとnginxの起動

あとは淡々と以下のコマンドを実行していきます。

```shell
[ec2-user ~]% sudo systemctl enable keycloak
[ec2-user ~]% sudo systemctl enable nginx
[ec2-user ~]% sudo systemctl start keycloak
[ec2-user ~]% sudo systemctl start nginx
```

## 動作確認

以下のコマンドを叩いて、メッセージが帰ってきたらOKです。

```shell
[ec2-user ~]% curl http://localhost:8080/
[ec2-user ~]% curl http://your.own.host/
```

## 

### 感想

あー疲れた…。
まだ使い方がわかってないので色々これから調整しながら調べないとな…。
軽く触ったけど、なんか微妙に参考にした内容と違ってる箇所があるようなので、また作り直してみるかユーザ消してやり直してみますかね。
add-user-keycloak.shで本来なら開けるはずの画面が開けてないので何かあるっぽいなー。

あ、ALBに終端させるのはこの流れで、セキュリティグループとかポートを80でやれば接続できるっす。

# 参考にした記事たち

http://sig9.hatenablog.com/entry/2019/07/16/000000
https://yoshinorin.net/2018/03/22/keycloak-with-nginx-https-reverse-proxy/
https://qiita.com/tamura__246/items/13fc301e9409fef77bf3

### 2019.7.30 追記

他にも加筆修正した箇所はありますが、大きくこれいらんのかーい！ってツッコミの入った箇所は `keycloak/standalone/configuration/standalone.xml` のファイルに対する修正でした。

以下の設定はALBを使って終端させる場合は不要となります。(nginxでhttpsを受ける場合は必要だったようです)

477行目ぐらいに `proxy-address-forwarding="true"` を記述します。

```shell
[ec2-user opt]% sudo vim keycloak/standalone/configuration/standalone.xml
```

変更前

```vim
                <http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true"/>
```

変更後

```vim
                <http-listener name="default" socket-binding="http" proxy-address-forwarding="true" redirect-socket="https" enable-http2="true"/>
```

477と打ち込んで、 `G` を押すと一気に飛べます。（知ってる人は多いけど）