mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-08-30 15:28:12 +02:00
Added parameter to skipp dependency loading to speed up debugging
This commit is contained in:
4
roles/web-app-keycloak/tasks/01_cleanup.yml
Normal file
4
roles/web-app-keycloak/tasks/01_cleanup.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
- name: "remove directory {{ KEYCLOAK_REALM_IMPORT_DIR_HOST }}"
|
||||
ansible.builtin.file:
|
||||
path: "{{ KEYCLOAK_REALM_IMPORT_DIR_HOST }}"
|
||||
state: absent
|
@@ -1,15 +0,0 @@
|
||||
- name: "load variables from {{ DOCKER_VARS_FILE }}"
|
||||
include_vars: "{{ DOCKER_VARS_FILE }}"
|
||||
|
||||
- name: "create directory {{ KEYCLOAK_HOST_IMPORT_DIR }}"
|
||||
file:
|
||||
path: "{{ KEYCLOAK_HOST_IMPORT_DIR }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: "Copy import files to {{ KEYCLOAK_HOST_IMPORT_DIR }}"
|
||||
template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ KEYCLOAK_HOST_IMPORT_DIR }}/{{ item | basename | regex_replace('\\.j2$', '') }}"
|
||||
mode: "0770"
|
||||
loop: "{{ lookup('fileglob', role_path ~ '/templates/import/*.j2', wantlist=True) }}"
|
15
roles/web-app-keycloak/tasks/02_initialize.yml
Normal file
15
roles/web-app-keycloak/tasks/02_initialize.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
- name: "load variables from {{ DOCKER_VARS_FILE }}"
|
||||
include_vars: "{{ DOCKER_VARS_FILE }}"
|
||||
|
||||
- name: "create directory {{ KEYCLOAK_REALM_IMPORT_DIR_HOST }}"
|
||||
file:
|
||||
path: "{{ KEYCLOAK_REALM_IMPORT_DIR_HOST }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: "Copy REALM import file '{{ KEYCLOAK_REALM_IMPORT_FILE_SRC }}' to '{{ KEYCLOAK_REALM_IMPORT_FILE_DST }}'"
|
||||
template:
|
||||
src: "{{ KEYCLOAK_REALM_IMPORT_FILE_SRC }}"
|
||||
dest: "{{ KEYCLOAK_REALM_IMPORT_FILE_DST }}"
|
||||
mode: "0770"
|
||||
when: KEYCLOAK_REALM_IMPORT_ENABLED | bool
|
@@ -14,58 +14,100 @@
|
||||
- name: Assert required vars
|
||||
assert:
|
||||
that:
|
||||
- kc_object_kind in ['client','component']
|
||||
- kc_object_kind in ['client','component','client-scope']
|
||||
- kc_lookup_value is defined
|
||||
- kc_desired is defined
|
||||
fail_msg: "kc_object_kind, kc_lookup_value, kc_desired are required."
|
||||
|
||||
- name: Derive API endpoint and lookup field
|
||||
set_fact:
|
||||
kc_api: "{{ 'clients' if kc_object_kind == 'client' else 'components' }}"
|
||||
kc_lookup_field_eff: "{{ 'clientId' if kc_object_kind == 'client' else (kc_lookup_field | default('name')) }}"
|
||||
kc_api: >-
|
||||
{{ 'clients' if kc_object_kind == 'client'
|
||||
else 'components' if kc_object_kind == 'component'
|
||||
else 'client-scopes' if kc_object_kind == 'client-scope'
|
||||
else '' }}
|
||||
kc_lookup_field_eff: >-
|
||||
{{ 'clientId' if kc_object_kind == 'client'
|
||||
else (kc_lookup_field | default('name')) if kc_object_kind == 'component'
|
||||
else 'name' if kc_object_kind == 'client-scope'
|
||||
else '' }}
|
||||
|
||||
- name: Resolve object id
|
||||
- name: Resolve object id (direct when lookup_field is id)
|
||||
when: kc_lookup_field_eff == 'id'
|
||||
set_fact:
|
||||
kc_obj_id: "{{ kc_lookup_value | string }}"
|
||||
|
||||
- name: Resolve object id via query
|
||||
when: kc_lookup_field_eff != 'id'
|
||||
shell: >
|
||||
{% if kc_object_kind == 'client-scope' -%}
|
||||
{{ KEYCLOAK_EXEC_KCADM }} get client-scopes -r {{ KEYCLOAK_REALM }} --format json
|
||||
| jq -r '.[] | select(.{{ kc_lookup_field_eff }}=="{{ kc_lookup_value }}") | .id' | head -n1
|
||||
{%- else -%}
|
||||
{{ KEYCLOAK_EXEC_KCADM }} get {{ kc_api }}
|
||||
-r {{ KEYCLOAK_REALM }}
|
||||
--query '{{ kc_lookup_field_eff }}={{ kc_lookup_value }}'
|
||||
--fields id --format json | jq -r '.[0].id'
|
||||
register: kc_obj_id
|
||||
{%- endif %}
|
||||
register: kc_obj_id_cmd
|
||||
changed_when: false
|
||||
|
||||
- name: Normalize resolved id to a plain string
|
||||
set_fact:
|
||||
kc_obj_id: >-
|
||||
{{
|
||||
kc_obj_id
|
||||
if kc_lookup_field_eff == 'id'
|
||||
else (kc_obj_id_cmd.stdout | default('') | trim)
|
||||
}}
|
||||
|
||||
- name: Fail if object not found
|
||||
assert:
|
||||
that:
|
||||
- (kc_obj_id.stdout | trim) != ''
|
||||
- (kc_obj_id.stdout | trim) != 'null'
|
||||
- (kc_obj_id | trim) != ''
|
||||
- (kc_obj_id | trim) != 'null'
|
||||
fail_msg: "{{ kc_object_kind | capitalize }} '{{ kc_lookup_value }}' not found."
|
||||
|
||||
- name: Read current object
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} get {{ kc_api }}/{{ kc_obj_id.stdout }}
|
||||
{{ KEYCLOAK_EXEC_KCADM }} get {{ kc_api }}/{{ kc_obj_id }}
|
||||
-r {{ KEYCLOAK_REALM }} --format json
|
||||
register: kc_cur
|
||||
changed_when: false
|
||||
|
||||
# ── Build merge payload safely (avoid evaluating kc_desired[kc_merge_path] when undefined) ─────────
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: Parse current object
|
||||
set_fact:
|
||||
cur_obj: "{{ kc_cur.stdout | from_json }}"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: "Safety check: providerId must match when updating a component"
|
||||
when:
|
||||
- kc_object_kind == 'component'
|
||||
- (kc_desired.providerId is defined)
|
||||
assert:
|
||||
that:
|
||||
- cur_obj.providerId == kc_desired.providerId
|
||||
fail_msg: >
|
||||
Refusing to update component '{{ cur_obj.name }}' (providerId={{ cur_obj.providerId }})
|
||||
because desired providerId={{ kc_desired.providerId }}. Check your lookup/ID.
|
||||
|
||||
- name: Prepare merge payload (subpath)
|
||||
when: kc_merge_path is defined and (kc_merge_path | length) > 0
|
||||
set_fact:
|
||||
merge_payload: "{{ { (kc_merge_path): (kc_desired[kc_merge_path] | default({}, true)) } }}"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: Prepare merge payload (full object)
|
||||
when: kc_merge_path is not defined or (kc_merge_path | length) == 0
|
||||
set_fact:
|
||||
merge_payload: "{{ kc_desired }}"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: Build desired object (base merge)
|
||||
set_fact:
|
||||
desired_obj: "{{ cur_obj | combine(merge_payload, recursive=True) }}"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
# Preserve immutable fields
|
||||
- name: Preserve immutable fields for client
|
||||
@@ -79,6 +121,7 @@
|
||||
'clientId': cur_obj.clientId
|
||||
}, recursive=True)
|
||||
}}
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: Preserve immutable fields for component
|
||||
when: kc_object_kind == 'component'
|
||||
@@ -93,6 +136,14 @@
|
||||
'parentId': cur_obj.parentId
|
||||
}, recursive=True)
|
||||
}}
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
# Preserve immutables for client-scope
|
||||
- name: Preserve immutable fields for client-scope
|
||||
when: kc_object_kind == 'client-scope'
|
||||
set_fact:
|
||||
desired_obj: "{{ desired_obj | combine({'id': cur_obj.id, 'name': cur_obj.name}, recursive=True) }}"
|
||||
|
||||
|
||||
# Optional forced attributes (e.g., frontchannelLogout)
|
||||
- name: Apply forced attributes (optional)
|
||||
@@ -102,6 +153,8 @@
|
||||
|
||||
- name: Update object via stdin
|
||||
shell: |
|
||||
cat <<'JSON' | {{ KEYCLOAK_EXEC_KCADM }} update {{ kc_api }}/{{ kc_obj_id.stdout }} -r {{ KEYCLOAK_REALM }} -f -
|
||||
cat <<'JSON' | {{ KEYCLOAK_EXEC_KCADM }} update {{ kc_api }}/{{ kc_obj_id }} -r {{ KEYCLOAK_REALM }} -f -
|
||||
{{ desired_obj | to_json }}
|
||||
JSON
|
||||
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
|
||||
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
|
72
roles/web-app-keycloak/tasks/04_rbac_client_scope.yml
Normal file
72
roles/web-app-keycloak/tasks/04_rbac_client_scope.yml
Normal file
@@ -0,0 +1,72 @@
|
||||
# --- Ensure RBAC client scope exists (idempotent) ---
|
||||
- name: Ensure RBAC client scope exists
|
||||
shell: |
|
||||
cat <<'JSON' | {{ KEYCLOAK_EXEC_KCADM }} create client-scopes -r {{ KEYCLOAK_REALM }} -f -
|
||||
{{
|
||||
(
|
||||
KEYCLOAK_DICTIONARY_REALM.clientScopes
|
||||
| selectattr('name','equalto', KEYCLOAK_OIDC_RBAC_SCOPE_NAME)
|
||||
| list | first
|
||||
) | to_json
|
||||
}}
|
||||
JSON
|
||||
register: create_rbac_scope
|
||||
changed_when: create_rbac_scope.rc == 0
|
||||
failed_when: create_rbac_scope.rc != 0 and
|
||||
('already exists' not in (create_rbac_scope.stderr | lower))
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
# --- Get the scope id we will attach to the client ---
|
||||
- name: Get all client scopes
|
||||
shell: "{{ KEYCLOAK_EXEC_KCADM }} get client-scopes -r {{ KEYCLOAK_REALM }} --format json"
|
||||
register: all_scopes
|
||||
changed_when: false
|
||||
|
||||
- name: Extract RBAC scope id
|
||||
set_fact:
|
||||
scope_id_rbac: >-
|
||||
{{ (
|
||||
all_scopes.stdout | from_json
|
||||
| selectattr('name','equalto', KEYCLOAK_OIDC_RBAC_SCOPE_NAME)
|
||||
| list | first | default({})
|
||||
).id | default('') }}
|
||||
|
||||
- name: Resolve application client id
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} get clients
|
||||
-r {{ KEYCLOAK_REALM }}
|
||||
--query 'clientId={{ KEYCLOAK_CLIENT_ID }}'
|
||||
--fields id --format json | jq -r '.[0].id'
|
||||
register: app_client_id_cmd
|
||||
changed_when: false
|
||||
|
||||
- name: Sanity check IDs
|
||||
assert:
|
||||
that:
|
||||
- scope_id_rbac | length > 0
|
||||
- (app_client_id_cmd.stdout | trim) is match('^[0-9a-f-]+$')
|
||||
fail_msg: "Could not determine client or scope ID."
|
||||
|
||||
- name: Get current optional client scopes
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} get
|
||||
clients/{{ app_client_id_cmd.stdout | trim }}/optional-client-scopes
|
||||
-r {{ KEYCLOAK_REALM }} --format json
|
||||
register: opt_scopes
|
||||
changed_when: false
|
||||
|
||||
- name: Decide if RBAC scope already assigned
|
||||
set_fact:
|
||||
has_rbac_optional: >-
|
||||
{{ (opt_scopes.stdout | from_json
|
||||
| selectattr('id','equalto', scope_id_rbac) | list | length) > 0 }}
|
||||
|
||||
- name: Ensure RBAC scope assigned as optional (only if missing)
|
||||
when: not has_rbac_optional
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} update
|
||||
clients/{{ app_client_id_cmd.stdout | trim }}/optional-client-scopes/{{ scope_id_rbac }}
|
||||
-r {{ KEYCLOAK_REALM }}
|
||||
register: add_opt
|
||||
changed_when: true
|
||||
failed_when: add_opt.rc != 0
|
134
roles/web-app-keycloak/tasks/05_ldap.yml
Normal file
134
roles/web-app-keycloak/tasks/05_ldap.yml
Normal file
@@ -0,0 +1,134 @@
|
||||
# roles/web-app-keycloak/tasks/05_ldap.yml
|
||||
---
|
||||
- name: "Update REALM settings (merge LDAP component .config)"
|
||||
include_tasks: 03_update.yml
|
||||
vars:
|
||||
kc_object_kind: "component"
|
||||
kc_lookup_value: "{{ KEYCLOAK_LDAP_CMP_NAME }}"
|
||||
kc_desired: >-
|
||||
{{
|
||||
KEYCLOAK_DICTIONARY_REALM.components['org.keycloak.storage.UserStorageProvider']
|
||||
| selectattr('providerId','equalto','ldap')
|
||||
| list | first
|
||||
}}
|
||||
kc_merge_path: "config"
|
||||
|
||||
# --- Read desired mapper definition from KEYCLOAK_DICTIONARY_REALM ---
|
||||
|
||||
- name: Get LDAP component (from KEYCLOAK_DICTIONARY_REALM)
|
||||
set_fact:
|
||||
ldap_component: >-
|
||||
{{
|
||||
KEYCLOAK_DICTIONARY_REALM.components['org.keycloak.storage.UserStorageProvider']
|
||||
| selectattr('providerId','equalto','ldap')
|
||||
| list | first | default({})
|
||||
}}
|
||||
|
||||
- name: Sanity check LDAP component
|
||||
assert:
|
||||
that:
|
||||
- ldap_component | length > 0
|
||||
- (ldap_component.subComponents | default({})) | length > 0
|
||||
fail_msg: "LDAP component not found in KEYCLOAK_DICTIONARY_REALM."
|
||||
|
||||
- name: Extract desired group-ldap-mapper definition (raw)
|
||||
set_fact:
|
||||
desired_group_mapper_raw: >-
|
||||
{{
|
||||
(
|
||||
ldap_component.subComponents['org.keycloak.storage.ldap.mappers.LDAPStorageMapper']
|
||||
| default([])
|
||||
)
|
||||
| selectattr('providerId','equalto','group-ldap-mapper')
|
||||
| list | first | default({})
|
||||
}}
|
||||
|
||||
- name: Ensure we found the mapper in the dictionary
|
||||
assert:
|
||||
that:
|
||||
- desired_group_mapper_raw | length > 0
|
||||
fail_msg: "group-ldap-mapper not found below LDAP component in KEYCLOAK_DICTIONARY_REALM."
|
||||
|
||||
- name: Compute desired mapper name
|
||||
set_fact:
|
||||
desired_group_mapper_name: "{{ desired_group_mapper_raw.name | default('ldap-roles') }}"
|
||||
|
||||
- name: Build clean mapper payload (strip unsupported keys)
|
||||
set_fact:
|
||||
desired_group_mapper: >-
|
||||
{{
|
||||
desired_group_mapper_raw
|
||||
| dict2items
|
||||
| rejectattr('key','equalto','subComponents')
|
||||
| rejectattr('key','equalto','id')
|
||||
| list | items2dict
|
||||
}}
|
||||
|
||||
# --- Work against Keycloak ---
|
||||
|
||||
- name: Resolve LDAP component id
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} get components
|
||||
-r {{ KEYCLOAK_REALM }}
|
||||
--query 'name={{ KEYCLOAK_LDAP_CMP_NAME }}'
|
||||
--fields id --format json | jq -r '.[0].id'
|
||||
register: ldap_cmp_id
|
||||
changed_when: false
|
||||
|
||||
- name: Assert LDAP component id resolved
|
||||
assert:
|
||||
that:
|
||||
- (ldap_cmp_id.stdout | trim) not in ["", "null"]
|
||||
fail_msg: "LDAP component '{{ KEYCLOAK_LDAP_CMP_NAME }}' not found in Keycloak."
|
||||
|
||||
- name: Check for group-ldap-mapper existence (by name under LDAP component)
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} get components
|
||||
-r {{ KEYCLOAK_REALM }}
|
||||
--query "parent={{ ldap_cmp_id.stdout | trim }}&type=org.keycloak.storage.ldap.mappers.LDAPStorageMapper&name={{ desired_group_mapper_name }}"
|
||||
--format json
|
||||
| jq -r '.[] | select(.parentId=="{{ ldap_cmp_id.stdout | trim }}"
|
||||
and .providerType=="org.keycloak.storage.ldap.mappers.LDAPStorageMapper"
|
||||
and .providerId=="group-ldap-mapper"
|
||||
and .name=="{{ desired_group_mapper_name }}") | .id' | head -n1
|
||||
register: grp_mapper_id
|
||||
changed_when: false
|
||||
|
||||
- name: Ensure group-ldap-mapper exists (create if missing)
|
||||
when: (grp_mapper_id.stdout | trim) in ["", "null"]
|
||||
shell: |
|
||||
cat <<'JSON' | {{ KEYCLOAK_EXEC_KCADM }} create components -r {{ KEYCLOAK_REALM }} -f -
|
||||
{{
|
||||
desired_group_mapper
|
||||
| combine({
|
||||
'name': desired_group_mapper_name,
|
||||
'parentId': ldap_cmp_id.stdout | trim,
|
||||
'providerType':'org.keycloak.storage.ldap.mappers.LDAPStorageMapper',
|
||||
'providerId': 'group-ldap-mapper'
|
||||
}, recursive=True)
|
||||
| to_json
|
||||
}}
|
||||
JSON
|
||||
register: create_mapper
|
||||
changed_when: create_mapper.rc == 0
|
||||
failed_when: create_mapper.rc != 0 and ('already exists' not in (create_mapper.stderr | lower))
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: Update existing group-ldap-mapper config (merge only .config)
|
||||
when: (grp_mapper_id.stdout | trim) not in ["", "null"]
|
||||
vars:
|
||||
kc_object_kind: "component"
|
||||
kc_lookup_field: "id"
|
||||
kc_lookup_value: "{{ grp_mapper_id.stdout | trim }}"
|
||||
kc_desired: >-
|
||||
{{
|
||||
desired_group_mapper
|
||||
| combine({
|
||||
'name': desired_group_mapper_name,
|
||||
'parentId': ldap_cmp_id.stdout | trim,
|
||||
'providerType': 'org.keycloak.storage.ldap.mappers.LDAPStorageMapper',
|
||||
'providerId': 'group-ldap-mapper'
|
||||
}, recursive=True)
|
||||
}}
|
||||
kc_merge_path: "config"
|
||||
include_tasks: 03_update.yml
|
@@ -1,31 +1,28 @@
|
||||
---
|
||||
- name: "create import files for {{ application_id }}"
|
||||
include_tasks: 01_initialize.yml
|
||||
- name: "Load cleanup routine for '{{ application_id }}'"
|
||||
include_tasks: 01_cleanup.yml
|
||||
|
||||
- name: "load required 'web-svc-logout' for {{ application_id }}"
|
||||
include_role:
|
||||
name: web-svc-logout
|
||||
when: run_once_web_svc_logout is not defined
|
||||
- name: "Load init routine for '{{ application_id }}'"
|
||||
include_tasks: 02_initialize.yml
|
||||
|
||||
- name: "load docker, db and proxy for {{ application_id }}"
|
||||
include_role:
|
||||
name: cmp-db-docker-proxy
|
||||
vars:
|
||||
docker_compose_flush_handlers: true
|
||||
- name: "Load the depdendencies required by '{{ application_id }}'"
|
||||
include_tasks: 03_load_dependencies.yml
|
||||
|
||||
- name: "Wait until Keycloak is reachable at {{ KEYCLOAK_SERVER_HOST_URL }}"
|
||||
uri:
|
||||
url: "{{ KEYCLOAK_MASTER_REALM_URL }}"
|
||||
method: GET
|
||||
status_code: 200
|
||||
validate_certs: false
|
||||
register: kc_up
|
||||
retries: 30
|
||||
- name: "Wait until '{{ KEYCLOAK_CONTAINER }}' container is healthy"
|
||||
community.docker.docker_container_info:
|
||||
name: "{{ KEYCLOAK_CONTAINER }}"
|
||||
register: kc_info
|
||||
retries: 60
|
||||
delay: 5
|
||||
until: kc_up.status == 200
|
||||
until: >
|
||||
kc_info is succeeded and
|
||||
(kc_info.container | default({})) != {} and
|
||||
(kc_info.container.State | default({})) != {} and
|
||||
(kc_info.container.State.Health | default({})) != {} and
|
||||
(kc_info.container.State.Health.Status | default('')) == 'healthy'
|
||||
|
||||
- name: kcadm login (master)
|
||||
no_log: true
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
shell: >
|
||||
{{ KEYCLOAK_EXEC_KCADM }} config credentials
|
||||
--server {{ KEYCLOAK_SERVER_INTERNAL_URL }}
|
||||
@@ -34,19 +31,6 @@
|
||||
--password {{ KEYCLOAK_MASTER_API_USER_PASSWORD }}
|
||||
changed_when: false
|
||||
|
||||
- name: "Update REALM settings"
|
||||
include_tasks: 02_update.yml
|
||||
vars:
|
||||
kc_object_kind: "component"
|
||||
kc_lookup_value: "{{ KEYCLOAK_LDAP_CMP_NAME }}"
|
||||
kc_desired: >-
|
||||
{{
|
||||
KEYCLOAK_DICTIONARY_REALM.components['org.keycloak.storage.UserStorageProvider']
|
||||
| selectattr('providerId','equalto','ldap')
|
||||
| list | first }}
|
||||
kc_merge_path: "config"
|
||||
when: KEYCLOAK_LDAP_ENABLED | bool
|
||||
|
||||
- name: "Update Client settings"
|
||||
vars:
|
||||
kc_object_kind: "client"
|
||||
@@ -59,6 +43,16 @@
|
||||
}}
|
||||
kc_force_attrs:
|
||||
frontchannelLogout: true
|
||||
attributes: "{{ (KEYCLOAK_DICTIONARY_CLIENT.attributes | default({}))
|
||||
| combine({'frontchannel.logout.url': KEYCLOAK_FRONTCHANNEL_LOGOUT_URL}, recursive=True) }}"
|
||||
include_tasks: 02_update.yml
|
||||
attributes: >-
|
||||
{{
|
||||
( (KEYCLOAK_DICTIONARY_REALM.clients
|
||||
| selectattr('clientId','equalto', KEYCLOAK_CLIENT_ID)
|
||||
| list | first | default({}) ).attributes | default({}) )
|
||||
| combine({'frontchannel.logout.url': KEYCLOAK_FRONTCHANNEL_LOGOUT_URL}, recursive=True)
|
||||
}}
|
||||
include_tasks: 03_update.yml
|
||||
|
||||
- include_tasks: 04_rbac_client_scope.yml
|
||||
|
||||
- include_tasks: 05_ldap.yml
|
||||
when: KEYCLOAK_LDAP_ENABLED | bool
|
||||
|
Reference in New Issue
Block a user