The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

如何用 Docker 快速上手 Keycloak 開發模式

要體驗強大的 Keycloak 這套開源的身分認證與存取管理系統,最簡單的方式莫過於透過 Docker/Podman 執行 Keycloak 的開發模式了。你可以在短時間內就可以架設出一套擁有 OpenID Connect (OIDC) 與 OAuth 2.0 提供者的完整實作,是一套功能強大同時又免費的解決方案。這篇文章我就來描述一下 Keycloak 啟動與初始化設定的過程。

啟動 Keycloak 伺服器

  1. 拉取最新版容器映象

    docker pull quay.io/keycloak/keycloak:latest
    
  2. 啟動 Keycloak 容器 (開發模式)

    docker run --name keycloak_test -d -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=changeME quay.io/keycloak/keycloak:latest start-dev
    

    以下是初次啟動時的 Docker Logs

    docker logs keycloak_test
    
    Updating the configuration and installing your custom providers, if any. Please wait.
    2023-04-21 06:35:34,329 INFO  [io.quarkus.deployment.QuarkusAugmentor] (main) Quarkus augmentation completed in 5974ms
    2023-04-21 06:35:35,897 INFO  [org.keycloak.quarkus.runtime.hostname.DefaultHostnameProvider] (main) Hostname settings: Base URL: <unset>, Hostname: <request>, Strict HTTPS: false, Path: <request>, Strict BackChannel: false, Admin URL: <unset>, Admin: <request>, Port: -1, Proxied: false
    2023-04-21 06:35:37,128 WARN  [io.quarkus.agroal.runtime.DataSources] (main) Datasource <default> enables XA but transaction recovery is not enabled. Please enable transaction recovery by setting quarkus.transaction-manager.enable-recovery=true, otherwise data may be lost if the application is terminated abruptly
    2023-04-21 06:35:37,846 INFO  [org.infinispan.SERVER] (keycloak-cache-init) ISPN005054: Native IOUring transport not available, using NIO instead: io.netty.incubator.channel.uring.IOUring
    2023-04-21 06:35:38,029 WARN  [org.infinispan.CONFIG] (keycloak-cache-init) ISPN000569: Unable to persist Infinispan internal caches as no global state enabled
    2023-04-21 06:35:38,062 WARN  [org.infinispan.PERSISTENCE] (keycloak-cache-init) ISPN000554: jboss-marshalling is deprecated and planned for removal
    2023-04-21 06:35:38,080 INFO  [org.infinispan.CONTAINER] (keycloak-cache-init) ISPN000556: Starting user marshaller 'org.infinispan.jboss.marshalling.core.JBossUserMarshaller'
    2023-04-21 06:35:38,226 INFO  [org.keycloak.broker.provider.AbstractIdentityProviderMapper] (main) Registering class org.keycloak.broker.provider.mappersync.ConfigSyncEventListener
    2023-04-21 06:35:39,530 INFO  [org.keycloak.quarkus.runtime.storage.legacy.liquibase.QuarkusJpaUpdaterProvider] (main) Initializing database schema. Using changelog META-INF/jpa-changelog-master.xml
    2023-04-21 06:35:41,141 INFO  [org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory] (main) Node name: node_126670, Site name: null
    2023-04-21 06:35:41,277 INFO  [org.keycloak.services] (main) KC-SERVICES0050: Initializing master realm
    2023-04-21 06:35:42,875 INFO  [io.quarkus] (main) Keycloak 21.1.0 on JVM (powered by Quarkus 2.13.7.Final) started in 8.393s. Listening on: http://0.0.0.0:8080
    2023-04-21 06:35:42,875 INFO  [io.quarkus] (main) Profile dev activated.
    2023-04-21 06:35:42,876 INFO  [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, jdbc-h2, jdbc-mariadb, jdbc-mssql, jdbc-mysql, jdbc-oracle, jdbc-postgresql, keycloak, logging-gelf, micrometer, narayana-jta, reactive-routes, resteasy, resteasy-jackson, smallrye-context-propagation, smallrye-health, vertx]
    2023-04-21 06:35:43,025 INFO  [org.keycloak.services] (main) KC-SERVICES0009: Added user 'admin' to realm 'master'
    2023-04-21 06:35:43,028 WARN  [org.keycloak.quarkus.runtime.KeycloakMain] (main) Running the server in development mode. DO NOT use this configuration in production.
    

    從 Log 可以看出,他預設會初始化一個名為 master 的 realm (領域),而且新增了一位名為 admin 的使用者到 master realm 中。除此之外,開發模式的預設設定比較不安全,若要正式環境使用請參考 Configuring Keycloak for production 文件說明。

    預設網址: http://localhost:8080 (點選 Administration Console 進行登入)

    預設帳號: admin

    預設密碼: changeME

    Keycloak Administration UI

