Skip to content

Update Keycloak to version 26.5.7 and dependencies#4096

Draft
tobybellwood wants to merge 1 commit into
mainfrom
keycloak-26-5
Draft

Update Keycloak to version 26.5.7 and dependencies#4096
tobybellwood wants to merge 1 commit into
mainfrom
keycloak-26-5

Conversation

@tobybellwood

@tobybellwood tobybellwood commented May 28, 2026

Copy link
Copy Markdown
Contributor

This pull request updates the Keycloak service and its custom protocol mapper to use newer versions of Keycloak, dependencies, and build tools. The changes improve compatibility, security, and maintainability by keeping the stack up to date.

Keycloak and Custom Mapper Version Upgrades:

  • Upgraded the Keycloak base image in services/keycloak/Dockerfile from 26.4.7 to 26.5.7, and updated the keycloak.version property in custom-mapper/pom.xml accordingly. [1] [2]
  • Updated the custom protocol mapper version from 1.1.1 to 1.1.2 in both the Dockerfile and pom.xml. [1] [2]

Dependency and Plugin Updates:

  • Upgraded the mariadb-java-client dependency from 3.4.0 to 3.5.8 in custom-mapper/pom.xml.
  • Updated Maven plugin versions in custom-mapper/pom.xml:
    • maven-compiler-plugin from 3.13.0 to 3.14.1
    • jandex-maven-plugin from 3.2.2 to 3.5.3
    • maven-shade-plugin from 3.6.0 to 3.6.2
  • Updated Maven build image in Dockerfile from 3.9.14-eclipse-temurin-21-alpine to 3.9.16-eclipse-temurin-21-alpine.

Provider and Extension Updates:

  • Updated the keycloak-home-idp-discovery provider JAR from version v26.1.1 to v26.2.0 in the Keycloak Dockerfile.

@tobybellwood

Copy link
Copy Markdown
Contributor Author

Keycloak 26.5.7 Migration Impact Report for Lagoon - Preliminary Unreviewed

Baseline version: 26.4.7
Target version: 26.5.7
Date assessed: 28 May 2026


Summary

Of the changes introduced between Keycloak 26.5.0 and 26.5.7, one is critical and requires a migration plan before upgrading. Several others require code-level fixes or are operational concerns for large deployments. The remainder do not impact Lagoon's setup.


Impacted Items

1. Fine-Grained Admin Permissions (FGAP) v1 Deprecated

Severity: Critical — Requires Migration Plan
Introduced: 26.5.0

Lagoon's startup explicitly enables FGAP v1:

# services/keycloak/entrypoints/kc-startup.sh
/opt/keycloak/bin/kc.sh "$@" --features="scripts,token-exchange:v1,admin-fine-grained-authz:v1,quick-theme"

The admin-fine-grained-authz:v1 feature is now deprecated and will be removed in a future release. FGAP v1 is the authorization backbone of the entire Lagoon api Keycloak client — the authorizationSettings block in the realm import contains:

  • 20+ named resources (project, environment, task, group, user, etc.)
  • 20+ JavaScript-backed authorization policies (e.g. [Lagoon] Users role for project is Maintainer)
  • 100+ scope-based permission entries
  • Policy enforcement mode: ENFORCING

All of Lagoon's access control for the API layer flows through this FGAP v1 configuration. If the feature is removed in a future Keycloak version, Lagoon's authorization will be completely non-functional.

Action required:

  • FGAP v1 continues to work in 26.5.x but this is the last series where it is fully supported.
  • Begin planning a migration from FGAP v1 (admin-fine-grained-authz:v1) to FGAP v2.
  • Review the Keycloak FGAP v2 migration documentation to understand the scope of changes needed to the realm import and JavaScript policies.
  • This is a significant piece of work that warrants its own development track.

2. Deprecated Bootstrap Admin Environment Variables

Severity: Medium — Requires Code Fix
Introduced: 26.5.0 (deprecation warning now active in 26.5.7)

Keycloak 26.5.x deprecated the KEYCLOAK_ADMIN and KEYCLOAK_ADMIN_PASSWORD environment variables in favour of KC_BOOTSTRAP_ADMIN_USERNAME and KC_BOOTSTRAP_ADMIN_PASSWORD. This deprecation is actively triggered in Lagoon's current setup and is visible in every container startup log:

KC-SERVICES0110: Environment variable 'KEYCLOAK_ADMIN' is deprecated, use 'KC_BOOTSTRAP_ADMIN_USERNAME' instead
KC-SERVICES0110: Environment variable 'KEYCLOAK_ADMIN_PASSWORD' is deprecated, use 'KC_BOOTSTRAP_ADMIN_PASSWORD' instead

The root cause is in services/keycloak/entrypoints/default-keycloak-entrypoint.sh, which explicitly passes the deprecated variable name:

