mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-08-30 15:28:12 +02:00
ansible: quote file modes; keycloak: robust LDAP bind update + config cleanup
Highlights - Quote all file modes as strings ("0755"/"0770") across multiple roles to avoid YAML octal quirks and improve portability. - Keycloak: introduce actions.{import_realm,update_ldap_bind} feature flags and wire them via vars/config. - Implement idempotent LDAP bind updater (tasks/03_update-ldap-bind.yml): * kcadm login with no_log protection, * fetch LDAP UserStorage component by name, * compare current bindDn/bindCredential and update only when changed. - Keycloak realm import template: keep providerId="ldap" and set name from keycloak_ldap_component_name. - Centralize Keycloak readiness check in tasks/main.yml; remove duplicate waits from 02_update_client_redirects.yml and 04_ssh_public_key.yml. - 01_import.yml: fix typo (keycloak), quote modes, tidy spacing, and replace Jinja-in-Jinja fileglob with concatenation. - 02_update_client_redirects.yml: correct assert fail_msg filename; keep login-first flow. - Minor template/vars tidy-ups (spacing, comments, consistent variable usage). Files touched (excerpt) - roles/*/*: replace 0755/0770 → "0755"/"0770" - roles/web-app-keycloak/config/main.yml: add actions map - roles/web-app-keycloak/vars/main.yml: unify Keycloak vars and feature flags - roles/web-app-keycloak/tasks/{01_import,02_update_client_redirects,03_update-ldap-bind,04_ssh_public_key,main}.yml - roles/web-app-keycloak/templates/{docker-compose.yml.j2,import/realm.json.j2} https://chatgpt.com/share/689bda16-b138-800f-8258-e13f6d7d8239
This commit is contained in:
@@ -1,19 +1,19 @@
|
||||
- name: "load variables from {{ DOCKER_VARS_FILE }}"
|
||||
include_vars: "{{ DOCKER_VARS_FILE }}"
|
||||
|
||||
- name: Set the directory to which keycloack import files will be copied on host
|
||||
- name: Set the directory to which keycloak import files will be copied on host
|
||||
set_fact:
|
||||
keycloak_host_import_directory: "{{ docker_compose.directories.volumes }}import/"
|
||||
|
||||
- name: "create directory {{keycloak_host_import_directory}}"
|
||||
- name: "create directory {{ keycloak_host_import_directory }}"
|
||||
file:
|
||||
path: "{{keycloak_host_import_directory}}"
|
||||
path: "{{ keycloak_host_import_directory }}"
|
||||
state: directory
|
||||
mode: 0755
|
||||
mode: "0755"
|
||||
|
||||
- name: "Copy import files to {{ keycloak_host_import_directory }}"
|
||||
template:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ keycloak_host_import_directory }}/{{ item | basename | regex_replace('\\.j2$', '') }}"
|
||||
mode: '770'
|
||||
loop: "{{ lookup('fileglob', '{{ role_path }}/templates/import/*.j2', wantlist=True) }}"
|
||||
mode: "0770"
|
||||
loop: "{{ lookup('fileglob', role_path ~ '/templates/import/*.j2', wantlist=True) }}"
|
@@ -27,19 +27,7 @@
|
||||
- keycloak_redirect_features is defined
|
||||
- domains is defined
|
||||
- applications is defined
|
||||
fail_msg: "Missing required variable(s). Provide all vars listed at the top of 10_update_client_redirects.yml."
|
||||
|
||||
# 0) Wait & login
|
||||
- name: "Wait until Keycloak is reachable at {{ keycloak_server_host_url }}"
|
||||
uri:
|
||||
url: "{{ keycloak_server_host_url }}/realms/master"
|
||||
method: GET
|
||||
status_code: 200
|
||||
validate_certs: false
|
||||
register: kc_up
|
||||
retries: 30
|
||||
delay: 5
|
||||
until: kc_up.status == 200
|
||||
fail_msg: "Missing required variable(s). Provide all vars listed at the top of 02_update_client_redirects.yml."
|
||||
|
||||
- name: "kcadm login"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
@@ -1,42 +1,80 @@
|
||||
# Draft
|
||||
---
|
||||
# Updates the LDAP provider's bind DN / password using kcadm.sh, idempotently.
|
||||
# Sources DN/password from group_vars/all/13_ldap.yml:
|
||||
# - DN: ldap.dn.administrator.data
|
||||
# - Password: ldap.bind_credential
|
||||
|
||||
- name: Wait until Keycloak is up
|
||||
uri:
|
||||
url: "{{ keycloak_server_host_url }}/realms/{{ keycloak_realm }}"
|
||||
method: GET
|
||||
status_code: 200
|
||||
validate_certs: false
|
||||
register: keycloak_up
|
||||
retries: 30
|
||||
delay: 5
|
||||
until: keycloak_up.status == 200
|
||||
- name: "Assert required vars exist"
|
||||
assert:
|
||||
that:
|
||||
- keycloak_realm is defined
|
||||
- keycloak_server_host_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_password is defined
|
||||
- keycloak_ldap_component_name is defined
|
||||
- ldap is defined
|
||||
- ldap.dn.administrator.data is defined
|
||||
- ldap.bind_credential is defined
|
||||
fail_msg: "Missing Keycloak/LDAP vars. Ensure 13_ldap.yml is loaded and credentials are set."
|
||||
|
||||
- name: Log in with kcadm.sh
|
||||
shell: |
|
||||
{{ keycloak_kcadm_path }} config credentials \
|
||||
--server {{ keycloak_server_internal_url }} \
|
||||
--realm master \
|
||||
--user {{ keycloak_master_api_user_name }} \
|
||||
--password {{ keycloak_master_api_user_password }}
|
||||
|
||||
- name: Retrieve LDAP component ID
|
||||
shell: |
|
||||
{{ keycloak_kcadm_path }} get components \
|
||||
-r {{ keycloak_realm }} \
|
||||
--query 'providerId=ldap' \
|
||||
--fields id \
|
||||
--format json \
|
||||
| jq -r '.[0].id'
|
||||
register: ldap_component
|
||||
- name: "kcadm login (master)"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
shell: >
|
||||
{{ keycloak_kcadm_path }} config credentials
|
||||
--server {{ keycloak_server_internal_url }}
|
||||
--realm master
|
||||
--user {{ keycloak_master_api_user_name }}
|
||||
--password {{ keycloak_master_api_user_password }}
|
||||
changed_when: false
|
||||
|
||||
- name: Update LDAP bind password
|
||||
# Resolve the LDAP component *by name* to avoid picking the wrong one.
|
||||
- name: "Resolve LDAP component id by name '{{ keycloak_ldap_component_name }}'"
|
||||
shell: >
|
||||
{{ keycloak_kcadm_path }} get components
|
||||
-r {{ keycloak_realm }}
|
||||
--query 'name={{ keycloak_ldap_component_name }}'
|
||||
--fields id,name,providerId,config --format json
|
||||
register: kc_ldap_list
|
||||
changed_when: false
|
||||
|
||||
- name: "Validate that exactly one LDAP component matched"
|
||||
vars:
|
||||
new_bind_password: "MyNewLdapPassword123!"
|
||||
shell: |
|
||||
{{ keycloak_kcadm_path }} update components/{{ ldap_component.stdout }} \
|
||||
-r {{ keycloak_realm }} \
|
||||
-s 'config.bindCredential=["{{ new_bind_password }}"]'
|
||||
parsed: "{{ kc_ldap_list.stdout | from_json }}"
|
||||
assert:
|
||||
that:
|
||||
- (parsed | length) == 1
|
||||
fail_msg: >-
|
||||
Expected exactly one LDAP component named '{{ keycloak_ldap_component_name }}',
|
||||
found {{ (kc_ldap_list.stdout | from_json) | length }}.
|
||||
|
||||
- name: "Extract LDAP component facts"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
register: update_bind
|
||||
changed_when: update_bind.rc == 0
|
||||
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] }}"
|
||||
|
||||
- name: "Determine if update is required"
|
||||
set_fact:
|
||||
kc_needs_update: >-
|
||||
{{ (kc_ldap_current_bind_dn != ldap.dn.administrator.data)
|
||||
or (kc_ldap_current_bind_pw != ldap.bind_credential) }}
|
||||
|
||||
- name: "Update LDAP bind DN / bind password"
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
shell: >
|
||||
{{ keycloak_kcadm_path }} update components/{{ kc_ldap_component_id }}
|
||||
-r {{ keycloak_realm }}
|
||||
-s 'config.bindDn=["{{ ldap.dn.administrator.data | replace("'", "\\'") }}"]'
|
||||
-s 'config.bindCredential=["{{ ldap.bind_credential | replace("'", "\\'") }}"]'
|
||||
when: kc_needs_update | bool
|
||||
register: kc_bind_update
|
||||
|
||||
- name: "LDAP bind credentials updated"
|
||||
debug:
|
||||
msg: "LDAP bind DN/password updated on component {{ keycloak_ldap_component_name }}."
|
||||
when:
|
||||
- kc_bind_update is defined
|
||||
- kc_bind_update.rc == 0
|
||||
|
@@ -1,14 +1,3 @@
|
||||
- name: "Wait until Keycloak is reachable at {{ keycloak_server_host_url }}"
|
||||
uri:
|
||||
url: "{{ keycloak_server_host_url }}/realms/master"
|
||||
method: GET
|
||||
status_code: 200
|
||||
validate_certs: false
|
||||
register: keycloak_check
|
||||
retries: 30
|
||||
delay: 5
|
||||
until: keycloak_check.status == 200
|
||||
|
||||
# Configure Credentials
|
||||
- name: Ensure Keycloak CLI credentials are configured
|
||||
shell: |
|
||||
|
@@ -6,9 +6,24 @@
|
||||
include_role:
|
||||
name: cmp-db-docker-proxy
|
||||
|
||||
- name: "Wait until Keycloak is reachable at {{ keycloak_server_host_url }}"
|
||||
uri:
|
||||
url: "{{ keycloak_server_host_url }}/realms/master"
|
||||
method: GET
|
||||
status_code: 200
|
||||
validate_certs: false
|
||||
register: kc_up
|
||||
retries: 30
|
||||
delay: 5
|
||||
until: kc_up.status == 200
|
||||
|
||||
- name: "Apply client redirects without realm import"
|
||||
include_tasks: 02_update_client_redirects.yml
|
||||
|
||||
- name: "Update LDAP bind credentials from ldap.*"
|
||||
when: keycloak_update_ldap_bind | bool
|
||||
include_tasks: 03_update-ldap-bind.yml
|
||||
|
||||
# Deactivated temporary. Import now via realm.yml
|
||||
#- name: Implement SSH Public Key Attribut
|
||||
# include_tasks: 03_ssh_public_key.yml
|
Reference in New Issue
Block a user