💨

Quarkus と Keycloak を使ったロールベース認可の実装

に公開

今回は Quarkus と Keycloak を組み合わせた ロールベース認可(RBAC) を試してみたので残します。
ロールベース認可 とは、その名の通り 特定のロールを持っているユーザのみリクエストを許可する というものです。
https://ja.quarkus.io/guides/security-keycloak-authorization

この記事ではだらだらと手順を書きましたが、Keycloak の設定さえできていれば、Quarkus の実装はとても簡単で、REST サービスに @RolesAllowed アノテーションを付けるだけ です。
Quarkus 側の実装でいつもと違うところはそれだけです。(設定ファイルに Keycloak の情報を書く必要はありますが、、)

そのため、Keycloak に詳しい方は、quarkus アプリケーションの設定 以降を読めば十分かと思います。

環境

  • Oracle Linux 8.10
  • quarkus 3.21.0
  • quarkus CLI 3.21.0
  • Open JDK 17.0.14
  • Podman 4.9.4-rhel
  • keycloak 23.0

ロールベース認可の設定手順

今回は keycloak は Podman で起動して、quarkus は 開発モードで実行します。

keycloak の起動

まずは Podman で keycloak の起動をします。今回は version 23 を使います。

podman run -p 8180:8080 --env KEYCLOAK_ADMIN=admin --env KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:23.0 start-dev

この後 quarkus を 8080 ポートで起動するので、8180 にしておきます。

Keycloak の realm, Client を作成する

まずは localhost:8180 で接続し admin/admin管理コンソール に入って、必要な設定をしてきます。

ということでまずは、Realm と Client を作成します。
今回は、quarkus という Realm と、quarkus-client という名前の Client を作成しました。
で、Client は以下のように Client authenticationAuthorization を On にしてください。他はデフォルトでよいです。

またあとで、Client Secret は使うので、控えておいてください。

keycloak のユーザとロールを作成する

次に、ユーザとそのパスワードの設定、それとロールを作成します。私は以下のようにコナンっぽい感じで作成しました。(デフォルトのロールは Unassign してます。)

ユーザ ロール
Conan Child
Kir BlackOrganization
Bourbon BlackOrganization

ユーザはこんな感じ

ロールはこんな感じ

quarkus アプリケーションのひな形作成

とりあえずいつもの通り、ひな形の作成をします。

export GROUPID=com.marcha
export AETIFACTID=access-control
export VERSION=1.0.0
quarkus create app -P io.quarkus.platform:quarkus-bom:3.21.0 ${GROUPID}:${AETIFACTID}:${VERSION}

次に、oidc extension を追加します。

cd ${AETIFACTID}
quarkus extension add oidc,rest-jackson

quarkus アプリケーションの設定

実装する前に、quarkus の設定ファイルに、認可サーバとして keycloak を利用するという設定をする必要があります。

src/main/resources/application.properties
quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.client-id=quarkus-client
quarkus.oidc.credentials.secret=xxxxxxxxxxxxx
quarkus.oidc.tls.verification=none
quarkus.keycloak.devservices.enabled=false

quarkus.oidc.credentials.secret は、管理コンソールから clients > quarkus-client > Credentials > Client Secret で確認できます。
また、quarkus.keycloak.devservices.enabled=false を設定しないと、quarkus がdocker を使って keycloak コンテナを立ち上げてくれちゃいます。私の環境は docker が入っていないので false にしています。

quarkus アプリケーションの実装

さて、実装してきます。
@RolesAllowed アノテーションを使って、ユーザーのロール(役割)に基づいてアクセス制御を行います。

src/main/java/com/marcha/SecureResource.java
package com.marcha;

import io.quarkus.security.identity.SecurityIdentity;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/secure")
public class SecureResource {

    @Inject
    SecurityIdentity securityIdentity;

    @GET
    @Path("/normal")
    @Produces(MediaType.TEXT_PLAIN)
    public String getNormalResource() {
        String name = securityIdentity.getPrincipal().getName();
        return name + " got the normal data!";
    }

    @GET
    @Path("/black")
    @RolesAllowed("BlackOrganization")
    @Produces(MediaType.TEXT_PLAIN)
    public String getBlackResource() {
        String name = securityIdentity.getPrincipal().getName();
        return name + " got the black secret data!";
    }
}

/secure/normal は誰でもアクセスできますが、/secure/black は、@RolesAllowed("BlackOrganization") アノテーションを使って、BlackOrganization ロールを持つユーザー(黒の組織)だけがアクセスできるようにしています。とっても簡単ですね。

動作確認

curl で動作確認をしてみます。

/secure/normal にアクセスする

$ curl -s -X GET http://localhost:8080/secure/normal
 got the normal data!

ログインしてないので、名前は表示されませんが、アクセスできました

次は、Conan ユーザとしてログインして、アクセストークンを取得します。

export access_token=$(\
    curl -X POST http://localhost:8180/realms/quarkus/protocol/openid-connect/token \
    --user quarkus-client:xxxxxxxxxxx \
    -H 'content-type: application/x-www-form-urlencoded' \
    -d 'username=conan&password=conan&grant_type=password' | jq --raw-output '.access_token' \
 )

これを使って、もう一度 /secure/normal にアクセスします。

$ curl -s -X GET http://localhost:8080/secure/normal -H "Authorization: Bearer "$access_token
conan got the normal data!

OK です!今度は名前が表示されています!

/secure/black にアクセスする

こちらは、黒の組織しかアクセスできないはずです。conan ユーザでリクエストしてみましょう。

$ curl -v -X GET http://localhost:8080/secure/black -H "Authorization: Bearer "$access_token
...
 HTTP/1.1 403 Forbidden

想定通り 403 で返ってきました。OK です。

では、黒の組織の Bourbon でログインしてみます。

$ export access_token=$(\
    curl -X POST http://localhost:8180/realms/quarkus/protocol/openid-connect/token \
    --user quarkus-client:xxxxxxxxxxx \
    -H 'content-type: application/x-www-form-urlencoded' \
    -d 'username=bourbon&password=bourbon&grant_type=password' | jq --raw-output '.access_token' \
 )
$ curl -s -X GET http://localhost:8080/secure/black -H "Authorization: Bearer "$access_token
bourbon got the black secret data!

OK です!名前も表示されていて、getBlackResource にアクセスできています!


まとめ

ということで今回はロールベースの認可(ロールベースのアクセス制御)をやってみました。
ロールベースの認可のより詳しい情報は、ドキュメントを参考にしてください。

今回は、Quarkus にアノテーションを付与しましたが、実は Keycloak の設定でアクセス制御ができます。つまり、Quarkus の実装から完全に分離できるということです。時間があったらそちらも紹介します。
今回はこのあたりで!

次回は、スコープを使った認可制御をしてみたいと思います。ではまた!

GitHubで編集を提案

Discussion