mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-08-15 08:30:46 +02:00
keycloak: robust LDAP bind and connectionUrl update via kcadm (argv + JSON); strict ldap.*; idempotent
Switch to command:argv to avoid shell quoting and argument splitting issues. Pass -s config values as JSON arrays via to_json, fixing previous errors: Cannot parse the JSON / failed at splitting arguments. Also reconcile config.connectionUrl from ldap.server.uri. Source desired values strictly from ldap.* (no computed defaults) and assert their presence. Keep operation idempotent by reading current values and updating only on change. Minor refactor: build reusable kcadm_argv_base and expand client state extraction. Touch: roles/web-app-keycloak/tasks/03_update-ldap-bind.yml https://chatgpt.com/share/689bea84-7188-800f-ba51-830a0735f24c
This commit is contained in:
parent
4fa1c6cfbd
commit
e497c001d6
@ -1,41 +1,63 @@
|
|||||||
---
|
---
|
||||||
# Updates the LDAP provider's bind DN / password using kcadm.sh, idempotently.
|
# Idempotent update of Keycloak LDAP provider:
|
||||||
# Sources DN/password from group_vars/all/13_ldap.yml:
|
# - bindDn
|
||||||
# - DN: ldap.dn.administrator.data
|
# - bindCredential
|
||||||
# - Password: ldap.bind_credential
|
# - 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"
|
- name: "Assert required vars exist (strict: use ldap.* only, no defaults)"
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- keycloak_realm is defined
|
- keycloak_realm is defined
|
||||||
- keycloak_server_host_url is defined
|
- keycloak_container is defined
|
||||||
- keycloak_server_internal_url is defined
|
- keycloak_server_internal_url is defined
|
||||||
- keycloak_kcadm_path is defined
|
|
||||||
- keycloak_master_api_user_name is defined
|
- keycloak_master_api_user_name is defined
|
||||||
- keycloak_master_api_user_password is defined
|
- keycloak_master_api_user_password is defined
|
||||||
- keycloak_ldap_component_name is defined
|
- keycloak_ldap_component_name is defined
|
||||||
- ldap is defined
|
- ldap is defined
|
||||||
|
- ldap.dn.administrator is defined
|
||||||
- ldap.dn.administrator.data is defined
|
- ldap.dn.administrator.data is defined
|
||||||
- ldap.bind_credential is defined
|
- ldap.bind_credential is defined
|
||||||
fail_msg: "Missing Keycloak/LDAP vars. Ensure 13_ldap.yml is loaded and credentials are set."
|
- 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)"
|
- name: "kcadm login (master)"
|
||||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||||
shell: >
|
command:
|
||||||
{{ keycloak_kcadm_path }} config credentials
|
argv: "{{ kcadm_argv_base
|
||||||
--server {{ keycloak_server_internal_url }}
|
+ ['config', 'credentials',
|
||||||
--realm master
|
'--server', keycloak_server_internal_url,
|
||||||
--user {{ keycloak_master_api_user_name }}
|
'--realm', 'master',
|
||||||
--password {{ keycloak_master_api_user_password }}
|
'--user', keycloak_master_api_user_name,
|
||||||
|
'--password', keycloak_master_api_user_password] }}"
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
# Resolve the LDAP component *by name* to avoid picking the wrong one.
|
# Resolve the LDAP component *by name* to avoid picking the wrong one.
|
||||||
- name: "Resolve LDAP component id by name '{{ keycloak_ldap_component_name }}'"
|
- name: "Resolve LDAP component id by name '{{ keycloak_ldap_component_name }}'"
|
||||||
shell: >
|
command:
|
||||||
{{ keycloak_kcadm_path }} get components
|
argv: "{{ kcadm_argv_base
|
||||||
-r {{ keycloak_realm }}
|
+ ['get', 'components',
|
||||||
--query 'name={{ keycloak_ldap_component_name }}'
|
'-r', keycloak_realm,
|
||||||
--fields id,name,providerId,config --format json
|
'--query', 'name=' ~ keycloak_ldap_component_name,
|
||||||
|
'--fields', 'id,name,providerId,config',
|
||||||
|
'--format', 'json'] }}"
|
||||||
register: kc_ldap_list
|
register: kc_ldap_list
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
@ -49,32 +71,48 @@
|
|||||||
Expected exactly one LDAP component named '{{ keycloak_ldap_component_name }}',
|
Expected exactly one LDAP component named '{{ keycloak_ldap_component_name }}',
|
||||||
found {{ (kc_ldap_list.stdout | from_json) | length }}.
|
found {{ (kc_ldap_list.stdout | from_json) | length }}.
|
||||||
|
|
||||||
- name: "Extract LDAP component facts"
|
- name: "Extract current LDAP component values"
|
||||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||||
set_fact:
|
set_fact:
|
||||||
kc_ldap_component_id: "{{ (kc_ldap_list.stdout | from_json)[0].id }}"
|
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_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_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] }}"
|
||||||
|
|
||||||
|
# Desired values come STRICTLY from ldap.*
|
||||||
|
- name: "Set desired LDAP values (strict from ldap.*)"
|
||||||
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||||
|
set_fact:
|
||||||
|
kc_desired_bind_dn: "{{ ldap.dn.administrator.data }}"
|
||||||
|
kc_desired_bind_pw: "{{ ldap.bind_credential }}"
|
||||||
|
kc_desired_connection_url: "{{ ldap.server.uri }}"
|
||||||
|
|
||||||
- name: "Determine if update is required"
|
- name: "Determine if update is required"
|
||||||
set_fact:
|
set_fact:
|
||||||
kc_needs_update: >-
|
kc_needs_update: >-
|
||||||
{{ (kc_ldap_current_bind_dn != ldap.dn.administrator.data)
|
{{
|
||||||
or (kc_ldap_current_bind_pw != ldap.bind_credential) }}
|
(kc_ldap_current_bind_dn != kc_desired_bind_dn)
|
||||||
|
or (kc_ldap_current_bind_pw != kc_desired_bind_pw)
|
||||||
|
or (kc_ldap_current_connection_url != kc_desired_connection_url)
|
||||||
|
}}
|
||||||
|
|
||||||
- name: "Update LDAP bind DN / bind password"
|
# 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 }}"
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||||
shell: >
|
command:
|
||||||
{{ keycloak_kcadm_path }} update components/{{ kc_ldap_component_id }}
|
argv: "{{ kcadm_argv_base
|
||||||
-r {{ keycloak_realm }}
|
+ ['update', 'components/' ~ kc_ldap_component_id,
|
||||||
-s 'config.bindDn=["{{ ldap.dn.administrator.data | replace("'", "\\'") }}"]'
|
'-r', keycloak_realm,
|
||||||
-s 'config.bindCredential=["{{ ldap.bind_credential | replace("'", "\\'") }}"]'
|
'-s', 'config.bindDn=' ~ ([kc_desired_bind_dn] | to_json),
|
||||||
|
'-s', 'config.bindCredential=' ~ ([kc_desired_bind_pw] | to_json),
|
||||||
|
'-s', 'config.connectionUrl=' ~ ([kc_desired_connection_url] | to_json)
|
||||||
|
] }}"
|
||||||
when: kc_needs_update | bool
|
when: kc_needs_update | bool
|
||||||
register: kc_bind_update
|
register: kc_bind_update
|
||||||
|
|
||||||
- name: "LDAP bind credentials updated"
|
- name: "LDAP provider updated"
|
||||||
debug:
|
debug:
|
||||||
msg: "LDAP bind DN/password updated on component {{ keycloak_ldap_component_name }}."
|
msg: "LDAP bindDn/bindCredential/connectionUrl updated on component {{ keycloak_ldap_component_name }}."
|
||||||
when:
|
when:
|
||||||
- kc_bind_update is defined
|
- kc_bind_update is defined
|
||||||
- kc_bind_update.rc == 0
|
- kc_bind_update.rc == 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user