Ubuntu

Keycloakでアプリケーションにアクセスできる人を制御する

今まではドメインに参加しているアカウント全てに開放するシステムばっかり考えてきたけれど、いま構築中のシステムについてはアクセスできる人を限定したい。



広告


うちではDockerでKeycloak 10.0.2が稼働している。

これを上手く設定し、Samba-ad-dcで特定のグループに属している人だけが、アクセスできるようにしたい。
Active Directoryを扱っている人ならOUに属している人だけ、という条件かもしれない。

アクセスできる人を制御する考え方

いま、Redmineの環境構築をしている。ぱっと見た感じ、ADの情報でグループを作ったりロールを作ったりする機能は見つからない…

良く考えてみれば、関係者以外立ち入り禁止にしたいなら、アプリケーションの側でログイン後にアクセス権で制御するよりも、Keycloakで最初っから入れないようにすれば楽な気がする。
とはいえ、レルムは1つで運用したいしたいので(SSOじゃなくなるし…)、クライアント単位でアクセスできる人を制御したいと考えた。

拡張機能Validate User Role

標準機能でどうにかできないかと考えたがどうにもならない。
SAMLの場合、クライアントに承認関連のタブがない。
どうすりゃいいのか…と探し続けていたら、こんな情報が見つかった。
stackoverflow / Keycloak: Role based client log-in access restriction for users

どうやらこの拡張機能 Validate User Role は認証フローのExecutionで、「その人がロールに含まれていることを確認して true or false」を返してくれるようだ。
Github / ValentinChirikov / kc_user_role_validate_extension

インストール

ソースからビルドしてjarを作成し、それを規定の場所に置けば機能する。

$ sudo apt install maven ← まだインストールされていなかった

$ git clone https://github.com/ValentinChirikov/kc_user_role_validate_extension.git
$ cd kc_user_role_validate_extension/

Keycloakのバージョンが10.0.2だったので、pom.xmlのバージョン部分を書き換えた。

    <parent>
        <artifactId>keycloak-parent</artifactId>
        <groupId>org.keycloak</groupId>
        <version>10.0.2</version>
    </parent>

ビルドするのにちょっと時間が掛かったが、user-role-validator-sources.jar と user-role-validator-sources.jar ができあがった。

$ mvn clean package
…
[INFO] Building jar: /home/rohhie/work/keycloak/kc_user_role_validate_extension/target/user-role-validator-sources.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  01:59 min
[INFO] Finished at: 2021-05-05T04:56:30+09:00
[INFO] ------------------------------------------------------------------------

ファイルを /opt/jboss/keycloak/standalone/deployments にコピーする。

$ sudo chown 1000:0 target/user-role-validator*
$ sudo docker cp -a target/user-role-validator.jar keycloak:/opt/jboss/keycloak/standalone/deployments/

※ソース(user-role-validator-sources.jar)を入れると、Keycloakのコンテナ再起動ができなくなる。

認証フローの設定

ファイルをコピーしてちょっとたってからレルムを選択し、認証のフローを開いたら、Validate User Roleが追加できるようになっていた。
動いていないようなら、Keycloakを再起動すれば良さそう。

まず、認証フローBrowserをコピーし、Redmineを作る。
そして、クライアントRedmineの認証フローを、作成した認証フローRedmineでオーバーライドした。

そして、認証フローRedmineに以下の設定を入れた。

  • ログイン時にロールを確認するようにした。
    • Redmine FormsにExecution(Validate User Role)を追加し、Username Password Formの下に移動させる。
    • Validate User RoleをREQUIREDに設定し、アクションからアクセス可能なロール(Samba-ad-dc上はグループ)を設定する。
  • 他のシステムにログインしていても(Cookieを持っていても)、ユーザーが特定のロールに含まれていることを確認するようにした。
    • 最初のCookieは無効にする。
      代わりにRedmine Cookieというフローを追加し、Redmine Formsの上に移動させる。
    • Redmine CookieをALTERNATIVEにする(失敗してもログイン画面が出るように)。
    • Execution(Cookie)を追加し、これはREQUIREDにした。
      ALTERNATIVEでも動くかなと思ったが、CookieがないときにValid User Roleが必ず呼び出されfalseになるため、ログイン画面が表示されてしまう。
    • Execution(Validate User Role)を追加する。
    • Validate User RoleをREQUIREDに設定し、アクションからアクセス可能なロール(Samba-ad-dc上はグループ)を設定する。

