まえがき
社内開発でdockerコンテナを立ててkeycloakを立ち上げているが、自分で1から構築したことなかったのでやってみる。
この記事に書くこと
・Keycloakコンテナ(jboss/keycloak)の構築手順
・「jboss/keycloak」の概要
Keycloakコンテナの構築手順
jboss/keycloakの概要について後述するが、すぐ立ち上げたい時用に構築手順を先述する。
手順1:docker-compose.ymlを用意
version: "3.7"
services:
keycloak:
image: jboss/keycloak:15.0.2
environment:
KEYCLOAK_USER: keycloak
KEYCLOAK_PASSWORD: keycloak
ports:
- 8180:8080
手順2:コンテナ起動
・docker-compose.ymlのあるディレクトリ配下で下記コマンドを実行。
・起動に1分以上かかるので待機。
docker compose up -d
こんな感じのログがまず出力されて
Attaching to keycloak-practice_keycloak_1
keycloak_1 | Added 'keycloak' to '/opt/jboss/keycloak/standalone/configuration/keycloak-add-user.json', restart server to load user
keycloak_1 | -b 0.0.0.0
keycloak_1 | =========================================================================
keycloak_1 |
keycloak_1 | Using Embedded H2 database
keycloak_1 |
keycloak_1 | =========================================================================
keycloak_1 |
keycloak_1 | =========================================================================
keycloak_1 |
keycloak_1 | JBoss Bootstrap Environment
keycloak_1 |
keycloak_1 | JBOSS_HOME: /opt/jboss/keycloak
・
・
こんな感じのログが出たら起動完了。
・
・
keycloak_1 | 21:09:48,383 INFO [org.wildfly.extension.undertow] (ServerService Thread Pool -- 64) WFLYUT0021: Registered web context: '/auth' for server 'default-server'
keycloak_1 | 21:09:48,599 INFO [org.jboss.as.server] (ServerService Thread Pool -- 46) WFLYSRV0010: Deployed "keycloak-server.war" (runtime-name : "keycloak-server.war")
keycloak_1 | 21:09:48,714 INFO [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server
keycloak_1 | 21:09:48,724 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: Keycloak 15.0.2 (WildFly Core 15.0.1.Final) started in 40834ms - Started 692 of 977 services (686 services are lazy, passive or on-demand)
keycloak_1 | 21:09:48,729 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management
keycloak_1 | 21:09:48,730 INFO [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990
手順3:管理画面を開く
・手順2のログの最後にある通り、管理画面は http://127.0.0.1:9990 で公開されている。
・9990はコンテナ内で公開されているポートなので、ローカルPCで公開されているポート8180に置き換えた http://127.0.0.1:8180 にアクセスする。
・問題なければ↓のWelcome Pageが表示される。
手順4:管理コンソールにログイン
・「Administration Console」をクリック
・下記画面が表示されるので、docker-compose.yml内で定義したKEYCLOAK_USER、KEYCLOAK_PASSWORDの値を入力して「Sign In」
・ログインに成功すると、管理コンソールのTOP画面が表示される。
手順5:Realmの設定
・Realmの作成
・RealmにログインするClientの追加
・RealmのUserに割り当てるRoleの追加
・RealmにログインするUserの追加
・Keycloakが生成するIDトークンにRoles情報が含まれるように設定
Realmの作成
・「Add Realm」を選択
・今回は「user」というrealmを作成
RealmにログインするClientの追加
・RealmにログインするClientを追加。クライアントアプリとしてNuxtJSを利用する想定で「nuxt-app」というクライアントを作成する。
・Web Originsに「*」を追加する
Realm内のUserに割り当てるRoleの追加
・RealmにログインするUserには「user」というロールを割り当てるため、ロールを追加する。
・Role一覧に追加されている
RealmにログインするUserの追加
・Realmにログインするユーザーを追加する
・必須入力項目のUsernameに「hoge」とだけ入力して作成
・Users一覧画面に「hoge」が追加されている
・User「hoge」にRole「user」を紐づける
※Roleの紐づけ対象として「Group」もある。
※20人のユーザーに同じRoleの組み合わせを割り当てる場合は、直接Userに割り当てるのではなくGroupに割り当ててそのGroupとUserと紐づける方法が良い。
パスワードの設定
・作成した「hoge」ユーザーにパスワードを設定する(Credentialsタブ)
・TemporaryがONだとログインする度にパスワード変更が求められるので、ここではOFFにしておく。
Keycloakが生成するIDトークンにRoles情報が含まれるように設定
・ログインに成功するとKeycloakから↓のような文字列が返ってくる。これを「IDトークン」と呼ぶ。
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJwd2tvQ0JDOFBRanZjbWpIR3ZFWmhKZFBZNHlTeTlMMERzMHRtbHExLThBIn0.eyJleHAiOjE2NDU5MjgyOTcsImlhdCI6MTY0NTkyNzk5NywiYXV0aF90aW1lIjoxNjQ1OTI3OTk2LCJqdGkiOiIzOTk1Y2U0Mi0wZDZkLTRlYzktOTY1MC00MWNhMjNjYWYxZGUiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgxODAvYXV0aC9yZWFsbXMvdXNlciIsImF1ZCI6Im51eHQtYXBwIiwic3ViIjoiOWFkZmI3YjUtYWIwNS00YTFjLWJhZDgtMTQ0NmM1ZWI2NDk4IiwidHlwIjoiSUQiLCJhenAiOiJudXh0LWFwcCIsIm5vbmNlIjoiYTdhNTJkMDUtN2E4Yy00YjI5LTg4ZGUtYmNmOTQ0OTYzYTE3Iiwic2Vzc2lvbl9zdGF0ZSI6Ijk1MTZjYTM3LTc1NDktNGNiZi1hODcxLTlmMzM3MmJiMzIyZCIsImF0X2hhc2giOiJnOW1ia2F3UXlEMzlJTlNTVnFXTXRRIiwiYWNyIjoiMSIsInNpZCI6Ijk1MTZjYTM3LTc1NDktNGNiZi1hODcxLTlmMzM3MmJiMzIyZCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiIsImRlZmF1bHQtcm9sZXMtdXNlciIsInVzZXIiXSwicHJlZmVycmVkX3VzZXJuYW1lIjoiaG9nZSJ9.KWnR4FBwB5XcIULlj8HMFSyUyHPyjaxaNx61Sg7c_p3A64r7bkf1ctfAo9YOhSIqEuTv45h3EpxSSI6ZrUDVqPO-gX4lqMBrOHwI-L43jhn8lA9ksR-sIRagyxRLUl3nAlyLGxT3PY9xhKQyn8EencnFHlaMnhkuRCH6MeUKsbBXOMoCcaIPtxf2H_eMjB3QU0wfu8N_eaxtPZTiAKOySxctgYvP-4QbgAnS2UX44NFzCdriStK35i940O4dqWxRWSoSJR5fRlnVrvYvAWc72sH-YOqtWiQWvcbfP0lrQ3ccXxK__kMK5BacInKjDik3fHF-e48n7zhgclg24ZE1Lw
※IDトークンについて、下記の記事がとても参考になった。
・↑のIDトークンは「①ヘッダー.②ペイロード.③署名」で構成されており、②ペイロードに認証/ユーザー情報が↓のように格納されている。
{
"exp": 1645927303,
"iat": 1645927003,
"auth_time": 1645926802,
"jti": "c72743e7-0396-4c33-bcef-3d1acc3eccf9",
"iss": "http://localhost:8180/auth/realms/user",
"aud": "nuxt-app",
"sub": "9adfb7b5-ab05-4a1c-bad8-1446c5eb6498",
"typ": "ID",
"azp": "nuxt-app",
"nonce": "023b0897-76f6-4b6d-8cf0-6701e0a57296",
"session_state": "b6baa48e-0192-4286-9492-351a51387cee",
"at_hash": "T5HufySZBmivhsMum_nDuQ",
"acr": "0",
"sid": "b6baa48e-0192-4286-9492-351a51387cee",
"email_verified": false,
"preferred_username": "hoge"
}
・↑のペイロードに「ユーザーhogeはどのロールを割り当てられいるのか」を追加する設定をKeyclaokにて行う。
・Clients > nuxt-app > Mappers で「Create」をクリック
・下記の内容で作成
- MapperTypeに「User Realm Role」が設定されていること
・再度IDトークンを取得して、"roles"があることを確認
{
"exp": 1645927303,
"iat": 1645927003,
"auth_time": 1645926802,
"jti": "c72743e7-0396-4c33-bcef-3d1acc3eccf9",
"iss": "http://localhost:8180/auth/realms/user",
"aud": "nuxt-app",
"sub": "9adfb7b5-ab05-4a1c-bad8-1446c5eb6498",
"typ": "ID",
"azp": "nuxt-app",
"nonce": "023b0897-76f6-4b6d-8cf0-6701e0a57296",
"session_state": "b6baa48e-0192-4286-9492-351a51387cee",
"at_hash": "T5HufySZBmivhsMum_nDuQ",
"acr": "0",
"sid": "b6baa48e-0192-4286-9492-351a51387cee",
"email_verified": false,
"roles": [
"offline_access",
"uma_authorization",
"default-roles-user",
"user"
],
"preferred_username": "hoge"
}
RealmをIMPORT/EXPORTする
EXPORTするための手順
・EXPORT先フォルダがホストPC内のフォルダとなるようVolumesを設定
version: "3.7"
services:
keycloak:
image: jboss/keycloak:15.0.2
environment:
KEYCLOAK_USER: keycloak
KEYCLOAK_PASSWORD: keycloak
ports:
- 8180:8080
volumes:
- ./keycloak/realm-config:/opt/jboss/keycloak/realm-config // Volume設定追加!
・下記コマンドを実行。これでVolumes配下のフォルダにEXPORTファイルが出力される。
docker exec -it <コンテナ名> /opt/jboss/keycloak/bin/standalone.sh
-Djboss.socket.binding.port-offset=100
-Dkeycloak.migration.action=export
-Dkeycloak.migration.provider=singleFile
-Dkeycloak.migration.realmName=<Realm名>
-Dkeycloak.migration.usersExportStrategy=REALM_FILE
-Dkeycloak.migration.file=//opt/jboss/keycloak/realm-config/<出力するJSONファイル名>
・管理画面にある「EXPORT」から出力できると思っていたが、ここからだとユーザ情報が出力されない。
・公式READMEには↑のコマンドを実行するように記載されている。
https://github.com/keycloak/keycloak-containers/blob/main/server/README.md
IMPORTするための手順
・環境変数KEYCLOAK_IMPORTとDB_USERを追加。
- DB_USERの初期値は''(空文字)
- KEYCLOAK_IMPORTを指定することでコンテナ起動時にDBにRealm情報が登録されるようになるのだが、この時にDB_USERが''だとDB接続に失敗する。
・先ほどEXPORTしたファイルが格納されているパスを指定
version: "3.7"
services:
keycloak:
image: jboss/keycloak:15.0.2
environment:
KEYCLOAK_USER: keycloak
KEYCLOAK_PASSWORD: keycloak
DB_USER: keycloak
KEYCLOAK_IMPORT: /opt/jboss/keycloak/realm-config/realms-user.json
ports:
- 8180:8080
volumes:
- ./keycloak/realm-config:/opt/jboss/keycloak/realm-config
・上記設定を行った上でコンテナ起動すると、realmが設定されていることを確認できる。
手順6:themesのカスタマイズ
・各画面(ログイン画面等)のデザイン(theme)をカスタマイズすることができる。
・カスタマイズするベースとなる雛型ファイルは、Keycloakコンテナ内の/opt/jboss/keycloak/themes/
配下に置いてある。
・ftlファイル
- /opt/jboss/keycloak/themes/base
配下
- HTMLのテンプレート的な
・theme.properties
- /opt/jboss/keycloak/themes/keycloak
配下
- テンプレートのftlファイルに、propertiesに定義された値を埋め込む。
・css, imgファイル
- /opt/jboss/keycloak/themes/resources
配下
- ftlファイルで利用するcss, imgファイル
・リポジトリ管理するために、コンテナ内からローカルPCに利用したい雛型ファイルをコピーして編集する。
・ローカルPCにて編集した雛型ファイルをVolumesに配置。
version: "3.7"
services:
keycloak:
image: jboss/keycloak:15.0.2
environment:
KEYCLOAK_USER: keycloak
KEYCLOAK_PASSWORD: keycloak
DB_USER: keycloak
KEYCLOAK_IMPORT: /opt/jboss/keycloak/realm-config/realms-user.json
ports:
- 8180:8080
volumes:
- ./keycloak/realm-config:/opt/jboss/keycloak/realm-config
- ./keycloak/theme-config/themes/user:/opt/jboss/keycloak/themes/user
・カスタマイズ完了したので、あとはKeycloak管理画面よりテーマを指定する。
・編集したテーマを反映するためにstandalone.xml
をVolumesに配置することでキャッシュを無効化する
・standalone.xml
- ~ で取得できる
-
version: "3.7"
services:
keycloak:
image: jboss/keycloak:15.0.2
environment:
KEYCLOAK_USER: keycloak
KEYCLOAK_PASSWORD: keycloak
DB_USER: keycloak
KEYCLOAK_IMPORT: /opt/jboss/keycloak/realm-config/realms-user.json
ports:
- 8180:8080
volumes:
- ./keycloak/realm-config:/opt/jboss/keycloak/realm-config
- ./keycloak/theme-config/themes/user:/opt/jboss/keycloak/themes/user
- ./keycloak/standalone.xml:/opt/jboss/keycloak/standalone/configuration/standalone.xml
- ./keycloak/standalone-ha.xml:/opt/jboss/keycloak/standalone/configuration/standalone-ha.xml
お疲れ様でした
・上記の手順を踏まば、Keycloakを利用してログインするための最低限の設定は完了となる(他にも色々あるがここでは割愛)
・下記の環境で動作確認を実施したので、こちらの記事(後日作成予定)に備忘録として残しておく。
クライアントアプリ:NuxtJS
認証認可サーバ:Keycloak
リソースサーバ:SpringBoot
概要
まず公式ドキュメントを見て、大事そうなことをまとめる。
https://hub.docker.com/r/jboss/keycloak/
① Adminユーザーの設定
・Keycloakでは管理画面にログインして色々設定をする。
・管理画面にログインするために必要なAdminユーザーはデフォルト設定だと作成されない。
By default there is no admin user created so you won't be able to login to the admin console.
・Adminユーザーの作り方1「コンテナ起動時に環境変数KEYCLOAK_USER、KEYCLOAK_PASSWORDを指定」
docker run -e KEYCLOAK_USER=<USERNAME> -e KEYCLOAK_PASSWORD=<PASSWORD> jboss/keycloak
・Adminユーザーの作り方2「起動中のコンテナに環境変数KEYCLOAK_USER、KEYCLOAK_PASSWORDを指定&再起動」
docker exec <CONTAINER> /opt/jboss/keycloak/bin/add-user-keycloak.sh -u <USERNAME> -p <PASSWORD>
docker restart <CONTAINER>
・Adminユーザーの作り方3「ファイル経由...環境変数KEYCLOAK_USER_FILE、KEYCLOAK_PASSWORD_FILEを指定」
・docker-compose.ymlで書くとこんな感じ
version: "3.7"
services:
keycloak:
image: jboss/keycloak:15.0.2
environment:
KEYCLOAK_USER: keycloak
KEYCLOAK_PASSWORD: keycloak
ports:
- ${KEYCLOAK_PORT}:8080 -- ローカルPCで8080ポート公開
② データベース
・jboss/keycloakがサポートしているDBは「H2, MySQL, PostgreSQL, MariaDB, Oracle, SQLServer」
・デフォルトで使用されるDBは「H2」。↓のように「Using Embedded H2 Database」とコンテナ起動時にログが出る。
・H2以外のDBを利用する場合、環境変数DB_VENDORの指定&該当DBコンテナを別で立ててKeycloakコンテナと連携する。
※ 本記事ではH2で検証していく。
③ realmの設定
・ログイン直後に表示される画面は「"Master"のRealm設定画面」である。
・左上の「Master」をホバーすると「Add Realm」ボタンが表示され、ここでRealmを追加できる。
・Realmという単語の定義は人によって色々あると思うが、私は「グループ」という解釈で問題ないと思っている。
・Realmは同義語/類似語として挙げられる「area, domain」も、グループみたいなもんだろう。
・「アプリAにログインしたらアプリBにもアクセス可能!」とするなら、「RealmAにログインしたら、アプリA/アプリBの認証OK!」という具合。