# current — uses deprecated KEYCLOAK_ADMIN
KEYCLOAK_USER=$KEYCLOAK_ADMIN_USER KEYCLOAK_PASSWORD=$KEYCLOAK_ADMIN_PASSWORD KEYCLOAK_ADMIN=$KEYCLOAK_ADMIN_USER /lagoon/kc-startup.sh "$@"

The default values are set in the Dockerfile:

KEYCLOAK_ADMIN_USER=admin
KEYCLOAK_ADMIN_PASSWORD=admin

Action required: Update default-keycloak-entrypoint.sh to export KC_BOOTSTRAP_ADMIN_USERNAME and KC_BOOTSTRAP_ADMIN_PASSWORD instead of KEYCLOAK_ADMIN and KEYCLOAK_PASSWORD. The existing KEYCLOAK_ADMIN_USER / KEYCLOAK_ADMIN_PASSWORD Lagoon env vars can be retained as the source values — only the mapping to Keycloak's own variable names needs to change:

# updated
KC_BOOTSTRAP_ADMIN_USERNAME=$KEYCLOAK_ADMIN_USER KC_BOOTSTRAP_ADMIN_PASSWORD=$KEYCLOAK_ADMIN_PASSWORD /lagoon/kc-startup.sh "$@"

This must be done before Keycloak removes the deprecated variables in a future release.


3. HTTP Paths with Semicolons Rejected

Severity: Medium — Integration Risk
Introduced: 26.5.2

Keycloak now rejects HTTP requests containing a semicolon (;) in the path, returning HTTP 400, treating it as a matrix parameter separator. This is the same class of change as the double-slash rejection introduced in 26.4.3.

Lagoon constructs Keycloak URLs from environment variables in:

Semicolons in URLs are uncommon but could theoretically appear in environment variable values or in request parameters passed through to Keycloak.

Action required: Low-risk but worth noting. Add KEYCLOAK_URL sanitization to guard against semicolons alongside the trailing-slash guard recommended in the 26.4.3 assessment. To debug rejected requests, enable:

org.keycloak.quarkus.runtime.services.RejectNonNormalizedPathFilter

4. BROKER_LINK Table Database Index Migration

Severity: Medium — Operational Risk
Introduced: 26.5.1

Two new indexes (IDX_BROKER_LINK_USER_ID and IDX_BROKER_LINK_IDENTITY_PROVIDER) are added to the BROKER_LINK table. As with the OFFLINE_CLIENT_SESSION change in 26.4.3, if the table has more than 300,000 rows, automatic index creation is skipped and the SQL is logged to the console instead.

Action required: For large production Lagoon deployments, check startup logs after upgrading for skipped index SQL and apply manually. This is particularly relevant for long-running Lagoon instances with many users who have linked social or SSO identity providers.


5. OFFLINE_USER_SESSION Table Changes and Indexes

Severity: Medium — Operational Risk
Introduced: 26.5.0

A new column REMEMBER_ME is added to the OFFLINE_USER_SESSION table, and new indexes are added to improve session expiration performance. The same 300,000-row threshold applies for automatic index creation.

Additionally, the session expiration model has changed — sessions are now deleted more proactively based on realm settings, with a ~3-minute delay after expiry. A new USER_SESSION_DELETED user event is fired for each deleted session.

Observed in 26.5.7 startup logs: Even on a fresh database (during initial Liquibase schema creation), two non-fatal column warnings appear at startup:

WARN Error: 1054-42S22: Unknown column 't.DETAILS_JSON' in 'field list'
WARN Error: 1054-42S22: Unknown column 't.REMEMBER_ME' in 'field list'

These are emitted because Keycloak queries these columns before the Liquibase migration has fully committed the schema changes. Both warnings are non-fatal — Keycloak proceeds to start and complete configuration successfully. On existing deployments upgrading from 26.4.x, these warnings are expected during the schema migration window.

Action required:

  • For large production deployments, check startup logs for skipped SQL after upgrading.
  • Treat DETAILS_JSON and REMEMBER_ME column warnings at startup as expected and non-fatal.
  • Be aware that users may see more frequent session expiry compared to prior versions.
  • If you have monitoring on user events, expect new USER_SESSION_DELETED events.

6. Default Authorization Resources and Policies No Longer Auto-Created

Severity: Low — New Deployment Concern
Introduced: 26.5.0

When enabling authorization (authorizationServicesEnabled: true) on a new client, Keycloak no longer automatically creates a "Default Resource", "Default Policy", and "Default Permission".

Lagoon explicitly defines all resources and policies in the realm import, including the Default Resource and Default Policy. Existing deployments are not affected. However, the lagoon-realm-base-import.json already contains these explicitly, so fresh installs are also unaffected.

