mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-08-18 17:55:09 +02:00
- Replace KEYCLOAK_KCADM_PATH with KEYCLOAK_EXEC_KCADM consistently - Externalize client.json to separate Jinja2 template and include it in realm.json - Simplify LDAP bind update to use explicit KEYCLOAK_LDAP_* vars - Add async/poll support for long-running kcadm updates - Restructure vars/main.yml: clearer grouping (General, Docker, Server, Update, LDAP, API) - Compute redirectUris/webOrigins centrally in vars - Align post.logout.redirect.uris handling with playbook Conversation: https://chatgpt.com/share/68a1a11f-f8ac-800f-bada-cdc99a4fa1bf
106 lines
4.0 KiB
YAML
106 lines
4.0 KiB
YAML
---
|
|
# Idempotent update of Keycloak LDAP provider:
|
|
# - bindDn
|
|
# - bindCredential
|
|
# - connectionUrl
|
|
#
|
|
# STRICT: Uses ONLY values from ldap.* (no computed defaults)
|
|
# - ldap.dn.administrator.data
|
|
# - ldap.bind_credential
|
|
# - ldap.server.uri
|
|
|
|
- name: "Assert required vars exist (strict: use ldap.* only, no defaults)"
|
|
assert:
|
|
that:
|
|
- KEYCLOAK_REALM is defined
|
|
- KEYCLOAK_CONTAINER is defined
|
|
- KEYCLOAK_SERVER_INTERNAL_URL is defined
|
|
- KEYCLOAK_MASTER_API_USER_NAME is defined
|
|
- KEYCLOAK_MASTER_API_USER_PASSWORD is defined
|
|
- KEYCLOAK_LDAP_CMP_NAME is defined
|
|
- ldap is defined
|
|
- ldap.dn.administrator is defined
|
|
- ldap.dn.administrator.data is defined
|
|
- ldap.bind_credential is defined
|
|
- ldap.server is defined
|
|
- ldap.server.uri is defined
|
|
fail_msg: >-
|
|
Missing required Keycloak/LDAP variables. Ensure ldap.dn.administrator.data,
|
|
ldap.bind_credential, and ldap.server.uri are defined.
|
|
|
|
# Build a base argv for kcadm to avoid fragile shell quoting
|
|
- name: "Build kcadm argv base"
|
|
set_fact:
|
|
kcadm_argv_base:
|
|
- docker
|
|
- exec
|
|
- -i
|
|
- "{{ KEYCLOAK_CONTAINER }}"
|
|
- /opt/keycloak/bin/kcadm.sh
|
|
|
|
- name: "kcadm login (master)"
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
command:
|
|
argv: "{{ kcadm_argv_base
|
|
+ ['config', 'credentials',
|
|
'--server', KEYCLOAK_SERVER_INTERNAL_URL,
|
|
'--realm', 'master',
|
|
'--user', KEYCLOAK_MASTER_API_USER_NAME,
|
|
'--password', KEYCLOAK_MASTER_API_USER_PASSWORD] }}"
|
|
changed_when: false
|
|
|
|
# Resolve the LDAP component *by name* to avoid picking the wrong one.
|
|
- name: "Resolve LDAP component id by name '{{ KEYCLOAK_LDAP_CMP_NAME }}'"
|
|
command:
|
|
argv: "{{ kcadm_argv_base
|
|
+ ['get', 'components',
|
|
'-r', KEYCLOAK_REALM,
|
|
'--query', 'name=' ~ KEYCLOAK_LDAP_CMP_NAME,
|
|
'--fields', 'id,name,providerId,config',
|
|
'--format', 'json'] }}"
|
|
register: kc_ldap_list
|
|
changed_when: false
|
|
|
|
- name: "Validate that exactly one LDAP component matched"
|
|
vars:
|
|
parsed: "{{ kc_ldap_list.stdout | from_json }}"
|
|
assert:
|
|
that:
|
|
- (parsed | length) == 1
|
|
fail_msg: >-
|
|
Expected exactly one LDAP component named '{{ KEYCLOAK_LDAP_CMP_NAME }}',
|
|
found {{ (kc_ldap_list.stdout | from_json) | length }}.
|
|
|
|
- name: "Extract current LDAP component values"
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
set_fact:
|
|
kc_ldap_component_id: "{{ (kc_ldap_list.stdout | from_json)[0].id }}"
|
|
kc_ldap_current_bind_dn: "{{ ((kc_ldap_list.stdout | from_json)[0].config['bindDn'] | default(['']))[0] }}"
|
|
kc_ldap_current_bind_pw: "{{ ((kc_ldap_list.stdout | from_json)[0].config['bindCredential'] | default(['']))[0] }}"
|
|
kc_ldap_current_connection_url: "{{ ((kc_ldap_list.stdout | from_json)[0].config['connectionUrl'] | default(['']))[0] }}"
|
|
|
|
- name: "Determine if update is required"
|
|
set_fact:
|
|
kc_needs_update: >-
|
|
{{
|
|
(kc_ldap_current_bind_dn != KEYCLOAK_LDAP_BIND_DN)
|
|
or (kc_ldap_current_bind_pw != KEYCLOAK_LDAP_BIND_PW)
|
|
or (kc_ldap_current_connection_url != KEYCLOAK_LDAP_URL)
|
|
}}
|
|
|
|
# Pass each -s as a single argv token with valid JSON (arrays), zero shell quoting issues.
|
|
- name: "Update LDAP bindDn / bindCredential / connectionUrl (strict, argv)"
|
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
command:
|
|
argv: "{{ kcadm_argv_base
|
|
+ ['update', 'components/' ~ kc_ldap_component_id,
|
|
'-r', KEYCLOAK_REALM,
|
|
'-s', 'config.bindDn=' ~ ([KEYCLOAK_LDAP_BIND_DN] | to_json),
|
|
'-s', 'config.bindCredential=' ~ ([KEYCLOAK_LDAP_BIND_PW] | to_json),
|
|
'-s', 'config.connectionUrl=' ~ ([KEYCLOAK_LDAP_URL] | to_json)
|
|
] }}"
|
|
when: kc_needs_update | bool
|
|
register: kc_bind_update
|
|
async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}"
|
|
poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}"
|