Document persistent sessions are enabled by default

Closes #32387

Signed-off-by: Michal Hajas <mhajas@redhat.com>
Signed-off-by: Alexander Schwartz <aschwart@redhat.com>
Co-authored-by: Pedro Ruivo <pruivo@users.noreply.github.com>
Co-authored-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
Michal Hajas 2024-08-30 11:20:58 +02:00 committed by GitHub
parent 3a8160b71d
commit af53af1506
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 113 additions and 89 deletions

View file

@ -153,3 +153,12 @@ Instead, prefer using the `federationLink` property to obtain the provider to wh
GELF support has been deprecated for a while now, and with this release it has been finally removed from {project_name}.
Other log handlers are available and fully supported to be used as a replacement of GELF, for example Syslog. For details
see the https://www.keycloak.org/server/logging[Logging guide].
= All user sessions are persisted by default
{project_name} 25 introduced the feature `persistent-user-sessions`. With this feature enabled all user sessions are persisted in the database as opposed to the previous behavior where only offline sessions were persisted.
In {project_name} 26, this feature is enabled by default. This means that all user sessions are persisted in the database by default.
It is possible to revert this behavior to the previous state by disabling the feature. Follow the `Volatile user sessions` section in https://www.keycloak.org/server/caching[Configuring distributed caches] guide for more details.
For information on how to upgrade, see the link:{upgradingguide_link}[{upgradingguide_name}].

View file

@ -9,11 +9,3 @@ When users log into realms, {project_name} maintains a user session for each use
* Revoke tokens.
* Set up token timeouts.
* Set up session timeouts.
ifeval::[{project_community}==true]
By default, online user and online client sessions are only kept in memory, and will be lost if all {project_name} nodes are shut down for maintenance or during upgrades.
If the feature `persistent-user-sessions` is enabled, {project_name} online user and online client sessions are saved to the database to persist them across restarts and upgrades.
See https://www.keycloak.org/server/caching[Configuring distributed caches] on how to configure this.
endif::[]

View file

@ -19,8 +19,8 @@ Clicking *Sign out all active sessions* does not revoke outstanding access token
.Procedure
. Click *Clients* in the menu.
. Click the *Sessions* tab.
. Click a client to see that client's sessions.
. Click the *Sessions* tab.
+
.Client sessions
image:images/client-sessions.png[Client sessions]
@ -29,8 +29,8 @@ image:images/client-sessions.png[Client sessions]
.Procedure
. Click *Users* in the menu.
. Click the *Sessions* tab.
. Click a user to see that user's sessions.
. Click the *Sessions* tab.
+
.User sessions
image:images/user-sessions.png[User sessions]

View file