Action required: None for existing deployments or fresh installs from the realm import. If any startup scripts dynamically create new authorization-enabled clients outside the realm import, they will need to explicitly configure their default resources and policies.


7. Stricter Access Control for Listing Realm and Client Roles

Severity: Low — Verify Service Accounts
Introduced: 26.5.6

Having only a query-* role is no longer sufficient to list realm or client roles. To list roles, an admin service account now needs:

  • view-realm or manage-realm for realm roles
  • view-clients or manage-clients for client roles

Lagoon's service accounts with limited realm-management roles:

Service Account Roles Granted
service-account-lagoon-opensearch-sync query-groups, view-users
service-account-service-api query-groups, view-users

Neither account uses query-* as their only role, and neither is known to call role listing APIs — they primarily read users and groups. The full realm-admin role (assigned to the api service account via uma_protection) is unaffected.

Action required: Verify that no Lagoon service or custom extension calls role listing endpoints using credentials from lagoon-opensearch-sync or service-api. If they do, add view-realm or view-clients to those service accounts as appropriate.


8. Stricter Access Control for Managing Permission Tickets

Severity: Low
Introduced: 26.5.6

Only users or service accounts with the uma-protection role can manage permission tickets for a resource server. The resource server itself is exempt.

The Lagoon api client is the resource server and already has uma_protection configured correctly on service-account-api. The api client itself is the resource server and is explicitly exempt from this restriction.

Action required: None. Lagoon's configuration already meets the new requirements.


9. Outgoing HTTP Client Connection Timeout Default Changed

Severity: Low — Monitor
Introduced: 26.5.0

Keycloak's outgoing HTTP client now has a default connection-request-timeout-millis of 5,000ms (previously unlimited). This affects any outgoing HTTP calls Keycloak makes (e.g., to external identity providers, JWKS endpoints, or email servers).

For Lagoon's standard setup with no external OIDC providers configured by default, this is unlikely to cause issues. However, for Lagoon instances configured with external SMTP servers or federated identity providers that may be slow to respond, timeouts could occur where they previously did not.

Action required: Monitor Keycloak logs after upgrading for timeout errors on outgoing connections. If needed, configure:

--spi-connections-http-client-default-connection-request-timeout-millis=<ms>

10. session_state and sid Format Change

Severity: Low — Verify Token Consumers
Introduced: 26.5.0

session_state and sid in OpenID Connect tokens are no longer UUIDs. They are now 24-character random base64-encoded strings. The specs define these as opaque strings, so well-behaved consumers are not affected.

Lagoon's token validation in keycloakClient.ts does not inspect session_state or sid. However, any UI, CLI, or downstream integrations that store or validate these values as UUIDs could break.

Action required: Audit any Lagoon components or integrations that store or compare session_state / sid values against a UUID format pattern.


Not Impacted

Change Reason
SAML SubjectConfirmationData validation (26.5.4) Lagoon does not use SAML
SAML redirect binding inflating size limit (26.5.4) Lagoon does not use SAML
Loopback hostname verification on Windows (26.5.0) Lagoon runs on Linux containers
PostgreSQL 13 end-of-life (26.5.0) Lagoon uses MariaDB
PostgreSQL pg_class/pg_namespace permissions (26.5.0) Lagoon uses MariaDB
MS SQL Server READ_COMMITTED_SNAPSHOT (26.5.0) Not applicable
HTML in login theme message keys (26.5.0) Lagoon's login theme has no messages_en.properties; only email theme messages exist
Client session timeout validation (26.5.0) All clientSessionIdleTimeout / clientSessionMaxLifespan values are 0 (use realm defaults)
Organization custom id attribute (26.5.0) Lagoon does not use Keycloak Organizations
SPIFFE Identity Provider (26.5.0) Not configured
Virtual threads CPU threshold change (26.5.2) Operational change; no configuration needed
HTTP access log sensitive data omission (26.5.5) Security improvement; no action needed
UserProfile#toRepresentation(boolean) API change (26.5.0) Lagoon does not implement UserProfile
AuthenticationManager.AuthResult is now a record (26.5.0) Lagoon does not extend Keycloak's services module
token-exchange:v1 feature Still in use and not deprecated in 26.5.x

Priority Summary

Priority Item
Critical Plan FGAP v1 → v2 migration
Medium Update deprecated KEYCLOAK_ADMIN/KEYCLOAK_ADMIN_PASSWORD env vars in default-keycloak-entrypoint.sh
Medium Check BROKER_LINK and OFFLINE_USER_SESSION index migration for large deployments
Low Add semicolon guard to KEYCLOAK_URL parsing
Low Audit service accounts for role listing API usage (26.5.6)
Low Monitor outgoing HTTP timeout behaviour
Low Audit session_state/sid consumers for UUID format assumptions

Files Referenced


References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants