要體驗強大的 Keycloak 這套開源的身分認證與存取管理系統,最簡單的方式莫過於透過 Docker/Podman 執行 Keycloak 的開發模式了。你可以在短時間內就可以架設出一套擁有 OpenID Connect (OIDC) 與 OAuth 2.0 提供者的完整實作,是一套功能強大同時又免費的解決方案。這篇文章我就來描述一下 Keycloak 啟動與初始化設定的過程。
啟動 Keycloak 伺服器
-
拉取最新版容器映象
docker pull quay.io/keycloak/keycloak:latest
-
啟動 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
初始化設定
-
建立 Realms (領域)
由於預設已經有一個名為 master
的領域(Realm),所以你不一定要建立新的。不過,這邊有幾個重要的觀念必須事先建立:
- 每個不同的 Realms 之間是互相獨立隔離的
- 一個 Realms 只能管理它下面所屬的使用者
- 一個使用者只能屬於並且能登入到一個 Realms
-
建立 Clients (用戶端)
這裡的選項很多,每個都要消化一下!
General Settings
這裡只要設定 Client ID 與 Name 即可。
Capability config
在 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_id
與 client_secret
的驗證,也就是 OAuth 2.0 的 Authorization Code Flow
這個授權流程在取得 Token 時一定會用到的資訊。
另外,這個 Authentication flow
寫的也有點隱晦,前 4 個跟 OAuth 2.0 標準中定義的流程也很難對的上,以下我概要說明一下:
Login settings
這裡只有 Valid redirect URIs
是必要設定,而 Web origins 主要是設定 CORS 設定,輸入 +
就代表直接拿 Valid redirect URIs
當作 CORS 的 Origin!
按下 SAVE
儲存!
Credentials
這個 Credentials
頁籤要先建立完用戶端之後才會出現,你在這個時候才能建立 OAuth 2.0 所需的 Client secret 來用!
-
建立 Realm roles (領域角色)
建立特定領域下的角色,有些內建的角色擁有不同的權限,角色可以設定 Attributes,也可以把使用者指派到特定角色中。
-
建立 Users (使用者)
你可以在領域下建立多位不同的使用者,用來進行 SSO (Single-Sign On) 或通過 OpenID Connect 認證流程。
-
建立 Groups (群組)
你可以在領域下建立多個不同的群組,群組可以設定 Attributes,也可以設定 Role Mapping,群組是可以分層的(hierarchical),一個群組可以包含多個子群組,但一個子群組只能隸屬於一個父群組。父群組的 Attributes 與 Role Mapping 會自動繼承給所有他的子群組。
這在 ABAC (Attribute-based Access Control) 架構下很好用。
取得端點資訊
要跟 Keycloak 整合 OAuth 2.0 與 OpenID Connect,最重要的就是取得所有相關的端點資訊,這部分資訊放在 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",
}
相關連結