Problem: Nubus - UMS Keycloak Bootstrap Fails During Upgrade

UMS Keycloak Bootstrap Fails During Upgrade to openDesk 1.5.0

Problem:

When upgrading openDesk from version 1.4.x to 1.5.0 (Nubus 1.9.x), the UMS Keycloak bootstrap process fails unexpectedly. While the issue does not appear in pre-production environments, it has been observed in multiple production instances. Specifically, the failure affects the Two-Factor Authentication (2FA) configuration, rendering the setup incomplete and requiring manual recovery steps.


Affected:

  • Product/Module: openDesk / UMS Keycloak Bootstrap
  • Version Affected: openDesk 1.5.0 (Nubus 1.9.x)
  • Applies To: Upgrades from openDesk 1.4.x

Symptoms:

During the execution of the bootstrap process, the enabling for 2FA halts with a fatal error. A 409 Conflict response is returned by Keycloak, stating:

Authentication execution configuration 2fa-role-mapping already exists

As a result, the bootstrap job does not complete successfully, preventing full Keycloak configuration and requiring manual intervention to proceed.

Logs:

TASK [Enable Two-Factor-Authentication] ****************************************
fatal: [localhost]: FAILED! => {“changed”: false, “cmd”: “univention-keycloak --keycloak-url http://ums-keycloak:8080 --realm opendesk --binduser kcadmin --bindpwdfile /credentials/keycloak.secret 2fa enable --group-2fa="2fa-users" --ldap-base="dc=swp-ldap,dc=internal"\n”, “delta”: “0:00:02.067930”, “end”: “2025-07-08 05:05:24.087799”, “msg”: “non-zero return code”, “rc”: 1, “start”: “2025-07-08 05:05:22.019869”, “stderr”: “Traceback (most recent call last):\n File "/usr/sbin/univention-keycloak", line 3436, in \n sys.exit(main())\n ^^^^^^\n File "/usr/sbin/univention-keycloak", line 3432, in main\n return opt.func(opt) or 0\n ^^^^^^^^^^^^^\n File "/usr/sbin/univention-keycloak", line 2715, in enable_2fa\n create_conditional_2fa_flow(kc_admin, opt.realm, realm_2fa_role, flow_name)\n File "/usr/sbin/univention-keycloak", line 2979, in create_conditional_2fa_flow\n create_config_for_execution(kc_admin, config, condition_user_role_id)\n File "/usr/sbin/univention-keycloak", line 3009, in create_config_for_execution\n return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204, 201])\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File "/usr/lib/python3/dist-packages/keycloak/exceptions.py", line 192, in raise_error_from_response\n raise error(\nkeycloak.exceptions.KeycloakGetError: 409: b’{"errorMessage":"Authentication execution configuration 2fa-role-mapping already exists"}'”, “stderr_lines”: [“Traceback (most recent call last):”, " File "/usr/sbin/univention-keycloak", line 3436, in “, " sys.exit(main())”, " ^^^^^^“, " File "/usr/sbin/univention-keycloak", line 3432, in main”, " return opt.func(opt) or 0", " ^^^^^^^^^^^^^“, " File "/usr/sbin/univention-keycloak", line 2715, in enable_2fa”, " create_conditional_2fa_flow(kc_admin, opt.realm, realm_2fa_role, flow_name)“, " File "/usr/sbin/univention-keycloak", line 2979, in create_conditional_2fa_flow”, " create_config_for_execution(kc_admin, config, condition_user_role_id)“, " File "/usr/sbin/univention-keycloak", line 3009, in create_config_for_execution”, " return raise_error_from_response(data_raw, KeycloakGetError, expected_codes=[204, 201])“, " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^”, " File "/usr/lib/python3/dist-packages/keycloak/exceptions.py", line 192, in raise_error_from_response", " raise error(", “keycloak.exceptions.KeycloakGetError: 409: b’{"errorMessage":"Authentication execution configuration 2fa-role-mapping already exists"}'”], “stdout”: “Enabling 2FA …\nUsing KC_URL: http://ums-keycloak:8080\nGroup already exists\nGroup already exists”, “stdout_lines”: [“Enabling 2FA …”, “Using KC_URL: http://ums-keycloak:8080”, “Group already exists”, “Group already exists”]}


Root Cause:

This issue is caused by the non-idempotent behavior of the univention-keycloak CLI tool, which attempts to recreate an authentication execution configuration that already exists.

Bug 58462

Technical Insight:

  • Keycloak requires each authentication execution configuration alias (such as 2fa-role-mapping) to be unique.
  • Upon re-running the bootstrap, the job tries to create an execution configuration that already exists from a prior run or incomplete cleanup.
  • The duplicate entries in the Keycloak database cause a 409 Conflict, breaking the bootstrap process.

Workaround:

To recover from this issue and allow the bootstrap job to succeed:

Manual Cleanup in Keycloak UI:

  1. Log into the Keycloak Admin Console for the affected realm (typically opendesk).

  2. Navigate to Authentication → Flows.

  3. Delete the conditional flow associated with 2fa-role-mapping.

  4. Go to Authentication → Executions and remove any remaining 2FA-related executions.

  5. Re-run the bootstrap job:

    helm upgrade --install ... --set keycloak-bootstrap.enabled=true

Alternative Cleanup via Database (Advanced):

Caution: Direct database modifications should only be performed by experienced administrators and with appropriate backups.

  1. Connect to the PostgreSQL database used by Keycloak.

  2. Inspect the authenticator_config table:

    SELECT * FROM authenticator_config WHERE alias = '2fa-role-mapping';

  3. Identify all redundant entries:

    SELECT * FROM authenticator_config_entry WHERE authenticator_id IN (...);

  4. Delete all stale entries:

    DELETE FROM authenticator_config_entry WHERE authenticator_id IN (...);

    DELETE FROM authenticator_config WHERE alias = '2fa-role-mapping';

  5. Rerun the bootstrap process.
    helm upgrade --install ... --set keycloak-bootstrap.enabled=true


Database Investigation

To identify which entries are also available and outdated and which are in use:

  • Cross-reference the id from authenticator_config with foreign key relationships in other tables such as:

    • authentication_execution
    • authenticator_config_entry
keycloak=# select * from authenticator_config;
                  id                  |           alias           |               realm_id               
--------------------------------------+---------------------------+--------------------------------------
 d0e23b44-9ea4-4af6-b175-912fe7eb4ecf | review profile config     | 4dc5b609-b312-4c45-97f6-c6d5ad1db
 802ea9c7-7e9e-4270-9d33-b146990ad  | create unique user config | 4dc5b609-b312-4c45-97f6-c6d5ad1db1
 d55cd22e-1dd3-4e7a-90f6-18c7409cdf | review profile config     | opendesk
 e9616ba9-3873-46ea-835f-29f1f3286a | create unique user config | opendesk
 0f978e63-154a-42ba-89e5-11e851b4f  | 2fa-role-mapping          | opendesk
 f1e0d786-9d97-477e-b4e3-2816bff790 | 2fa-role-mapping          | opendesk
 aab1534e-9167-4451-9061-c22d1295b | 2fa-role-mapping          | opendesk
 77092ec7-bc98-4a66-a4bc-8d694d87d | 2fa-role-mapping          | opendesk
 13cea73e-65f4-406c-b28f-a3cb9844d | 2fa-role-mapping          | opendesk
 34fa8cef-46e1-4b41-8653-ae1263981 | 2fa-role-mapping          | opendesk
(10 rows)

keycloak=# select * from authenticator_config_entry ;
           authenticator_id           |  value   |                    name                    
--------------------------------------+----------+--------------------------------------------
 802ea9c7-7e9e-4270-9d33-b146990adc | false    | require.password.update.after.registration
 d0e23b44-9ea4-4af6-b175-912fe7eb4e | missing  | update.profile.on.first.login
 d55cd22e-1dd3-4e7a-90f6-18c7409cdf | missing  | update.profile.on.first.login
 e9616ba9-3873-46ea-835f-29f1f3286a | false    | require.password.update.after.registration
 0f978e63-154a-42ba-89e5-11e851b4f9 | 2FA role | condUserRole
 f1e0d786-9d97-477e-b4e3-2816bff790 | 2FA role | condUserRole
 aab1534e-9167-4451-9061-c22d1295 | 2FA role | condUserRole
 77092ec7-bc98-4a66-a4bc-8d694d87 | 2FA role | condUserRole
 13cea73e-65f4-406c-b28f-a3cb9844d | 2FA role | condUserRole
 34fa8cef-46e1-4b41-8653-ae1263981 | 2FA role | condUserRole
(10 rows)

Our recommendation to resolve this issue is as follows:

  • Remove all entries from both authenticator_config and authenticator_config_entry tables.
  • Rerun the keycloak-bootstrap job. This process should recreate the necessary and correct entries.