初始化設定

  1. 建立 Realms (領域)

    由於預設已經有一個名為 master 的領域(Realm),所以你不一定要建立新的。不過,這邊有幾個重要的觀念必須事先建立:

    • 每個不同的 Realms 之間是互相獨立隔離的
    • 一個 Realms 只能管理它下面所屬的使用者
    • 一個使用者只能屬於並且能登入到一個 Realms
  2. 建立 Clients (用戶端)

    這裡的選項很多,每個都要消化一下!

    General Settings

    image

    這裡只要設定 Client IDName 即可。

    Capability config

    image

    在 Keycloak 之中,用戶端區分成三種不同的 Access Type (存取類型):

    • Access Type=confidential 用在可以妥善保存 client_secret 的情境
    • Access Type=public 用在 client_secret 無法妥善保存的情境 (SPA)
    • Access Type=bearer-only 用在 Web API 只能用 Bearer Token 需要直接呼叫 RS (資源伺服器) 的情境

    這裡的 Client authentication 如果設定為 On 的話,所代表的意思就是要對 Client 進行 client_idclient_secret 的驗證,也就是 OAuth 2.0 的 Authorization Code Flow 這個授權流程在取得 Token 時一定會用到的資訊。

    另外,這個 Authentication flow 寫的也有點隱晦,前 4 個跟 OAuth 2.0 標準中定義的流程也很難對的上,以下我概要說明一下:

    Login settings

    image

    這裡只有 Valid redirect URIs 是必要設定,而 Web origins 主要是設定 CORS 設定,輸入 + 就代表直接拿 Valid redirect URIs 當作 CORS 的 Origin!

    按下 SAVE 儲存!

    Credentials

    image

    這個 Credentials 頁籤要先建立完用戶端之後才會出現,你在這個時候才能建立 OAuth 2.0 所需的 Client secret 來用!

  3. 建立 Realm roles (領域角色)

    建立特定領域下的角色,有些內建的角色擁有不同的權限,角色可以設定 Attributes,也可以把使用者指派到特定角色中。

  4. 建立 Users (使用者)

    你可以在領域下建立多位不同的使用者,用來進行 SSO (Single-Sign On) 或通過 OpenID Connect 認證流程。

  5. 建立 Groups (群組)

    你可以在領域下建立多個不同的群組,群組可以設定 Attributes,也可以設定 Role Mapping,群組是可以分層的(hierarchical),一個群組可以包含多個子群組,但一個子群組只能隸屬於一個父群組。父群組的 Attributes 與 Role Mapping 會自動繼承給所有他的子群組。

    這在 ABAC (Attribute-based Access Control) 架構下很好用。

取得端點資訊

要跟 Keycloak 整合 OAuth 2.0 與 OpenID Connect,最重要的就是取得所有相關的端點資訊,這部分資訊放在 Configure > Realm settings 頁面下方:

Configure > Realm settings

注意:每個 Realm 因為都是獨立的,所以不同的 Realm 都會有不同的 Endpoints,所以才必須要到上述頁面查找資訊。

本地開發模式 master 領域的端點如下:

{
  "issuer": "http://localhost:8080/realms/master",
  "authorization_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/auth",
  "token_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/token",
  "introspection_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/token/introspect",
  "userinfo_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/userinfo",
  "end_session_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/logout",
  "jwks_uri": "http://localhost:8080/realms/master/protocol/openid-connect/certs",
  "check_session_iframe": "http://localhost:8080/realms/master/protocol/openid-connect/login-status-iframe.html",
  "registration_endpoint": "http://localhost:8080/realms/master/clients-registrations/openid-connect",
  "revocation_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/revoke",
  "device_authorization_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/auth/device",
  "backchannel_authentication_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/ext/ciba/auth",
  "pushed_authorization_request_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/ext/par/request",
}

相關連結

留言評論