緑でマーキングした範囲が追加設定箇所。

Validate User Roleにロールを指定してみたところ、ロールが付いていないメンバーはログインができなくなった。
具体的には We are sorry… Invalid username or password. が表示される。

ユーザーが特定のグループに含まれていることの示し方

うちはSamba-ad-dcでアカウントを管理しているので、グループを自動的に取り込んでロールにし、グループに含まれる人だったらそのロールが付くようにしたい。

実現のためにやったことは、過去記事ベースにユーザーフェデレーションでrole-ldap-mapperを追加し、「LDAPロールをKeycloakに同期」ボタンをクリックしたことだけ。
LDAPロールを同期すると、グループがKeycloakのロールに登録される。
これでValidate User Roleからロールが選択できるようになる。

じゃあロールにユーザーが登録されている姿が見えるか、というと、Keycloakからは見えない。
見えないけれども、Keycloakは評価のタイミングではちゃんとSamba-ad-dcから情報を持ってきて判断してくれる。
マッパーでLOAD_ROLES_BY_MEMBER_ATTRIBUTE_RECURSIVELYを指定しておけば、子供のグループもたぐって判断してくれる。

これで、関係者しかアクセスできないシステムになった。

トラブルからの復帰

mvnでできあがった user-role-validator-sources.jar をdeployments ディレクトリに放り込んだばっかりに、システムトラブルに発展。
コンテナを再起動したら、Keycloakはエラーで起動しなくなっており、Keycloakが認証を司るシステムにアクセスできなくなったのだった。

このコマンドを実行すると…

$ sudo docker cp -a target/user-role-validator-sources.jar keycloak:/opt/jboss/keycloak/standalone/deployments/

実はこんなログが出ていた。

23:36:51,199 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-2) WFLYSRV0028: Stopped deployment user-role-validator-sources.jar (runtime-name: user-role-validator-sources.jar) in 15ms
23:36:51,203 INFO  [org.jboss.as.server.deployment] (MSC service thread 1-3) WFLYSRV0027: Starting deployment of "user-role-validator-sources.jar" (runtime-name: "user-role-validator-sources.jar")
23:36:51,271 INFO  [org.keycloak.subsystem.server.extension.KeycloakProviderDeploymentProcessor] (MSC service thread 1-4) Deploying Keycloak provider: user-role-validator-sources.jar
23:36:51,342 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-4) MSC000001: Failed to start service jboss.deployment.unit."user-role-validator-sources.jar".POST_MODULE: org.jboss.msc.service.StartException in service jboss.deployment.unit."user-role-validator-sources.jar".POST_MODULE: WFLYSRV0153: Failed to process phase POST_MODULE of deployment "user-role-validator-sources.jar"
        at org.jboss.as.server@11.1.1.Final//org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:183)
        at org.jboss.msc@1.4.11.Final//org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1739)
…

        ... 8 more

23:36:51,344 ERROR [org.jboss.as.controller.management-operation] (DeploymentScanner-threads - 2) WFLYCTL0013: Operation ("full-replace-deployment") failed - address: ([]) - failure description: {"WFLYCTL0080: Failed services" => {"jboss.deployment.unit.\"user-role-validator-sources.jar\".POST_MODULE" => "WFLYSRV0153: Failed to process phase POST_MODULE of deployment \"user-role-validator-sources.jar\"
    Caused by: java.util.ServiceConfigurationError: org.keycloak.authentication.AuthenticatorFactory: Provider by.ese.keycloak.authentication.validators.RoleValidatorFactory not found"}}
23:36:51,385 INFO  [org.jboss.as.server] (DeploymentScanner-threads - 2) WFLYSRV0016: Replaced deployment "user-role-validator-sources.jar" with deployment "user-role-validator-sources.jar"
23:36:51,385 INFO  [org.jboss.as.controller] (DeploymentScanner-threads - 2) WFLYCTL0183: Service status report
WFLYCTL0186:   Services which failed to start:      service jboss.deployment.unit."user-role-validator-sources.jar".POST_MODULE: WFLYSRV0153: Failed to process phase POST_MODULE of deployment "user-role-validator-sources.jar"

※赤でこんなにわかりやすく書いてくれていたのに、見ちゃいないという…

ログインして消せるのであれば消せば良いが、7秒で再起動してたので、以下のコマンドを投入してファイルを消して問題を解消。

$ sudo docker exec -u 0 -it keycloak rm /opt/jboss/keycloak/standalone/deployments/user-role-validator-sources.jar

トラブルを経験して理解した、このディレクトリはポーリングされていて、ファイルが置かれると自動的にインストールしてくれる。
パッケージの形ができあがっていれば、簡単にシステムに拡張機能が追加できる、と。

ただし、拡張機能はあくまでも拡張機能なので、次のバージョンで動作することを保証されているわけではない。
提供者が更新を諦めても泣かない覚悟は必要になるだろう。
とはいえ、今回のソースを見ると「なんとかできそうなレベル」と思えるけれども。

さいごに

この情報を探している過程で幾つもあったのが、承認フローでスクリプトが使えるようにして、なんとか実現しているよ、というやりとりだった。

だけど、この拡張機能は一度インストールしさえすれば、後はGUIで設定ができるのでメンテナンスが楽になると思う。
クライアントが個別に持つロールは redmine.hogehogerole と手で書かなくても、GUIで選択できるし。

現在は☆10個しかないこの拡張機能、潜在的にかなりの需要があるんじゃないかと思うのだった。

広告

コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他

  1. sbin より:

    参考にさせて貰います。
    FreeBSDのJailでKeycloak動かし始めました。ユーザー情報は、ldapから貰いつつmattermostやApacheの認証に使えて中々便利ですね。
    グループ単位での認証例がなくて困りました。この方法でやるか、手を抜いてアトリビュートを追加してマッパーでマッピングさせるか考えてみます。

  2. rohhie より:

    コメント頂きありがとうございます。

    この記事は、特定のユーザーだけにRedmineを使わせたい、それ以外の人は、仮に認証済みでもRedmineには入れないようにしたい、という思想で書いています。Redmineの中で特定の権限を与えるような制御にはなっていませんので、最終的には使えない記事なのかもしれないなと想像しています。

    本来は、Keycloakの先にあるシステムで制御するのが正しい姿であるように思うのですが、Redmineで自動ユーザー登録を実装したところで、Redmineで制限するのは面倒そうだ…と思ってこの方向にしました。

    sbinさんが運用されているシステムに適用できるようなものだとよいのですが。
    書きながら、何か他のシステムからの要求で認証済みの状態にしたあとで、Redmineにアクセスしに行ったらどうなるのか、テストしていなかったと気付きました。誰かに手伝ってもらって試してみなければ。

  3. sbin より:

    返信ありがとうございます。
    特定のユーザーだけに使わせたい用途はあると思います。

    本当は、require ldap-user xxxxxx のように1名づつ指定できれば、
    リストを include するだけで済むので運用は楽だなと思います。

    とりあえず、OIDC_CLAIM_preferred_usernameの値を使うようにしました。
    他のシステムで認証済みでもアプリケーションIDが変わればロールの部分が再評価
    される気がします。