From ecf949b57766704083bee6ee3ce228739e03228c Mon Sep 17 00:00:00 2001 From: Evan Shortiss Date: Fri, 19 Jun 2026 17:42:45 +0900 Subject: [PATCH] feat(keycloak): support service account client role mappings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keycloak automatically creates a service account user when a client has serviceAccountsEnabled=true, but the realm import doesn't assign client roles to it. Add optional serviceAccountRoles dict to keycloak_clients entries — when defined, the realm import includes the service account user with the specified clientRoles mappings. Use case: the RHDH keycloakOrg plugin requires the backstage-plugin service account to have query-users, view-users, and query-groups roles on the realm-management client. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../defaults/main.yml | 17 +++++++++++++++++ .../templates/keycloak/realm_import.yml.j2 | 17 ++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/roles/ocp4_workload_authentication/defaults/main.yml b/roles/ocp4_workload_authentication/defaults/main.yml index af863a69..809005e1 100644 --- a/roles/ocp4_workload_authentication/defaults/main.yml +++ b/roles/ocp4_workload_authentication/defaults/main.yml @@ -135,6 +135,9 @@ ocp4_workload_authentication_keycloak_openshift_client_id: idp-4-ocp # - standardFlowEnabled: true/false (optional, defaults to true) # - directAccessGrantsEnabled: true/false (optional, defaults to true) # - serviceAccountsEnabled: true/false (optional, defaults to true) +# - serviceAccountRoles: dict of client-name → role list (optional) +# Assigns client roles to the service account user created by Keycloak. +# Only used when serviceAccountsEnabled is true. ocp4_workload_authentication_keycloak_clients: [] @@ -159,4 +162,18 @@ ocp4_workload_authentication_keycloak_clients: [] # - "https://grafana.{{ openshift_cluster_ingress_domain }}/login/generic_oauth" # description: "Grafana OAuth Client" +# Example: RHDH Keycloak Plugin with service account roles +# The keycloakOrg catalog provider requires realm-management roles +# to sync users and groups into the Developer Hub catalog. +# ocp4_workload_authentication_keycloak_clients: +# - clientId: backstage-plugin +# secret: "{{ lookup('password', '/dev/null chars=ascii_letters,digits length=32') }}" +# standardFlowEnabled: false +# serviceAccountsEnabled: true +# serviceAccountRoles: +# realm-management: +# - query-users +# - view-users +# - query-groups + ocp4_workload_authentication_keycloak_enable_user_info_messages: true diff --git a/roles/ocp4_workload_authentication/templates/keycloak/realm_import.yml.j2 b/roles/ocp4_workload_authentication/templates/keycloak/realm_import.yml.j2 index 990242d2..bc16500b 100644 --- a/roles/ocp4_workload_authentication/templates/keycloak/realm_import.yml.j2 +++ b/roles/ocp4_workload_authentication/templates/keycloak/realm_import.yml.j2 @@ -59,8 +59,23 @@ spec: description: "Default user role" - name: admin description: "Administrator role" -{% if ocp4_workload_authentication_num_users | int > 0 or _ocp4_workload_authentication_cluster_accounts | length > 0 %} +{% set _has_service_account_roles = ocp4_workload_authentication_keycloak_clients | selectattr('serviceAccountRoles', 'defined') | list | length > 0 %} +{% if ocp4_workload_authentication_num_users | int > 0 or _ocp4_workload_authentication_cluster_accounts | length > 0 or _has_service_account_roles %} users: +{% for client in ocp4_workload_authentication_keycloak_clients %} +{% if client.serviceAccountRoles is defined %} + - username: service-account-{{ client.clientId }} + enabled: true + serviceAccountClientId: {{ client.clientId }} + clientRoles: +{% for client_name, roles in client.serviceAccountRoles.items() %} + {{ client_name }}: +{% for role in roles %} + - {{ role }} +{% endfor %} +{% endfor %} +{% endif %} +{% endfor %} {% for _account in _ocp4_workload_authentication_cluster_accounts %} - username: {{ _account.name }} enabled: true