@ -8,7 +8,7 @@ During https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess[offli
The client application is responsible for persisting the offline token in storage and then using it to retrieve new access tokens from the {project_name} server.
The difference between a refresh token and an offline token is that an offline token never expires and is not subject to the `SSO Session Idle` timeout and `SSO Session Max` lifespan. The offline token is valid after a user logout or server restart. You must use the offline token for a refresh token action at least once per thirty days or for the value of the <<_offline-session-idle, Offline Session Idle>>.
The difference between a refresh token and an offline token is that an offline token never expires and is not subject to the `SSO Session Idle` timeout and `SSO Session Max` lifespan. The offline token is valid after a user logout. You must use the offline token for a refresh token action at least once per thirty days or for the value of the <<_offline-session-idle, Offline Session Idle>>.
If you enable <<_offline-session-max-limited, Offline Session Max Limited>>, offline tokens expire after 60 days even if you use the offline token for a refresh token action. You can change this value, <<_offline-session-max, Offline Session Max>>, in the Admin Console.
@ -22,12 +22,11 @@ To issue an offline token, users must have the role mapping for the realm-level
Clients can request an offline token by adding the parameter `scope=offline_access` when sending their authorization request to {project_name}. The {project_name} OIDC client adapter automatically adds this parameter when you use it to access your application's secured URL (such as, $$http://localhost:8080/customer-portal/secured?scope=offline_access$$). The Direct Access Grant and Service Accounts support offline tokens if you include `scope=offline_access` in the authentication request body.
Offline sessions are besides the Infinispan caches stored also in the database. Whenever the {project_name} server is restarted or an offline session is evicted from the Infinispan cache, it is still available in the database. Any following attempt to access the offline session will load the session from the database, and also import it to the Infinispan cache.
{project_name} will limit its internal cache for offline user and offline client sessions to 10000 entries by default, which will reduce the overall memory usage for offline sessions.
Items which are evicted from memory will be loaded on-demand from the database when needed.
To set different sizes for the caches, edit {project_name}'s cache config file to set a `+<memory max-count="..."/>+` for those caches.
To reduce memory requirements, we introduced a configuration option to shorten lifespan for imported offline sessions. Such sessions will be evicted from the Infinispan caches after the specified lifespan, but still available in the database. This will lower memory consumption, especially for deployments with a large number of offline sessions. Currently, the offline session lifespan override is disabled by default.
ifeval::[{project_community}==true]
This override is only available if the feature `persistent-user-sessions` is disabled.
endif::[]
If you disabled feature `persistent-user-sessions`, it is possible to reduce memory requirements using a configuration option that shortens lifespan for imported offline sessions. Such sessions will be evicted from the Infinispan caches after the specified lifespan, but still available in the database. This will lower memory consumption, especially for deployments with a large number of offline sessions.
To specify the lifespan override for offline user sessions, start {project_name} server with the following parameter:
@ -42,9 +41,3 @@ Similarly for offline client sessions:
----
--spi-user-sessions-infinispan-offline-client-session-cache-entry-lifespan-override=<lifespan-in-seconds>
----
ifeval::[{project_community}==true]
If the feature `persistent-user-sessions` is enabled, {project_name} will limit its internal cache for offline user and offline client sessions to 10000 entries by default, which will reduce the overall memory usage for offline sessions.
Items which are evicted from memory will be loaded on-demand from the database when needed.
To set different sizes for the caches, edit {project_name}'s cache config file to set a `+<memory max-count="..."/>+` for those caches.
endif::[]

View file

@ -206,3 +206,21 @@ The deprecated hostname v1 feature was removed. This feature was deprecated in {
= Proxy option removed
The deprecated `proxy` option was removed. This option was deprecated in {project_name} 24 and replaced by the `proxy-headers` option in combination with hostname options as needed. For more details, see https://www.keycloak.org/server/reverseproxy[using a reverse proxy] and https://www.keycloak.org/docs/latest/upgrading/index.html#deprecated-proxy-option[the initial upgrading guide].
= All user sessions are persisted by default
Since the database is now the source of truth for user sessions, it is possible to restrict the size of the session caches to reduce memory usage.
If you use the default `conf/cache-ispn.xml` file the caches for storing user and client sessions are by default configured to store only 10000 sessions and one owner for each entry.
Update your custom embedded Infinispan cache configuration file with configuration similar to one shown below for caches `sessions`, `clientSessions`, `offlineSessions`, and `offlineClientSessions`:
[,xml]
----
<distributed-cache name="sessions" owners="1">
<!-- other configuration -->
<memory max-count="10000"/>
</distributed-cache>
----
For more details proceed to the https://www.keycloak.org/server/caching[Configuring distributed caches] guide.

View file

@ -13,17 +13,15 @@ Perform the following steps before you upgrade the server.
+
The database will no longer be compatible with the old server after you upgrade the server. If you need to revert the upgrade, first restore the old installation, and then restore the database from the backup copy.
[NOTE]
====
In case the feature `persistent-user-sessions` is disabled in your current setup and the server is upgraded, all user sessions will be lost except for offline user sessions.
Users owning these sessions will have to log in again.
Note the feature `persistent-user-sessions` is disabled by default in the {project_name} server releases prior to 26.0.0.
====
[WARNING]
====
ifeval::[{project_product}==true]
After the upgrade of {project_name}, except for offline user sessions, user sessions are lost. Users will have to log in again.
endif::[]
ifeval::[{project_community}==true]
After the upgrade of {project_name}, only if the feature `persistent-user-sessions` is enabled, users will still be logged in with their online sessions.
If it is not enabled, users will have to log in again, except where offline user sessions are used.
endif::[]
Information about failed logins for the brute force detection and currently ongoing authentication flows is only stored in the internal caches that are cleared when {project_name} is shut down.
Users currently authenticating, changing their passwords or resetting their password will need to restart the authentication flow once {project_name} is up and running again.
====

View file

@ -33,7 +33,7 @@ Some platforms, such as Kubernetes, provide mechanisms to vertically autoscale.
== Horizontal Scaling
A single {project_name} instance is susceptible to availability issues. If the instance goes down, you experience a full outage until another instance comes up. Also, unless the '`persistent-user-sessions`' feature is enabled, all ongoing sessions are lost. By running two or more cluster members on different machines, you greatly increase the availability of {project_name}.
A single {project_name} instance is susceptible to availability issues. If the instance goes down, you experience a full outage until another instance comes up. By running two or more cluster members on different machines, you greatly increase the availability of {project_name}.
A single JVM has a limit on how many concurrent requests it can handle. Additional server instances can provide roughly linear scaling of throughput until associated resources, such as the database or distributed caching, limit that scaling.
@ -43,7 +43,7 @@ If you are not using the Operator, please review the following:
* Higher availability is possible of your instances are on separate machines. On Kubernetes, use Pod anti-affinitity to enforce this.
* Use distributed caching; for multi-site clusters, use external caching for cluster members to share the same session state. For details on the relevant configuration, see <@links.server id="caching" />. The embedded Infinispan cache has horizontal scaling considerations including:
* Use distributed caching; for multi-site clusters, use external caching for cluster members to share the same state. For details on the relevant configuration, see <@links.server id="caching" />. The embedded Infinispan cache has horizontal scaling considerations including:
- Your instances need a way to discover each other. For more information, see discovery in <@links.server id="caching" />.
- This cache is not optimal for clusters that span multiple availability zones, which are also called stretch clusters. For embedded Infinispan cache, work to have all instances in one availability zone. The goal is to avoid unnecessary round-trips in the communication that would amplify in the response times. On Kubernetes, use Pod affinity to enforce this grouping of Pods.
@ -55,7 +55,8 @@ To avoid losing service availability when a whole site is unavailable, see the h
Horizontal autoscaling allows for adding or removing {project_name} instances on demand. Keep in mind that startup times will not be instantaneous and that optimized images should be used to minimize the start time.
When using the embedded Infinispan cache cluster, dynamically adding or removing cluster members requires Infinispan to perform a rebalancing of the session caches,m which can get expensive if many entries exist in those caches.
When using the embedded Infinispan cache cluster, dynamically adding or removing cluster members requires Infinispan to perform a rebalancing of the Infinispan caches, which can get expensive if many entries exist in those caches.
To minimize this time we limit number of entries in session related caches to 10000 by default. Note, this optimization is possible only if `persistent-user-sessions` feature is not explicitly disabled in your configuration.
On Kubernetes, the Keycloak custom resource is scalable meaning that it can be targeted by the https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/[built-in autoscaler].

View file

@ -41,10 +41,10 @@ You configure these caches in `conf/cache-ispn.xml`:
|keys|Local|Cache external public keys
|work|Replicated|Propagate invalidation messages across nodes
|authenticationSessions|Distributed|Caches authentication sessions, created/destroyed/expired during the authentication process
|sessions|Distributed|Caches user sessions, created upon successful authentication and destroyed during logout, token revocation, or due to expiration
|clientSessions|Distributed|Caches client sessions, created upon successful authentication to a specific client and destroyed during logout, token revocation, or due to expiration
|offlineSessions|Distributed|Caches offline user sessions, created upon successful authentication and destroyed during logout, token revocation, or due to expiration
|offlineClientSessions|Distributed|Caches client sessions, created upon successful authentication to a specific client and destroyed during logout, token revocation, or due to expiration
|sessions|Distributed|Cache persisted user session data
|clientSessions|Distributed|Cache persisted client session data
|offlineSessions|Distributed|Cache persisted offline user session data
|offlineClientSessions|Distributed|Cache persisted offline client session data
|loginFailures|Distributed|keep track of failed logins, fraud detection
|actionTokens|Distributed|Caches action Tokens
|===
@ -91,66 +91,72 @@ CPU, memory, and network utilization.
.User sessions
Once the user is authenticated, a user session is created. The user session tracks your active users and their state so that they can seamlessly
authenticate to any application without being asked for their credentials again. For each application, the user authenticates with a client session
is created too, so that the server can track the applications the user is authenticated with and their state on a per-application basis.
authenticate to any application without being asked for their credentials again. For each application, the user authenticates with a client session, so that the server can track the applications the user is authenticated with and their state on a per-application basis.
User and client sessions are automatically destroyed whenever the user performs a logout, the client performs a token revocation, or due to reaching their expiration time.
The following caches are used to store both user and client sessions:
The session data are stored in the database by default and loaded on-demand to the following caches:
* sessions
* clientSessions
By relying on a distributable cache, user and client sessions are available to any node in the cluster so that users can be redirected
to any node without losing their state. However, production-ready deployments should always consider session affinity and favor redirecting users
By relying on a distributable cache, cached user and client sessions are available to any node in the cluster so that users can be redirected
to any node without the need to load session data from the database. However, production-ready deployments should always consider session affinity and favor redirecting users
to the node where their sessions were initially created. By doing that, you are going to avoid unnecessary state transfer between nodes and improve
CPU, memory, and network utilization.
ifeval::[{project_community}==true]
.Persistent user sessions
The feature `persistent-user-sessions` stores online user and client sessions also in the database.
This will allow a user to stay logged in even if all instances of {project_name} are restarted or upgraded.
The feature is disabled by default. To use it, enable the feature:
----
bin/kc.sh start --features=persistent-user-sessions ...
----
With this feature enabled, the in-memory caches for online user sessions and online client sessions are limited to, by default, 10000 entries per node which will reduce the overall memory usage of {project_name} for larger installations.
These in-memory caches for user sessions and client sessions are limited to, by default, 10000 entries per node which reduces the overall memory usage of {project_name} for larger installations.
The internal caches will run with only a single owner for each cache entry.
Items which are evicted from memory will be loaded on-demand from the database when needed.
To set different sizes for the caches, edit {project_name}'s cache config file to set a `+<memory max-count="..."/>+` for those caches.
Consider trade-off between memory consumption and the database utilization and set different sizes for the caches, edit {project_name}'s cache config file (`conf/cache-ispn.xml`) to set a `+<memory max-count="..."/>+` for those caches.
[WARNING]
====
Enabling this feature via a rolling configuration upgrade can result in an undefined behavior of {project_name} related to sessions if both persisted and non-persisted sessions co-exist.
To prevent that, remove all online user and client sessions before the first node is started with this feature enabled.
This means all {project_name} nodes need to be stopped and, if used, {jdgserver_name} remote cache store and embedded Infinispan JDBC persistence need to be cleared.
====
.Volatile user sessions
endif::[]
By default, user sessions are stored in the database and loaded on-demand to the cache.
It is possible to configure {project_name} to store user sessions in the cache only and minimize the database utilization.
Since all the sessions in this setup are stored in-memory, there are two side effects related to this:
* Losing sessions on all Keycloak nodes restart
* Increased memory consumption
Follow these steps to enable this setup:
1. Since the cache is the only source of truth for user and client sessions, configure caches to not limit the number of entries and to replicate each entry to at least two nodes. To do so, edit {project_name}'s cache config file (`conf/cache-ispn.xml`) for caches `sessions` and `clientSessions` with the following update:
+
--
* Remove the `+<memory max-count="..."/>+`
* Change `owners` attribute of the `distributed-cache` tag to 2 or more
--
+
An example of the resulting configuration for the `sessions` cache would look as follows.
+
[source,xml]
----
<distributed-cache name="sessions" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
----
2. Disable `persistent-user-sessions` feature using the following command:
+
----
bin/kc.sh start --features-disabled=persistent-user-sessions ...
----
[NOTE]
====
Disabling `persistent-user-sessions` is not possible when `multi-site` feature is enabled.
====
.Offline user sessions
As an OpenID Connect Provider, the server is also capable of authenticating users and issuing offline tokens. Similarly to regular user and client sessions,
when an offline token is issued by the server upon successful authentication, the server also creates an offline user session and an offline client session. However, due to the nature
of offline tokens, offline sessions are handled differently as they are long-lived and should survive a complete cluster shutdown. Because of that, they are also persisted to the database.
when an offline token is issued by the server upon successful authentication, the server also creates an offline user session and an offline client session.
The following caches are used to store offline sessions:
* offlineSessions
* offlineClientSessions
Upon a cluster restart, offline sessions are lazily loaded from the database and kept in a shared cache using the two caches above.
ifeval::[{project_community}==true]
With feature `persistent-user-sessions` enabled, the in-memory caches for offline user sessions and offline client sessions are limited to 10000 entries which will reduce the overall memory usage of Keycloak for larger installations.
Items which are evicted from memory will be loaded on-demand from the database when needed.
To set different sizes for the caches, edit {project_name}'s cache config file to set a `+<memory max-count="..."/>+` for those caches.
endif::[]
Similarly to regular user and client sessions caches, also the offline user and client session caches are limited to 10000 entries per node by default. Items which are evicted from the memory will be loaded on-demand from the database when needed.
Consider trade-off between memory consumption and the database utilization and set different sizes for the caches, edit {project_name}'s cache config file (`conf/cache-ispn.xml`) to set a `+<memory max-count="..."/>+` for those caches.
.Password brute force detection
The `loginFailures` distributed cache is used to track data about failed login attempts.
@ -164,10 +170,9 @@ The `actionTokens` distributed cache is used to track metadata about action toke
Distributed caches replicate cache entries on a subset of nodes in a cluster and assigns entries to fixed owner nodes.
Each distributed cache has two owners per default, which means that two nodes have a copy of the specific cache entries.
Each distributed cache, that is a primary source of truth of the data (`authenticationSessions`, `loginFailures` and `actionTokens`) has two owners per default, which means that two nodes have a copy of the specific cache entries.
Non-owner nodes query the owners of a specific cache to obtain data.
When both owner nodes are offline, all data is lost.
This situation usually leads to users being logged out at the next request and having to log in again.
The default number of owners is enough to survive 1 node (owner) failure in a cluster setup with at least three nodes. You are free
to change the number of owners accordingly to better fit into your availability requirements. To change the number of owners, open `conf/cache-ispn.xml` and change the value for `owners=<value>` for the distributed caches to your desired value.
@ -190,11 +195,11 @@ Once any of declared CLI parameters are present, it is expected there is no conf
WARNING: Disabling security is not recommended in production!
In a development or test environment, it is easier to start an unsecured Infinispan server.
For these use case, the CLI options `cache-remote-tls-enabled` disables the encryption (TLS) between {project_name} and Infinispan.
{project_name} will fail to start if the Infinispan server is configured to accept only encrypted connections.
For these use case, the CLI options `cache-remote-tls-enabled` disables the encryption (TLS) between {project_name} and {jdgserver_name}.
{project_name} will fail to start if the {jdgserver_name} server is configured to accept only encrypted connections.
The CLI options `cache-remote-username` and `cache-remote-password` are optional and, if not set, {project_name} will connect to the Infinispan server without presenting any credentials.
If the Infinispan server has authentication enabled, {project_name} will fail to start.
The CLI options `cache-remote-username` and `cache-remote-password` are optional and, if not set, {project_name} will connect to the {jdgserver_name} server without presenting any credentials.
If the {jdgserver_name} server has authentication enabled, {project_name} will fail to start.
== Transport stacks
Transport stacks ensure that distributed cache nodes in a cluster communicate in a reliable fashion.

View file

@ -46,7 +46,7 @@ Typical cluster deployment consists of the load balancer (reverse proxy) and 2 o
For performance purposes, it may be useful if load balancer forwards all requests related to particular browser session to the same {project_name} backend node.
The reason is, that {project_name} is using Infinispan distributed cache under the covers for save data related to current authentication session and user session.
The Infinispan distributed caches are configured with two owners by default. That means that particular session is primarily stored on two cluster nodes and the other nodes need to lookup the session remotely if they want to access it.
The Infinispan distributed caches are configured with limited number of owners. That means that session related data are stored only in some cluster nodes and the other nodes need to lookup the data remotely if they want to access it.
For example if authentication session with ID 123 is saved in the Infinispan cache on node1, and then node2 needs to lookup this session, it needs to send the request to node1 over the network to return the particular session entity.

View file

@ -54,7 +54,7 @@ When using transient users, you should be aware of the following:
needed since persistent users can manage offline tokens more easily
by the Account Console. Also, the transient users feature contributes
the purpose of not storing any personally identifiable information into the database.
Since offline sessions are persisted in database, the transient user data would be stored
Since sessions are persisted in database, the transient user data would be stored
there as well. It is up to the administrator to determine whether this is acceptable or not.
- Technically, transient user data is stored as part

View file

@ -458,7 +458,11 @@ public class CacheManagerFactory {
configurationBuilder.clustering().hash().numOwners(1);
} else {
if (configurationBuilder.memory().maxCount() != -1) {
logger.warnf("Persistent user sessions NOT enabled and memory limit found in configuration for cache %s. This might be a misconfiguration!", cacheName);
logger.warnf("Persistent user sessions disabled and memory limit found in configuration for cache %s. This might be a misconfiguration! Update your Infinispan configuration to remove this message.", cacheName);
}
if (configurationBuilder.memory().maxCount() == 10000 && (cacheName.equals(USER_SESSION_CACHE_NAME) || cacheName.equals(CLIENT_SESSION_CACHE_NAME))) {
logger.warnf("Persistent user sessions disabled and memory limit is set to default value 10000. Ignoring cache limits to avoid losing sessions for cache %s.", cacheName);
configurationBuilder.memory().maxCount(-1);
}
if (configurationBuilder.clustering().hash().attributes().attribute(HashConfiguration.NUM_OWNERS).get() == 1
&& configurationBuilder.persistence().stores().isEmpty()) {

View file

@ -37,20 +37,24 @@
</encoding>
<memory max-count="10000"/>
</local-cache>
<distributed-cache name="sessions" owners="2">
<distributed-cache name="sessions" owners="1">
<expiration lifespan="-1"/>
<memory max-count="10000"/>
</distributed-cache>
<distributed-cache name="authenticationSessions" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
<distributed-cache name="offlineSessions" owners="2">
<distributed-cache name="offlineSessions" owners="1">
<expiration lifespan="-1"/>
<memory max-count="10000"/>
</distributed-cache>
<distributed-cache name="clientSessions" owners="2">
<distributed-cache name="clientSessions" owners="1">
<expiration lifespan="-1"/>
<memory max-count="10000"/>
</distributed-cache>
<distributed-cache name="offlineClientSessions" owners="2">
<distributed-cache name="offlineClientSessions" owners="1">
<expiration lifespan="-1"/>
<memory max-count="10000"/>
</distributed-cache>
<distributed-cache name="loginFailures" owners="2">
<expiration lifespan="-1"/>