From db19fd5d19a1eaa62bbbcc9d17012812f5400a24 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Thu, 7 Dec 2023 14:30:27 +0000 Subject: [PATCH 001/205] Bump version to 2.0.2 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index bd77fe6..ac09faa 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.0.1" +version: "2.0.2" readme: README.md authors: - Romain Pelisse From ed6dbd60fb9c358daf26907c0773a00344183f92 Mon Sep 17 00:00:00 2001 From: Ranabir Chakraborty Date: Mon, 11 Dec 2023 22:12:39 +0530 Subject: [PATCH 002/205] AMW-170 Ansible Hub links for rhbk are broken --- README.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index d93231f..efcd597 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ > **_NOTE:_ If you are Red Hat customer, install `redhat.sso` from [Automation Hub](https://console.redhat.com/ansible/ansible-dashboard) as the certified version of this collection.** -Collection to install and configure [Keycloak](https://www.keycloak.org/) or [Red Hat Single Sign-On](https://access.redhat.com/products/red-hat-single-sign-on). +Collection to install and configure [Keycloak](https://www.keycloak.org/) or [Red Hat Single Sign-On](https://access.redhat.com/products/red-hat-single-sign-on). ## Ansible version compatibility @@ -44,25 +44,25 @@ A requirement file is provided to install: pip install -r requirements.txt - + ### Included roles * [`keycloak`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak/README.md): role for installing the service. * [`keycloak_realm`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak_realm/README.md): role for configuring a realm, user federation(s), clients and users, in an installed service. * [`keycloak_quarkus`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak_quarkus/README.md): role for installing the quarkus variant of keycloak (>= 17.0.0). - + ## Usage ### Install Playbook - + * [`playbooks/keycloak.yml`](https://github.com/ansible-middleware/keycloak/blob/main/playbooks/keycloak.yml) installs based on the defined variables (using most defaults). Both playbooks include the `keycloak` role, with different settings, as described in the following sections. For full service configuration details, refer to the [keycloak role README](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak/README.md). - + #### Install from controller node (offline) @@ -85,7 +85,7 @@ It is possible to perform downloads from alternate sources, using the `keycloak_ ### Example installation command -Execute the following command from the source root directory +Execute the following command from the source root directory ``` ansible-playbook -i -e @rhn-creds.yml playbooks/keycloak.yml -e keycloak_admin_password= @@ -106,9 +106,9 @@ Note: when deploying clustered configurations, all hosts belonging to the cluste ### Config Playbook - + [`playbooks/keycloak_realm.yml`](https://github.com/ansible-middleware/keycloak/blob/main/playbooks/keycloak_realm.yml) creates or updates provided realm, user federation(s), client(s), client role(s) and client user(s). - + ### Example configuration command @@ -126,9 +126,9 @@ ansible-playbook -i playbooks/keycloak_realm.yml -e keycloak_adm [keycloak] localhost ansible_connection=local ``` - + For full configuration details, refer to the [keycloak_realm role README](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak_realm/README.md). - + @@ -137,6 +137,7 @@ For full configuration details, refer to the [keycloak_realm role README](https: ## License Apache License v2.0 or later - + See [LICENSE](LICENSE) to view the full text. + From 83bcb6712adb24cd4904aa8c2c49287ec99a1aa8 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 19 Dec 2023 09:30:30 +0100 Subject: [PATCH 003/205] keycloak_quarkus: add systemd control options * keycloak_quarkus_service_restart_always * keycloak_quarkus_service_restart_on_failure * keycloak_quarkus_service_restartsec --- roles/keycloak_quarkus/README.md | 7 +++++-- roles/keycloak_quarkus/defaults/main.yml | 3 +++ roles/keycloak_quarkus/meta/argument_specs.yml | 12 ++++++++++++ roles/keycloak_quarkus/templates/keycloak.service.j2 | 7 +++++++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 9a04e1b..8fa1a75 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -31,6 +31,9 @@ Role Defaults |`keycloak_quarkus_jgroups_port`| jgroups cluster tcp port | `7600` | |`keycloak_quarkus_service_user`| Posix account username | `keycloak` | |`keycloak_quarkus_service_group`| Posix account group | `keycloak` | +|`keycloak_quarkus_service_restart_always`| systemd restart always behavior activation | `False` | +|`keycloak_quarkus_service_restart_on_failure`| systemd restart on-failure behavior activation | `False` | +|`keycloak_quarkus_service_restartsec`| systemd RestartSec | `10s` | |`keycloak_quarkus_service_pidfile`| Pid file path for service | `/run/keycloak.pid` | |`keycloak_quarkus_jvm_package`| RHEL java package runtime | `java-17-openjdk-headless` | |`keycloak_quarkus_java_home`| JAVA_HOME of installed JRE, leave empty for using specified keycloak_quarkus_jvm_package RPM path | `None` | @@ -79,7 +82,7 @@ Role Defaults |`keycloak_quarkus_ispn_sasl_mechanism` | Infinispan auth mechanism | `SCRAM-SHA-512` | |`keycloak_quarkus_ispn_use_ssl` | Whether infinispan uses TLS connection | `false` | |`keycloak_quarkus_ispn_trust_store_path` | Path to infinispan server trust certificate | `/etc/pki/java/cacerts` | -|`keycloak_quarkus_ispn_trust_store_password` | Password for infinispan certificate keystore | `changeit` | +|`keycloak_quarkus_ispn_trust_store_password` | Password for infinispan certificate keystore | `changeit` | * Install options @@ -87,7 +90,7 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:---------| |`keycloak_quarkus_offline_install` | Perform an offline install | `False`| -|`keycloak_quarkus_download_url`| Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download//`| +|`keycloak_quarkus_download_url`| Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download//`| |`keycloak_quarkus_version`| keycloak.org package version | `23.0.1` | |`keycloak_quarkus_dest`| Installation root path | `/opt/keycloak` | |`keycloak_quarkus_download_url` | Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index a4f1d5e..1a1382f 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -19,6 +19,9 @@ keycloak_quarkus_service_user: keycloak keycloak_quarkus_service_group: keycloak keycloak_quarkus_service_pidfile: "/run/keycloak/keycloak.pid" keycloak_quarkus_configure_firewalld: false +keycloak_quarkus_service_restart_always: false +keycloak_quarkus_service_restart_on_failure: false +keycloak_quarkus_service_restartsec: "10s" ### administrator console password keycloak_quarkus_admin_user: admin diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 6fdd108..f616611 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -69,6 +69,18 @@ argument_specs: default: false description: "Ensure firewalld is running and configure keycloak ports" type: "bool" + keycloak_service_restart_always: + default: false + description: "systemd restart always behavior of service" + type: "bool" + keycloak_service_restart_on_failure: + default: false + description: "systemd restart on-failure behavior of service" + type: "bool" + keycloak_service_restartsec: + default: "10s" + description: "systemd RestartSec for service" + type: "str" keycloak_quarkus_admin_user: default: "admin" description: "Administration console user account" diff --git a/roles/keycloak_quarkus/templates/keycloak.service.j2 b/roles/keycloak_quarkus/templates/keycloak.service.j2 index f7ffc1c..1854463 100644 --- a/roles/keycloak_quarkus/templates/keycloak.service.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.service.j2 @@ -13,6 +13,13 @@ ExecStart={{ keycloak.home }}/bin/kc.sh start-dev ExecStart={{ keycloak.home }}/bin/kc.sh start --log={{ keycloak_quarkus_log }} {% endif %} User={{ keycloak.service_user }} +Group={{ keycloak.service_group }} +{% if keycloak_quarkus_service_restart_always %} +Restart=always +{% elif keycloak_quarkus_service_restart_on_failure %} +Restart=on-failure +{% endif %} +RestartSec={{ keycloak_quarkus_service_restartsec }} [Install] WantedBy=multi-user.target From 1d5ce87c16a69ceacd16790e3cd5f69c1fc72846 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 19 Dec 2023 09:55:02 +0100 Subject: [PATCH 004/205] keycloak_quarkus: Remove legacy (?) `keycloak_management_url` --- roles/keycloak_quarkus/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 8fa1a75..e419d89 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -111,7 +111,6 @@ Role Defaults |`keycloak_auth_client` | Authentication client for configuration REST calls | `admin-cli` | |`keycloak_force_install` | Remove pre-existing versions of service | `False` | |`keycloak_url` | URL for configuration rest calls | `http://{{ keycloak_quarkus_host }}:{{ keycloak_http_port }}` | -|`keycloak_management_url` | URL for management console rest calls | `http://{{ keycloak_quarkus_host }}:{{ keycloak_management_http_port }}` | |`keycloak_quarkus_log`| Enable one or more log handlers in a comma-separated list | `file` | |`keycloak_quarkus_log_level`| The log level of the root category or a comma-separated list of individual categories and their levels | `info` | |`keycloak_quarkus_log_file`| Set the log file path and filename relative to keycloak home | `data/log/keycloak.log` | From bfd9db6703daf0550f3910c44840331bc04a345b Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 8 Jan 2024 17:42:30 +0100 Subject: [PATCH 005/205] fix/147: keycloak_quarkus: RBKC: Add support for sqlserver jdbc driver --- roles/keycloak_quarkus/README.md | 2 +- roles/keycloak_quarkus/defaults/main.yml | 5 ++++- roles/keycloak_quarkus/meta/argument_specs.yml | 2 +- roles/keycloak_quarkus/tasks/install.yml | 6 ++++++ roles/keycloak_quarkus/tasks/jdbc_driver.yml | 12 ++++++++++++ 5 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 roles/keycloak_quarkus/tasks/jdbc_driver.yml diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index c2338c3..acdb121 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -55,7 +55,7 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| -|`keycloak_quarkus_jdbc_engine` | Database engine [mariadb,postres] | `postgres` | +|`keycloak_quarkus_jdbc_engine` | Database engine [mariadb,postres,mssql] | `postgres` | |`keycloak_quarkus_db_user` | User for database connection | `keycloak-user` | |`keycloak_quarkus_db_pass` | Password for database connection | `keycloak-pass` | |`keycloak_quarkus_jdbc_url` | JDBC URL for connecting to database | `jdbc:postgresql://localhost:5432/keycloak` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 51ca792..1c7a41b 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -97,7 +97,10 @@ keycloak_quarkus_default_jdbc: mariadb: url: 'jdbc:mariadb://localhost:3306/keycloak' version: 2.7.4 - + mssql: + url: 'jdbc:sqlserver://localhost:1433;databaseName=keycloak;' + version: 12.2.0 + driver_jar_url: "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/12.2.0.jre11/mssql-jdbc-12.2.0.jre11.jar" # cf. https://access.redhat.com/documentation/en-us/red_hat_build_of_keycloak/22.0/html/server_guide/db-#db-installing-the-microsoft-sql-server-driver ### logging configuration keycloak_quarkus_log: file keycloak_quarkus_log_level: info diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index d260910..accd770 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -234,7 +234,7 @@ argument_specs: keycloak_quarkus_jdbc_engine: # line 56 of defaults/main.yml default: "postgres" - description: "Database engine [mariadb,postres]" + description: "Database engine [mariadb,postres,mssql]" type: "str" keycloak_quarkus_db_user: # line 58 of defaults/main.yml diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index b1ea1ee..ebd8585 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -109,3 +109,9 @@ msg: "{{ keycloak.home }} already exists and version unchanged, skipping decompression" when: - (not new_version_downloaded.changed) and path_to_workdir.stat.exists + +- name: "Install {{ keycloak_quarkus_jdbc_engine }} JDBC driver" + ansible.builtin.include_tasks: jdbc_driver.yml + when: + - rhbk_enable is defined and rhbk_enable + - keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url is defined diff --git a/roles/keycloak_quarkus/tasks/jdbc_driver.yml b/roles/keycloak_quarkus/tasks/jdbc_driver.yml new file mode 100644 index 0000000..0d03030 --- /dev/null +++ b/roles/keycloak_quarkus/tasks/jdbc_driver.yml @@ -0,0 +1,12 @@ +--- + +- name: "Retrieve JDBC Driver from {{ keycloak_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url }}" + ansible.builtin.get_url: + url: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url }}" + dest: "{{ keycloak.home }}/providers" + owner: "{{ keycloak.service_user }}" + group: "{{ keycloak.service_group }}" + mode: 0640 + become: true + notify: + - restart keycloak From b057f0297ac6c79794bbf13f5318a85798fe5073 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 9 Jan 2024 08:20:02 +0100 Subject: [PATCH 006/205] fix/#151: keycloak_quarkus: allow configuration of `hostname-strict-backchannel` --- roles/keycloak_quarkus/README.md | 1 + roles/keycloak_quarkus/defaults/main.yml | 3 +++ roles/keycloak_quarkus/meta/argument_specs.yml | 4 ++++ roles/keycloak_quarkus/templates/keycloak.conf.j2 | 1 + 4 files changed, 9 insertions(+) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 9a04e1b..623ca28 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -56,6 +56,7 @@ Role Defaults |:---------|:------------|:--------| |`keycloak_quarkus_http_relative_path`| Set the path relative to / for serving resources. The path must start with a / | `/` | |`keycloak_quarkus_hostname_strict`| Disables dynamically resolving the hostname from request headers | `true` | +|`keycloak_quarkus_hostname_strict_backchannel`| By default backchannel URLs are dynamically resolved from request headers to allow internal and external applications. If all applications use the public URL this option should be enabled. | `false` | * Database configuration diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index a4f1d5e..46cce41 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -66,6 +66,9 @@ keycloak_quarkus_http_relative_path: / # Disables dynamically resolving the hostname from request headers. # Should always be set to true in production, unless proxy verifies the Host header. keycloak_quarkus_hostname_strict: true +# By default backchannel URLs are dynamically resolved from request headers to allow internal and external applications. +# If all applications use the public URL this option should be enabled. +keycloak_quarkus_hostname_strict_backchannel: false # proxy address forwarding mode if the server is behind a reverse proxy. [none, edge, reencrypt, passthrough] keycloak_quarkus_proxy_mode: edge diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 6fdd108..e975696 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -292,6 +292,10 @@ argument_specs: default: true type: "bool" description: "Disables dynamically resolving the hostname from request headers. Should always be set to true in production, unless proxy verifies the Host header." + keycloak_quarkus_hostname_strict_backchannel: + default: false + type: "bool" + description: "By default backchannel URLs are dynamically resolved from request headers to allow internal and external applications. If all applications use the public URL this option should be enabled." downstream: options: rhbk_version: diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index b3b6787..8ea545d 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -42,6 +42,7 @@ hostname-path={{ keycloak_quarkus_path }} {% endif %} hostname-admin-url={{ keycloak_quarkus_admin_url }} hostname-strict={{ keycloak_quarkus_hostname_strict | lower }} +hostname-strict-backchannel={{ keycloak_quarkus_hostname_strict_backchannel | lower }} # Cluster {% if keycloak_quarkus_ha_enabled %} From b1b31427d50b88f0e9f039b54a046245290338f5 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Wed, 10 Jan 2024 16:26:46 +0100 Subject: [PATCH 007/205] fix/#153: keycloak_quarkus: Use `keycloak_quarkus_java_opts` Note: when multiple -X options of the same kind are provided, the last option seems to take precendence as per : > java -Xmx1G -XX:+PrintFlagsFinal -Xmx2G 2>/dev/null | grep MaxHeapSize --- roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 | 1 + 1 file changed, 1 insertion(+) diff --git a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 index a3fdf57..b028085 100644 --- a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 +++ b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 @@ -3,3 +3,4 @@ KEYCLOAK_ADMIN={{ keycloak_quarkus_admin_user }} KEYCLOAK_ADMIN_PASSWORD='{{ keycloak_quarkus_admin_pass }}' PATH={{ keycloak_java_home | default(keycloak_rpm_java_home, true) }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin JAVA_HOME={{ keycloak_java_home | default(keycloak_rpm_java_home, true) }} +JAVA_OPTS_APPEND={{ keycloak_quarkus_java_opts }} \ No newline at end of file From 922e4c10f5557b341aa929da03d2f68ef8a86235 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 15 Jan 2024 14:40:46 +0100 Subject: [PATCH 008/205] #145 - CR changes --- galaxy.yml | 1 + roles/keycloak_quarkus/README.md | 1 - roles/keycloak_quarkus/meta/argument_specs.yml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy.yml b/galaxy.yml index ac09faa..21cb096 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -7,6 +7,7 @@ authors: - Romain Pelisse - Guido Grazioli - Pavan Kumar Motaparthi + - Helmut Wolf description: Install and configure a keycloak, or Red Hat Single Sign-on, service. license_file: "LICENSE" tags: diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index e419d89..9fdb2e0 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -90,7 +90,6 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:---------| |`keycloak_quarkus_offline_install` | Perform an offline install | `False`| -|`keycloak_quarkus_download_url`| Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download//`| |`keycloak_quarkus_version`| keycloak.org package version | `23.0.1` | |`keycloak_quarkus_dest`| Installation root path | `/opt/keycloak` | |`keycloak_quarkus_download_url` | Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}` | diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index f616611..3ad24f8 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -71,7 +71,7 @@ argument_specs: type: "bool" keycloak_service_restart_always: default: false - description: "systemd restart always behavior of service" + description: "systemd restart always behavior of service; takes precedence over keycloak_service_restart_on_failure if true" type: "bool" keycloak_service_restart_on_failure: default: false From 8adc018cb317fe172d783f731e5c347b884a1aae Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 8 Jan 2024 18:19:00 +0100 Subject: [PATCH 009/205] fix/#149: keycloak_quarkus: Allow ports <1024 (e.g., :443) --- roles/keycloak_quarkus/templates/keycloak.service.j2 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/roles/keycloak_quarkus/templates/keycloak.service.j2 b/roles/keycloak_quarkus/templates/keycloak.service.j2 index 1854463..a529c5b 100644 --- a/roles/keycloak_quarkus/templates/keycloak.service.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.service.j2 @@ -20,6 +20,9 @@ Restart=always Restart=on-failure {% endif %} RestartSec={{ keycloak_quarkus_service_restartsec }} +{% if keycloak_quarkus_http_port|int < 1024 or keycloak_quarkus_https_port|int < 1024 %} +AmbientCapabilities=CAP_NET_BIND_SERVICE +{% endif %} [Install] WantedBy=multi-user.target From 30309582f37439893c33939cd2081845f6e7b63b Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 16 Jan 2024 09:17:47 +0100 Subject: [PATCH 010/205] Update README.md --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0cb62c2..0cd3ba0 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,10 @@ [![Build Status](https://github.com/ansible-middleware/keycloak/workflows/CI/badge.svg?branch=main)](https://github.com/ansible-middleware/keycloak/actions/workflows/ci.yml) -> **_NOTE:_ If you are Red Hat customer, install `redhat.sso` from [Automation Hub](https://console.redhat.com/ansible/ansible-dashboard) as the certified version of this collection.** +> **_NOTE:_ If you are Red Hat customer, install `redhat.sso` (for Red Hat Single Sign-On) or `redhat.rhbk` (for Red Hat Build of Keycloak) from [Automation Hub](https://console.redhat.com/ansible/ansible-dashboard) as the certified version of this collection.** -Collection to install and configure [Keycloak](https://www.keycloak.org/) or [Red Hat Single Sign-On](https://access.redhat.com/products/red-hat-single-sign-on). +Collection to install and configure [Keycloak](https://www.keycloak.org/) or [Red Hat Single Sign-On](https://access.redhat.com/products/red-hat-single-sign-on) / [Red Hat Build of Keycloak](https://access.redhat.com/products/red-hat-build-of-keycloak). ## Ansible version compatibility @@ -47,7 +47,7 @@ A requirement file is provided to install: ### Included roles -* [`keycloak`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak/README.md): role for installing the service. +* [`keycloak`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak/README.md): role for installing the service (keycloak <= 19.0). * [`keycloak_realm`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak_realm/README.md): role for configuring a realm, user federation(s), clients and users, in an installed service. * [`keycloak_quarkus`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak_quarkus/README.md): role for installing the quarkus variant of keycloak (>= 17.0.0). @@ -57,8 +57,9 @@ A requirement file is provided to install: ### Install Playbook -* [`playbooks/keycloak.yml`](https://github.com/ansible-middleware/keycloak/blob/main/playbooks/keycloak.yml) installs based on the defined variables (using most defaults). - +* [`playbooks/keycloak.yml`](https://github.com/ansible-middleware/keycloak/blob/main/playbooks/keycloak.yml) installs keycloak legacy based on the defined variables (using most defaults). +* [`playbooks/keycloak_quarkus.yml`](https://github.com/ansible-middleware/keycloak/blob/main/playbooks/keycloak_quarkus.yml) installs keycloak >= 17 based on the defined variables (using most defaults). + Both playbooks include the `keycloak` role, with different settings, as described in the following sections. For full service configuration details, refer to the [keycloak role README](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak/README.md). From 2985f808ea4cb62019a294d399f454fbe4a5c306 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Wed, 17 Jan 2024 08:50:24 +0000 Subject: [PATCH 011/205] Update changelog for release 2.0.2 Signed-off-by: ansible-middleware-core --- CHANGELOG.rst | 16 ++++++++++++++++ changelogs/changelog.yaml | 27 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 274cfa3..c3a46da 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,22 @@ middleware_automation.keycloak Release Notes This changelog describes changes after version 0.2.6. +v2.0.2 +====== + +Minor Changes +------------- + +- keycloak_quarkus: Add support for sqlserver jdbc driver `#148 `_ +- keycloak_quarkus: allow configuration of ``hostname-strict-backchannel`` `#152 `_ +- keycloak_quarkus: systemd restart behavior `#145 `_ + +Bugfixes +-------- + +- keycloak_quarkus: Use ``keycloak_quarkus_java_opts`` `#154 `_ +- keycloak_quarkus: allow ports <1024 (e.g. :443) in systemd unit `#150 `_ + v2.0.1 ====== diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 7d19d7f..7d684cd 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -359,3 +359,30 @@ releases: - 138.yaml - 139.yaml release_date: '2023-12-07' + 2.0.2: + changes: + bugfixes: + - 'keycloak_quarkus: Use ``keycloak_quarkus_java_opts`` `#154 `_ + + ' + - 'keycloak_quarkus: allow ports <1024 (e.g. :443) in systemd unit `#150 `_ + + ' + minor_changes: + - 'keycloak_quarkus: Add support for sqlserver jdbc driver `#148 `_ + + ' + - 'keycloak_quarkus: allow configuration of ``hostname-strict-backchannel`` + `#152 `_ + + ' + - 'keycloak_quarkus: systemd restart behavior `#145 `_ + + ' + fragments: + - 145.yaml + - 148.yaml + - 150.yaml + - 152.yaml + - 154.yaml + release_date: '2024-01-17' From e866d1f4e417a0d7d02216ebdff5f8554980f401 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Wed, 17 Jan 2024 08:50:31 +0000 Subject: [PATCH 012/205] Bump version to 2.0.3 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index 21cb096..b5c1a2b 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.0.2" +version: "2.0.3" readme: README.md authors: - Romain Pelisse From 688ec956fc6df2a77e0eb81b133896cf673ecf82 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Wed, 17 Jan 2024 16:51:24 +0100 Subject: [PATCH 013/205] fix #156: quarkus 3 ispn config renamings --- galaxy.yml | 2 +- roles/keycloak_quarkus/README.md | 2 +- roles/keycloak_quarkus/defaults/main.yml | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 6 +++--- .../templates/quarkus.properties.j2 | 14 +++++++++----- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/galaxy.yml b/galaxy.yml index b5c1a2b..6a1d110 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.0.3" +version: "2.1.0" readme: README.md authors: - Romain Pelisse diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index e0a189b..cd720a5 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -79,7 +79,7 @@ Role Defaults |:---------|:------------|:--------| |`keycloak_quarkus_ispn_user` | Username for connecting to infinispan | `supervisor` | |`keycloak_quarkus_ispn_pass` | Password for connecting to infinispan | `supervisor` | -|`keycloak_quarkus_ispn_url` | URL for connecting to infinispan | `localhost` | +|`keycloak_quarkus_ispn_hosts` | host name/port for connecting to infinispan, eg. host1:11222;host2:11222 | `localhost:11222` | |`keycloak_quarkus_ispn_sasl_mechanism` | Infinispan auth mechanism | `SCRAM-SHA-512` | |`keycloak_quarkus_ispn_use_ssl` | Whether infinispan uses TLS connection | `false` | |`keycloak_quarkus_ispn_trust_store_path` | Path to infinispan server trust certificate | `/etc/pki/java/cacerts` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index bcc03ee..da42960 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -85,7 +85,7 @@ keycloak_quarkus_health_enabled: true ### infinispan remote caches access (hotrod) keycloak_quarkus_ispn_user: supervisor keycloak_quarkus_ispn_pass: supervisor -keycloak_quarkus_ispn_url: localhost +keycloak_quarkus_ispn_hosts: "localhost:11222" keycloak_quarkus_ispn_sasl_mechanism: SCRAM-SHA-512 keycloak_quarkus_ispn_use_ssl: false # if ssl is enabled, import ispn server certificate here diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 22a9b45..37c873e 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -218,10 +218,10 @@ argument_specs: default: "supervisor" description: "Password for connecting to infinispan" type: "str" - keycloak_quarkus_ispn_url: + keycloak_quarkus_ispn_hosts: # line 48 of defaults/main.yml - default: "localhost" - description: "URL for connecting to infinispan" + default: "localhost:11222" + description: "host name/port for connecting to infinispan, eg. host1:11222;host2:11222" type: "str" keycloak_quarkus_ispn_sasl_mechanism: # line 49 of defaults/main.yml diff --git a/roles/keycloak_quarkus/templates/quarkus.properties.j2 b/roles/keycloak_quarkus/templates/quarkus.properties.j2 index cf133a3..cb2f2d3 100644 --- a/roles/keycloak_quarkus/templates/quarkus.properties.j2 +++ b/roles/keycloak_quarkus/templates/quarkus.properties.j2 @@ -1,10 +1,16 @@ # {{ ansible_managed }} {% if keycloak_quarkus_ha_enabled %} -quarkus.infinispan-client.server-list={{ keycloak_quarkus_ispn_url }} -quarkus.infinispan-client.client-intelligence=HASH_DISTRIBUTION_AWARE -quarkus.infinispan-client.use-auth=true +{% if not rhbk_enable or keycloak_quarkus_version.split('.')[0]|int < 22 %} +quarkus.infinispan-client.server-list={{ keycloak_quarkus_ispn_hosts }} quarkus.infinispan-client.auth-username={{ keycloak_quarkus_ispn_user }} quarkus.infinispan-client.auth-password={{ keycloak_quarkus_ispn_pass }} +{% else %} +quarkus.infinispan-client.hosts={{ keycloak_quarkus_ispn_hosts }} +quarkus.infinispan-client.username={{ keycloak_quarkus_ispn_user }} +quarkus.infinispan-client.password={{ keycloak_quarkus_ispn_pass }} +{% endif %} +quarkus.infinispan-client.client-intelligence=HASH_DISTRIBUTION_AWARE +quarkus.infinispan-client.use-auth=true quarkus.infinispan-client.auth-realm=default quarkus.infinispan-client.auth-server-name=infinispan quarkus.infinispan-client.sasl-mechanism={{ keycloak_quarkus_ispn_sasl_mechanism }} @@ -14,6 +20,4 @@ quarkus.infinispan-client.trust-store-password={{ keycloak_quarkus_ispn_trust_st quarkus.infinispan-client.trust-store-type=jks {% endif %} #quarkus.infinispan-client.use-schema-registration=true -#quarkus.infinispan-client.auth-client-subject -#quarkus.infinispan-client.auth-callback-handler {% endif %} \ No newline at end of file From 63f83d77445feb698f4ea784ea370489f781ee14 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Wed, 17 Jan 2024 17:22:06 +0100 Subject: [PATCH 014/205] add initial support for templating `cache-ispn.xml` --- roles/keycloak_quarkus/tasks/main.yml | 11 +++ .../keycloak_quarkus/templates/cache-ispn.xml | 85 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 roles/keycloak_quarkus/templates/cache-ispn.xml diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index 71582f8..394cf3b 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -43,6 +43,17 @@ notify: - restart keycloak +- name: "Configure infinispan config for keycloak service" + ansible.builtin.template: + src: cache-ispn.xml + dest: "{{ keycloak.home }}/conf/cache-ispn.xml" + owner: "{{ keycloak.service_user }}" + group: "{{ keycloak.service_group }}" + mode: 0644 + become: true + notify: + - restart keycloak + - name: Ensure logdirectory exists ansible.builtin.file: state: directory diff --git a/roles/keycloak_quarkus/templates/cache-ispn.xml b/roles/keycloak_quarkus/templates/cache-ispn.xml new file mode 100644 index 0000000..20a1af7 --- /dev/null +++ b/roles/keycloak_quarkus/templates/cache-ispn.xml @@ -0,0 +1,85 @@ +# {{ ansible_managed }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 0c5047bcc109393e63a707d903edea0d0f82bdb9 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 22 Jan 2024 13:53:28 +0100 Subject: [PATCH 015/205] feature/160: keycloak_quarkus: Allow easier log setting configuration --- roles/keycloak_quarkus/README.md | 3 +++ roles/keycloak_quarkus/defaults/main.yml | 3 +++ roles/keycloak_quarkus/meta/argument_specs.yml | 12 ++++++++++++ .../keycloak_quarkus/templates/quarkus.properties.j2 | 5 ++++- 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index cd720a5..80eef90 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -116,6 +116,9 @@ Role Defaults |`keycloak_quarkus_log_file`| Set the log file path and filename relative to keycloak home | `data/log/keycloak.log` | |`keycloak_quarkus_log_format`| Set a format specific to file log entries | `%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n` | |`keycloak_quarkus_log_target`| Set the destination of the keycloak log folder link | `/var/log/keycloak` | +|`keycloak_quarkus_log_max_file_size`| Set the maximum log file size before a log rotation happens; A size configuration option recognises string in this format (shown as a regular expression): [0-9]+[KkMmGgTtPpEeZzYy]?. If no suffix is given, assume bytes." | `10M` +|`keycloak_quarkus_log_max_backup_index`| Set the maximum number of archived log files to keep" | `10` +|`keycloak_quarkus_log_file_suffix`| Set the log file handler rotation file suffix. When used, the file will be rotated based on its suffix; Note: If the suffix ends with `.zip` or `.gz`, the rotation file will also be compressed." | `.yyyy-MM-dd.zip` |`keycloak_quarkus_proxy_mode`| The proxy address forwarding mode if the server is behind a reverse proxy | `edge` | |`keycloak_quarkus_start_dev`| Whether to start the service in development mode (start-dev) | `False` | |`keycloak_quarkus_transaction_xa_enabled`| Whether to use XA transactions | `True` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index da42960..fa85d98 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -117,3 +117,6 @@ keycloak_quarkus_log_level: info keycloak_quarkus_log_file: data/log/keycloak.log keycloak_quarkus_log_format: '%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n' keycloak_quarkus_log_target: /var/log/keycloak +keycloak_quarkus_log_max_file_size: 10M +keycloak_quarkus_log_max_backup_index: 10 +keycloak_quarkus_log_file_suffix: '.yyyy-MM-dd.zip' diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 37c873e..f7b49e3 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -288,6 +288,18 @@ argument_specs: default: '/var/log/keycloak' type: "str" description: "Set the destination of the keycloak log folder link" + keycloak_quarkus_log_max_file_size: + default: 10M + type: "str" + description: "Set the maximum log file size before a log rotation happens; A size configuration option recognises string in this format (shown as a regular expression): [0-9]+[KkMmGgTtPpEeZzYy]?. If no suffix is given, assume bytes." + keycloak_quarkus_log_max_backup_index: + default: 10 + type: "str" + description: "Set the maximum number of archived log files to keep" + keycloak_quarkus_log_file_suffix: + default: '.yyyy-MM-dd.zip' + type: "str" + description: "Set the log file handler rotation file suffix. When used, the file will be rotated based on its suffix; Note: If the suffix ends with .zip or .gz, the rotation file will also be compressed." keycloak_quarkus_proxy_mode: default: 'edge' type: "str" diff --git a/roles/keycloak_quarkus/templates/quarkus.properties.j2 b/roles/keycloak_quarkus/templates/quarkus.properties.j2 index cb2f2d3..f8502f2 100644 --- a/roles/keycloak_quarkus/templates/quarkus.properties.j2 +++ b/roles/keycloak_quarkus/templates/quarkus.properties.j2 @@ -20,4 +20,7 @@ quarkus.infinispan-client.trust-store-password={{ keycloak_quarkus_ispn_trust_st quarkus.infinispan-client.trust-store-type=jks {% endif %} #quarkus.infinispan-client.use-schema-registration=true -{% endif %} \ No newline at end of file +{% endif %} +quarkus.log.file.rotation.max-file-size={{ keycloak_quarkus_log_max_file_size }} +quarkus.log.file.rotation.max-backup-index={{ keycloak_quarkus_log_max_backup_index }} +quarkus.log.file.rotation.file-suffix={{ keycloak_quarkus_log_file_suffix }} \ No newline at end of file From c2009a0a12d28e6fa8114d22c11a3214caceea7b Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Thu, 8 Feb 2024 16:10:32 +0100 Subject: [PATCH 016/205] feature/160: CR changes --- roles/keycloak_quarkus/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 80eef90..1f222a6 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -116,9 +116,9 @@ Role Defaults |`keycloak_quarkus_log_file`| Set the log file path and filename relative to keycloak home | `data/log/keycloak.log` | |`keycloak_quarkus_log_format`| Set a format specific to file log entries | `%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n` | |`keycloak_quarkus_log_target`| Set the destination of the keycloak log folder link | `/var/log/keycloak` | -|`keycloak_quarkus_log_max_file_size`| Set the maximum log file size before a log rotation happens; A size configuration option recognises string in this format (shown as a regular expression): [0-9]+[KkMmGgTtPpEeZzYy]?. If no suffix is given, assume bytes." | `10M` -|`keycloak_quarkus_log_max_backup_index`| Set the maximum number of archived log files to keep" | `10` -|`keycloak_quarkus_log_file_suffix`| Set the log file handler rotation file suffix. When used, the file will be rotated based on its suffix; Note: If the suffix ends with `.zip` or `.gz`, the rotation file will also be compressed." | `.yyyy-MM-dd.zip` +|`keycloak_quarkus_log_max_file_size`| Set the maximum log file size before a log rotation happens; A size configuration option recognises string in this format (shown as a regular expression): `[0-9]+[KkMmGgTtPpEeZzYy]?`. If no suffix is given, assume bytes. | `10M` | +|`keycloak_quarkus_log_max_backup_index`| Set the maximum number of archived log files to keep" | `10` | +|`keycloak_quarkus_log_file_suffix`| Set the log file handler rotation file suffix. When used, the file will be rotated based on its suffix; Note: If the suffix ends with `.zip` or `.gz`, the rotation file will also be compressed. | `.yyyy-MM-dd.zip` | |`keycloak_quarkus_proxy_mode`| The proxy address forwarding mode if the server is behind a reverse proxy | `edge` | |`keycloak_quarkus_start_dev`| Whether to start the service in development mode (start-dev) | `False` | |`keycloak_quarkus_transaction_xa_enabled`| Whether to use XA transactions | `True` | From e0d4920a490c8248174ad70b536c627331b342ef Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 22 Jan 2024 14:06:38 +0100 Subject: [PATCH 017/205] feature/162: keycloak_quarkus: make `spi-sticky-session-encoder-infinispan-should-attach-route` configurable in `keycloak.conf` --- roles/keycloak_quarkus/README.md | 2 +- roles/keycloak_quarkus/defaults/main.yml | 3 +++ roles/keycloak_quarkus/meta/argument_specs.yml | 4 ++++ roles/keycloak_quarkus/templates/keycloak.conf.j2 | 3 +-- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index cd720a5..8a32909 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -119,7 +119,7 @@ Role Defaults |`keycloak_quarkus_proxy_mode`| The proxy address forwarding mode if the server is behind a reverse proxy | `edge` | |`keycloak_quarkus_start_dev`| Whether to start the service in development mode (start-dev) | `False` | |`keycloak_quarkus_transaction_xa_enabled`| Whether to use XA transactions | `True` | - +|`keycloak_quarkus_spi_sticky_session_encoder_infinispan_should_attach_route`| If the route should be attached to cookies to reflect the node that owns a particular session. If false, route is not attached to cookies and we rely on the session affinity capabilities from reverse proxy | `True` | Role Variables -------------- diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index da42960..a2141bc 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -79,6 +79,9 @@ keycloak_quarkus_proxy_mode: edge # disable xa transactions keycloak_quarkus_transaction_xa_enabled: true +# If the route should be attached to cookies to reflect the node that owns a particular session. If false, route is not attached to cookies and we rely on the session affinity capabilities from reverse proxy +keycloak_quarkus_spi_sticky_session_encoder_infinispan_should_attach_route: true + keycloak_quarkus_metrics_enabled: false keycloak_quarkus_health_enabled: true diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 37c873e..5760c7d 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -308,6 +308,10 @@ argument_specs: default: false type: "bool" description: "By default backchannel URLs are dynamically resolved from request headers to allow internal and external applications. If all applications use the public URL this option should be enabled." + keycloak_quarkus_spi_sticky_session_encoder_infinispan_should_attach_route: + default: true + type: "bool" + description: "If the route should be attached to cookies to reflect the node that owns a particular session. If false, route is not attached to cookies and we rely on the session affinity capabilities from reverse proxy" downstream: options: rhbk_version: diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index 8ea545d..9d6aaaa 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -55,8 +55,7 @@ cache-stack=tcp # Proxy proxy={{ keycloak_quarkus_proxy_mode }} {% endif %} -# Do not attach route to cookies and rely on the session affinity capabilities from reverse proxy -#spi-sticky-session-encoder-infinispan-should-attach-route=false +spi-sticky-session-encoder-infinispan-should-attach-route={{ keycloak_quarkus_spi_sticky_session_encoder_infinispan_should_attach_route | d(true) | lower }} # Transaction transaction-xa-enabled={{ keycloak_quarkus_transaction_xa_enabled | lower }} From 4adab64dc0ca52e36e5963b013de330331d7aedc Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 22 Jan 2024 09:28:00 +0100 Subject: [PATCH 018/205] #158: support for TCPPING --- roles/keycloak_quarkus/README.md | 3 ++- roles/keycloak_quarkus/defaults/main.yml | 3 ++- roles/keycloak_quarkus/handlers/main.yml | 4 ++++ roles/keycloak_quarkus/meta/argument_specs.yml | 6 +++++- roles/keycloak_quarkus/tasks/main.yml | 16 ++++++++++++++++ roles/keycloak_quarkus/tasks/rebuild_config.yml | 7 +++++++ .../templates/keycloak.service.j2 | 2 +- 7 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 roles/keycloak_quarkus/tasks/rebuild_config.yml diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index cd720a5..a554254 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -19,6 +19,7 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| |`keycloak_quarkus_ha_enabled`| Enable auto configuration for database backend, clustering and remote caches on infinispan | `False` | +|`keycloak_quarkus_ha_discovery`| Discovery protocol for HA cluster members | `TCPPING` | |`keycloak_quarkus_db_enabled`| Enable auto configuration for database backend | `True` if `keycloak_quarkus_ha_enabled` is True, else `False` | |`keycloak_quarkus_admin_user`| Administration console user account | `admin` | |`keycloak_quarkus_bind_address`| Address for binding service ports | `0.0.0.0` | @@ -28,7 +29,7 @@ Role Defaults |`keycloak_quarkus_http_port`| HTTP listening port | `8080` | |`keycloak_quarkus_https_port`| TLS HTTP listening port | `8443` | |`keycloak_quarkus_ajp_port`| AJP port | `8009` | -|`keycloak_quarkus_jgroups_port`| jgroups cluster tcp port | `7600` | +|`keycloak_quarkus_jgroups_port`| jgroups cluster tcp port | `7800` | |`keycloak_quarkus_service_user`| Posix account username | `keycloak` | |`keycloak_quarkus_service_group`| Posix account group | `keycloak` | |`keycloak_quarkus_service_restart_always`| systemd restart always behavior activation | `False` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index da42960..07d83b7 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -37,7 +37,7 @@ keycloak_quarkus_http_enabled: true keycloak_quarkus_http_port: 8080 keycloak_quarkus_https_port: 8443 keycloak_quarkus_ajp_port: 8009 -keycloak_quarkus_jgroups_port: 7600 +keycloak_quarkus_jgroups_port: 7800 keycloak_quarkus_java_opts: "-Xms1024m -Xmx2048m" ### TLS/HTTPS configuration @@ -55,6 +55,7 @@ keycloak_quarkus_trust_store_password: '' ### Enable configuration for database backend, clustering and remote caches on infinispan keycloak_quarkus_ha_enabled: false +keycloak_quarkus_ha_discovery: "TCPPING" ### Enable database configuration, must be enabled when HA is configured keycloak_quarkus_db_enabled: "{{ True if keycloak_quarkus_ha_enabled else False }}" diff --git a/roles/keycloak_quarkus/handlers/main.yml b/roles/keycloak_quarkus/handlers/main.yml index 00cab00..6cbe276 100644 --- a/roles/keycloak_quarkus/handlers/main.yml +++ b/roles/keycloak_quarkus/handlers/main.yml @@ -1,4 +1,8 @@ --- +# handler should be invoked anytime a [build configuration](https://www.keycloak.org/server/all-config?f=build) changes +- name: "Rebuild {{ keycloak.service_name }} config" + ansible.builtin.include_tasks: rebuild_config.yml + listen: "rebuild keycloak config" - name: "Restart {{ keycloak.service_name }}" ansible.builtin.include_tasks: restart.yml listen: "restart keycloak" \ No newline at end of file diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 37c873e..1d371ed 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -168,7 +168,7 @@ argument_specs: type: "int" keycloak_quarkus_jgroups_port: # line 32 of defaults/main.yml - default: 7600 + default: 7800 description: "jgroups cluster tcp port" type: "int" keycloak_quarkus_java_opts: @@ -181,6 +181,10 @@ argument_specs: default: false description: "Enable auto configuration for database backend, clustering and remote caches on infinispan" type: "bool" + keycloak_quarkus_ha_discovery: + default: "TCPPING" + description: "Discovery protocol for HA cluster members" + type: "str" keycloak_quarkus_db_enabled: # line 38 of defaults/main.yml default: "{{ True if keycloak_quarkus_ha_enabled else False }}" diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index 394cf3b..c65ab59 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -30,6 +30,7 @@ mode: 0644 become: true notify: + - rebuild keycloak config - restart keycloak - name: "Configure quarkus config for keycloak service" @@ -43,6 +44,20 @@ notify: - restart keycloak +- name: Create tcpping cluster node list + ansible.builtin.set_fact: + keycloak_quarkus_cluster_nodes: > + {{ keycloak_quarkus_cluster_nodes | default([]) + [ + { + "name": item, + "address": 'jgroups-' + item, + "inventory_host": hostvars[item].ansible_default_ipv4.address | default(item) + '[' + (keycloak_quarkus_jgroups_port | string) + ']', + "value": hostvars[item].ansible_default_ipv4.address | default(item) + } + ] }} + loop: "{{ ansible_play_batch }}" + when: keycloak_quarkus_ha_enabled and keycloak_quarkus_ha_discovery == 'TCPPING' + - name: "Configure infinispan config for keycloak service" ansible.builtin.template: src: cache-ispn.xml @@ -52,6 +67,7 @@ mode: 0644 become: true notify: + - rebuild keycloak config - restart keycloak - name: Ensure logdirectory exists diff --git a/roles/keycloak_quarkus/tasks/rebuild_config.yml b/roles/keycloak_quarkus/tasks/rebuild_config.yml new file mode 100644 index 0000000..5a715c6 --- /dev/null +++ b/roles/keycloak_quarkus/tasks/rebuild_config.yml @@ -0,0 +1,7 @@ +--- +# cf. https://www.keycloak.org/server/configuration#_optimize_the_keycloak_startup +- name: "Rebuild {{ keycloak.service_name }} config" + ansible.builtin.shell: | + {{ keycloak.home }}/bin/kc.sh build + become: true + changed_when: true diff --git a/roles/keycloak_quarkus/templates/keycloak.service.j2 b/roles/keycloak_quarkus/templates/keycloak.service.j2 index a529c5b..5b90986 100644 --- a/roles/keycloak_quarkus/templates/keycloak.service.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.service.j2 @@ -10,7 +10,7 @@ PIDFile={{ keycloak_quarkus_service_pidfile }} {% if keycloak_quarkus_start_dev %} ExecStart={{ keycloak.home }}/bin/kc.sh start-dev {% else %} -ExecStart={{ keycloak.home }}/bin/kc.sh start --log={{ keycloak_quarkus_log }} +ExecStart={{ keycloak.home }}/bin/kc.sh start --optimized {% endif %} User={{ keycloak.service_user }} Group={{ keycloak.service_group }} From df81dc54971fbcab930431fe4312f10569bfd14b Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 22 Jan 2024 11:15:04 +0100 Subject: [PATCH 019/205] #158: move TCPPING config to ispn config file --- .../keycloak_quarkus/templates/cache-ispn.xml | 20 +++++++++++++++++-- .../templates/keycloak.conf.j2 | 4 +++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/roles/keycloak_quarkus/templates/cache-ispn.xml b/roles/keycloak_quarkus/templates/cache-ispn.xml index 20a1af7..67514d3 100644 --- a/roles/keycloak_quarkus/templates/cache-ispn.xml +++ b/roles/keycloak_quarkus/templates/cache-ispn.xml @@ -1,4 +1,4 @@ -# {{ ansible_managed }} + + + + +{% endif %} + - + diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index 8ea545d..81acce9 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -48,7 +48,9 @@ hostname-strict-backchannel={{ keycloak_quarkus_hostname_strict_backchannel | lo {% if keycloak_quarkus_ha_enabled %} cache=ispn cache-config-file=cache-ispn.xml -cache-stack=tcp +{% if keycloak_quarkus_ha_enabled and keycloak_quarkus_ha_discovery == 'TCPPING' %} +# cache-stack=tcp # configured directly in `cache-ispn.xml` +{% endif %} {% endif %} {% if keycloak_quarkus_proxy_mode is defined and keycloak_quarkus_proxy_mode != "none" %} From f7bef0a956dbb5fefa1dea2b27888e3d306c852e Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 22 Feb 2024 16:28:24 +0100 Subject: [PATCH 020/205] set enable-recovery when xa transactions are enabled --- roles/keycloak_quarkus/templates/quarkus.properties.j2 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/roles/keycloak_quarkus/templates/quarkus.properties.j2 b/roles/keycloak_quarkus/templates/quarkus.properties.j2 index f8502f2..7ef1db7 100644 --- a/roles/keycloak_quarkus/templates/quarkus.properties.j2 +++ b/roles/keycloak_quarkus/templates/quarkus.properties.j2 @@ -23,4 +23,7 @@ quarkus.infinispan-client.trust-store-type=jks {% endif %} quarkus.log.file.rotation.max-file-size={{ keycloak_quarkus_log_max_file_size }} quarkus.log.file.rotation.max-backup-index={{ keycloak_quarkus_log_max_backup_index }} -quarkus.log.file.rotation.file-suffix={{ keycloak_quarkus_log_file_suffix }} \ No newline at end of file +quarkus.log.file.rotation.file-suffix={{ keycloak_quarkus_log_file_suffix }} +{% if keycloak_quarkus_db_enabled %} +quarkus.transaction-manager.enable-recovery=true +{% endif %} From d4fb20b230797a53f54518dca78db5dec1c700d7 Mon Sep 17 00:00:00 2001 From: Footur <3769085+Footur@users.noreply.github.com> Date: Thu, 22 Feb 2024 17:10:22 +0100 Subject: [PATCH 021/205] Update Keycloak to version 23.0.7 --- roles/keycloak_quarkus/README.md | 4 ++-- roles/keycloak_quarkus/defaults/main.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 2dd7ca0..7c01eae 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -11,7 +11,7 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| -|`keycloak_quarkus_version`| keycloak.org package version | `23.0.1` | +|`keycloak_quarkus_version`| keycloak.org package version | `23.0.7` | * Service configuration @@ -92,7 +92,7 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:---------| |`keycloak_quarkus_offline_install` | Perform an offline install | `False`| -|`keycloak_quarkus_version`| keycloak.org package version | `23.0.1` | +|`keycloak_quarkus_version`| keycloak.org package version | `23.0.7` | |`keycloak_quarkus_dest`| Installation root path | `/opt/keycloak` | |`keycloak_quarkus_download_url` | Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}` | |`keycloak_quarkus_configure_firewalld` | Ensure firewalld is running and configure keycloak ports | `False` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 612dd65..f5cdb82 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -1,6 +1,6 @@ --- ### Configuration specific to keycloak -keycloak_quarkus_version: 23.0.1 +keycloak_quarkus_version: 23.0.7 keycloak_quarkus_archive: "keycloak-{{ keycloak_quarkus_version }}.zip" keycloak_quarkus_download_url: "https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}" keycloak_quarkus_installdir: "{{ keycloak_quarkus_dest }}/keycloak-{{ keycloak_quarkus_version }}" From b3ca517583488d8be5d1fa0f20009f3a71e039ce Mon Sep 17 00:00:00 2001 From: Romain Pelisse Date: Thu, 22 Feb 2024 11:14:54 +0100 Subject: [PATCH 022/205] molecule: adapt sudo setup to work when ansible is not connecting as root on the target --- molecule/default/prepare.yml | 4 +++- molecule/prepare.yml | 22 ++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml index 437f3e2..43e4e54 100644 --- a/molecule/default/prepare.yml +++ b/molecule/default/prepare.yml @@ -5,12 +5,14 @@ - name: Install sudo ansible.builtin.yum: name: - - sudo - java-1.8.0-openjdk state: present - name: Prepare hosts: all + gather_facts: yes + vars: + sudo_pkg_name: sudo tasks: - name: "Run preparation common to all scenario" ansible.builtin.include_tasks: ../prepare.yml diff --git a/molecule/prepare.yml b/molecule/prepare.yml index a927ba0..d01d6fd 100644 --- a/molecule/prepare.yml +++ b/molecule/prepare.yml @@ -3,9 +3,27 @@ ansible.builtin.debug: msg: "Ansible version is {{ ansible_version.full }}" -- name: Install sudo + +- name: "Ensure {{ sudo_pkg_name }} is installed (if user is root)." ansible.builtin.yum: - name: + name: "{{ sudo_pkg_name }}" + when: + - ansible_user_id == 'root' + + +- name: Gather the package facts + ansible.builtin.package_facts: + manager: auto + +- name: "Check if {{ sudo_pkg_name }} is installed." + ansible.builtin.assert: + that: + - sudo_pkg_name in ansible_facts.packages + +- name: Install sudo + become: yes + ansible.builtin.yum: + name: - sudo - iproute state: present From 7324f48e8dea2b7fba0feac3381c81351f2cafc6 Mon Sep 17 00:00:00 2001 From: Romain Pelisse Date: Thu, 22 Feb 2024 11:22:32 +0100 Subject: [PATCH 023/205] molecule: cleanup prepare to use one play --- molecule/default/prepare.yml | 18 +++++----- molecule/default/verify.yml | 59 +++++++++++++++++--------------- molecule/overridexml/prepare.yml | 3 ++ 3 files changed, 43 insertions(+), 37 deletions(-) diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml index 43e4e54..da1ab18 100644 --- a/molecule/default/prepare.yml +++ b/molecule/default/prepare.yml @@ -1,13 +1,4 @@ --- -- name: Prepare - hosts: all - tasks: - - name: Install sudo - ansible.builtin.yum: - name: - - java-1.8.0-openjdk - state: present - - name: Prepare hosts: all gather_facts: yes @@ -20,3 +11,12 @@ assets: - "{{ assets_server }}/sso/7.6.0/rh-sso-7.6.0-server-dist.zip" - "{{ assets_server }}/sso/7.6.1/rh-sso-7.6.1-patch.zip" + + - name: Install JDK8 + become: yes + ansible.builtin.yum: + name: + - java-1.8.0-openjdk + state: present + + diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index ba0e01f..39e94c5 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -56,31 +56,34 @@ ansible.builtin.assert: that: - (keycloak_query_clients.json | selectattr('clientId','equalto','TestClient') | first)["attributes"]["post.logout.redirect.uris"] == '/public/logout' - - name: Check log folder - ansible.builtin.stat: - path: "/tmp/keycloak" - register: keycloak_log_folder - - name: Check that keycloak log folder exists and is a link - ansible.builtin.assert: - that: - - keycloak_log_folder.stat.exists - - not keycloak_log_folder.stat.isdir - - keycloak_log_folder.stat.islnk - - name: Check log file - ansible.builtin.stat: - path: "/tmp/keycloak/server.log" - register: keycloak_log_file - - name: Check if keycloak file exists - ansible.builtin.assert: - that: - - keycloak_log_file.stat.exists - - not keycloak_log_file.stat.isdir - - name: Check default log folder - ansible.builtin.stat: - path: "/var/log/keycloak" - register: keycloak_default_log_folder - failed_when: false - - name: Check that default keycloak log folder doesn't exist - ansible.builtin.assert: - that: - - not keycloak_default_log_folder.stat.exists + - name: "Privilege escalation as some files/folders may requires it" + become: yes + block: + - name: Check log folder + ansible.builtin.stat: + path: "/tmp/keycloak" + register: keycloak_log_folder + - name: Check that keycloak log folder exists and is a link + ansible.builtin.assert: + that: + - keycloak_log_folder.stat.exists + - not keycloak_log_folder.stat.isdir + - keycloak_log_folder.stat.islnk + - name: Check log file + ansible.builtin.stat: + path: "/tmp/keycloak/server.log" + register: keycloak_log_file + - name: Check if keycloak file exists + ansible.builtin.assert: + that: + - keycloak_log_file.stat.exists + - not keycloak_log_file.stat.isdir + - name: Check default log folder + ansible.builtin.stat: + path: "/var/log/keycloak" + register: keycloak_default_log_folder + failed_when: false + - name: Check that default keycloak log folder doesn't exist + ansible.builtin.assert: + that: + - not keycloak_default_log_folder.stat.exists diff --git a/molecule/overridexml/prepare.yml b/molecule/overridexml/prepare.yml index f9b2406..26245be 100644 --- a/molecule/overridexml/prepare.yml +++ b/molecule/overridexml/prepare.yml @@ -1,6 +1,9 @@ --- - name: Prepare hosts: all + gather_facts: yes + vars: + sudo_pkg_name: sudo tasks: - name: "Run preparation common to all scenario" ansible.builtin.include_tasks: ../prepare.yml From 5bd39a0d0eb6a21151b81d549c658a7953c97154 Mon Sep 17 00:00:00 2001 From: Romain Pelisse Date: Thu, 22 Feb 2024 12:17:32 +0100 Subject: [PATCH 024/205] molecule: use block to skip assets download entirely if needed --- molecule/prepare.yml | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/molecule/prepare.yml b/molecule/prepare.yml index d01d6fd..9d39694 100644 --- a/molecule/prepare.yml +++ b/molecule/prepare.yml @@ -32,22 +32,21 @@ ansible.builtin.set_fact: assets_server: "{{ lookup('env','MIDDLEWARE_DOWNLOAD_RELEASE_SERVER_URL') }}" -- name: "Set offline when assets server from env is defined" - ansible.builtin.set_fact: - sso_offline_install: True +- name: "Download artefacts only if assets_server is set" when: - assets_server is defined - assets_server | length > 0 + block: + - name: "Set offline when assets server from env is defined" + ansible.builtin.set_fact: + sso_offline_install: True -- name: "Download and deploy zips from {{ assets_server }}" - ansible.builtin.get_url: - url: "{{ asset }}" - dest: "{{ lookup('env', 'PWD') }}" - validate_certs: no - delegate_to: localhost - loop: "{{ assets }}" - loop_control: - loop_var: asset - when: - - assets_server is defined - - assets_server | length > 0 + - name: "Download and deploy zips from {{ assets_server }}" + ansible.builtin.get_url: + url: "{{ asset }}" + dest: "{{ lookup('env', 'PWD') }}" + validate_certs: no + delegate_to: localhost + loop: "{{ assets }}" + loop_control: + loop_var: asset From 167bf512c5ce2c01dcef0a04a94c7f483eb7671a Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 27 Feb 2024 17:17:14 +0100 Subject: [PATCH 025/205] fix typo in variable name --- roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 index b028085..a665ec8 100644 --- a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 +++ b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 @@ -1,6 +1,6 @@ # {{ ansible_managed }} KEYCLOAK_ADMIN={{ keycloak_quarkus_admin_user }} KEYCLOAK_ADMIN_PASSWORD='{{ keycloak_quarkus_admin_pass }}' -PATH={{ keycloak_java_home | default(keycloak_rpm_java_home, true) }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -JAVA_HOME={{ keycloak_java_home | default(keycloak_rpm_java_home, true) }} -JAVA_OPTS_APPEND={{ keycloak_quarkus_java_opts }} \ No newline at end of file +PATH={{ keycloak_quarkus_java_home | default(keycloak_rpm_java_home, true) }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +JAVA_HOME={{ keycloak_quarkus_java_home | default(keycloak_rpm_java_home, true) }} +JAVA_OPTS_APPEND={{ keycloak_quarkus_java_opts }} From 7f021a849efc7932960aa7f944bcd2c528c5305c Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 27 Feb 2024 17:17:24 +0100 Subject: [PATCH 026/205] Linter --- molecule/https_revproxy/prepare.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/molecule/https_revproxy/prepare.yml b/molecule/https_revproxy/prepare.yml index a641257..44018be 100644 --- a/molecule/https_revproxy/prepare.yml +++ b/molecule/https_revproxy/prepare.yml @@ -33,6 +33,7 @@ ansible.builtin.file: path: /etc/nginx/tls state: directory + mode: 0755 - name: Copy certificates ansible.builtin.copy: src: "{{ item.name }}" From d97ddbde3c3a67d790469c67116a4b141a9b71b9 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 27 Feb 2024 19:27:07 +0100 Subject: [PATCH 027/205] add test --- molecule/quarkus-devmode/converge.yml | 1 + molecule/quarkus-devmode/prepare.yml | 11 ++++++++++- molecule/quarkus-devmode/verify.yml | 8 ++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/molecule/quarkus-devmode/converge.yml b/molecule/quarkus-devmode/converge.yml index 6cbe7d8..2a45189 100644 --- a/molecule/quarkus-devmode/converge.yml +++ b/molecule/quarkus-devmode/converge.yml @@ -9,6 +9,7 @@ keycloak_quarkus_frontend_url: 'http://localhost:8080/' keycloak_quarkus_start_dev: True keycloak_quarkus_proxy_mode: none + keycloak_quarkus_java_home: /opt/openjdk/ roles: - role: keycloak_quarkus - role: keycloak_realm diff --git a/molecule/quarkus-devmode/prepare.yml b/molecule/quarkus-devmode/prepare.yml index 09cbda3..88c2fb3 100644 --- a/molecule/quarkus-devmode/prepare.yml +++ b/molecule/quarkus-devmode/prepare.yml @@ -4,9 +4,18 @@ tasks: - name: Install sudo ansible.builtin.yum: - name: sudo + name: + - sudo + - java-17-openjdk-headless state: present + - name: Link default logs directory + ansible.builtin.file: + state: link + src: /usr/lib/jvm/jre-17-openjdk + dest: /opt/openjdk + force: true + - name: "Display hera_home if defined." ansible.builtin.set_fact: hera_home: "{{ lookup('env', 'HERA_HOME') }}" diff --git a/molecule/quarkus-devmode/verify.yml b/molecule/quarkus-devmode/verify.yml index ebb6047..b808ece 100644 --- a/molecule/quarkus-devmode/verify.yml +++ b/molecule/quarkus-devmode/verify.yml @@ -11,6 +11,14 @@ - ansible_facts.services["keycloak.service"]["state"] == "running" - ansible_facts.services["keycloak.service"]["status"] == "enabled" + - name: Verify we are running on requested JAVA_HOME # noqa blocked_modules command-instead-of-module + ansible.builtin.shell: | + set -o pipefail + ps -ef | grep '/opt/openjdk' | grep -v grep + args: + executable: /bin/bash + changed_when: False + - name: Set internal envvar ansible.builtin.set_fact: hera_home: "{{ lookup('env', 'HERA_HOME') }}" From 1e1665adb05d313ccc4f6218650515daf61a8095 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Wed, 28 Feb 2024 15:58:33 +0000 Subject: [PATCH 028/205] Update changelog for release 2.1.0 Signed-off-by: ansible-middleware-core --- CHANGELOG.rst | 33 ++++++++++++++++++++++++++++----- changelogs/changelog.yaml | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c3a46da..15c2fbf 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,11 +1,36 @@ -============================================ -middleware_automation.keycloak Release Notes -============================================ +============================================= +middleware\_automation.keycloak Release Notes +============================================= .. contents:: Topics This changelog describes changes after version 0.2.6. +v2.1.0 +====== + +Major Changes +------------- + +- Implement infinispan TCPPING discovery protocol `#159 `_ + +Minor Changes +------------- + +- Set enable-recovery when xa transactions are enabled `#167 `_ +- keycloak_quarkus: Allow configuring log rotate options in quarkus configuration `#161 `_ +- keycloak_quarkus: ``sticky-session`` for infinispan routes `#163 `_ + +Breaking Changes / Porting Guide +-------------------------------- + +- keycloak_quarkus: renamed infinispan host list configuration `#157 `_ + +Bugfixes +-------- + +- keycloak_quarkus: fix custom JAVA_HOME parameter name `#171 `_ + v2.0.2 ====== @@ -269,7 +294,6 @@ Release Summary Minor enhancements, bug and documentation fixes. - Major Changes ------------- @@ -287,4 +311,3 @@ Release Summary --------------- This is the first stable release of the ``middleware_automation.keycloak`` collection. - diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 7d684cd..dd44253 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -386,3 +386,36 @@ releases: - 152.yaml - 154.yaml release_date: '2024-01-17' + 2.1.0: + changes: + breaking_changes: + - 'keycloak_quarkus: renamed infinispan host list configuration `#157 `_ + + ' + bugfixes: + - 'keycloak_quarkus: fix custom JAVA_HOME parameter name `#171 `_ + + ' + major_changes: + - 'Implement infinispan TCPPING discovery protocol `#159 `_ + + ' + minor_changes: + - 'Set enable-recovery when xa transactions are enabled `#167 `_ + + ' + - 'keycloak_quarkus: Allow configuring log rotate options in quarkus configuration + `#161 `_ + + ' + - 'keycloak_quarkus: ``sticky-session`` for infinispan routes `#163 `_ + + ' + fragments: + - 157.yaml + - 159.yaml + - 161.yaml + - 163.yaml + - 167.yaml + - 171.yaml + release_date: '2024-02-28' From 6541b5e386796777f33eba4b8cce007ec4662175 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Wed, 28 Feb 2024 15:58:47 +0000 Subject: [PATCH 029/205] Bump version to 2.1.1 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index 6a1d110..dd55345 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.1.0" +version: "2.1.1" readme: README.md authors: - Romain Pelisse From d74820190f5231a0e33fcb31af9acb2e61618e8a Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 28 Feb 2024 17:10:02 +0100 Subject: [PATCH 030/205] ci: rename keycloak_quarkus infinispan jinja2 template --- roles/keycloak_quarkus/tasks/main.yml | 2 +- .../templates/{cache-ispn.xml => cache-ispn.xml.j2} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename roles/keycloak_quarkus/templates/{cache-ispn.xml => cache-ispn.xml.j2} (100%) diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index c65ab59..4e55961 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -60,7 +60,7 @@ - name: "Configure infinispan config for keycloak service" ansible.builtin.template: - src: cache-ispn.xml + src: cache-ispn.xml.j2 dest: "{{ keycloak.home }}/conf/cache-ispn.xml" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" diff --git a/roles/keycloak_quarkus/templates/cache-ispn.xml b/roles/keycloak_quarkus/templates/cache-ispn.xml.j2 similarity index 100% rename from roles/keycloak_quarkus/templates/cache-ispn.xml rename to roles/keycloak_quarkus/templates/cache-ispn.xml.j2 From a59a1fb8dd16ca33a7c87418f158faf9fc4cef7f Mon Sep 17 00:00:00 2001 From: Romain Pelisse Date: Mon, 4 Mar 2024 21:13:06 +0100 Subject: [PATCH 031/205] Rework Molecule prepare phase to install sudo only if root on target --- molecule/prepare.yml | 13 +++++++++---- molecule/quarkus-devmode/prepare.yml | 12 ++++++------ molecule/quarkus/prepare.yml | 12 ++++-------- molecule/quarkus/verify.yml | 4 +++- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/molecule/prepare.yml b/molecule/prepare.yml index 9d39694..f122f9d 100644 --- a/molecule/prepare.yml +++ b/molecule/prepare.yml @@ -3,28 +3,31 @@ ansible.builtin.debug: msg: "Ansible version is {{ ansible_version.full }}" +- name: "Set package name for sudo" + ansible.builtin.set_fact: + sudo_pkg_name: sudo - name: "Ensure {{ sudo_pkg_name }} is installed (if user is root)." ansible.builtin.yum: name: "{{ sudo_pkg_name }}" + state: present when: - ansible_user_id == 'root' - - name: Gather the package facts ansible.builtin.package_facts: manager: auto -- name: "Check if {{ sudo_pkg_name }} is installed." +- name: "Check if sudo is installed." ansible.builtin.assert: that: - sudo_pkg_name in ansible_facts.packages + fail_msg: "sudo is not installed on target system" -- name: Install sudo +- name: "Install iproute" become: yes ansible.builtin.yum: name: - - sudo - iproute state: present @@ -36,6 +39,8 @@ when: - assets_server is defined - assets_server | length > 0 + - assets is defined + - assets | length > 0 block: - name: "Set offline when assets server from env is defined" ansible.builtin.set_fact: diff --git a/molecule/quarkus-devmode/prepare.yml b/molecule/quarkus-devmode/prepare.yml index 88c2fb3..313adb8 100644 --- a/molecule/quarkus-devmode/prepare.yml +++ b/molecule/quarkus-devmode/prepare.yml @@ -2,20 +2,20 @@ - name: Prepare hosts: all tasks: - - name: Install sudo + - name: "Ensure common prepare phase are set." + ansible.builtin.include_tasks: ../prepare.yml + + - name: Install JDK17 + become: yes ansible.builtin.yum: name: - - sudo - java-17-openjdk-headless state: present - name: Link default logs directory + become: yes ansible.builtin.file: state: link src: /usr/lib/jvm/jre-17-openjdk dest: /opt/openjdk force: true - - - name: "Display hera_home if defined." - ansible.builtin.set_fact: - hera_home: "{{ lookup('env', 'HERA_HOME') }}" diff --git a/molecule/quarkus/prepare.yml b/molecule/quarkus/prepare.yml index 13d85a8..c7ba481 100644 --- a/molecule/quarkus/prepare.yml +++ b/molecule/quarkus/prepare.yml @@ -2,14 +2,8 @@ - name: Prepare hosts: all tasks: - - name: Install sudo - ansible.builtin.yum: - name: sudo - state: present - - - name: "Display hera_home if defined." - ansible.builtin.set_fact: - hera_home: "{{ lookup('env', 'HERA_HOME') }}" + - name: "Ensure common prepare phase are set." + ansible.builtin.include_tasks: ../prepare.yml - name: Create certificate request ansible.builtin.command: openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes -subj '/CN=instance' @@ -17,12 +11,14 @@ changed_when: False - name: Create conf directory # risky-file-permissions in test user account does not exist yet + become: yes ansible.builtin.file: state: directory path: "/opt/keycloak/certs/" mode: 0755 - name: Copy certificates + become: yes ansible.builtin.copy: src: "{{ item }}" dest: "/opt/keycloak/certs/{{ item }}" diff --git a/molecule/quarkus/verify.yml b/molecule/quarkus/verify.yml index 2d75c32..a58a13f 100644 --- a/molecule/quarkus/verify.yml +++ b/molecule/quarkus/verify.yml @@ -49,8 +49,9 @@ - keycloak_log_folder.stat.exists - not keycloak_log_folder.stat.isdir - keycloak_log_folder.stat.islnk - + - name: Check log file + become: yes ansible.builtin.stat: path: "/tmp/keycloak/keycloak.log" register: keycloak_log_file @@ -62,6 +63,7 @@ - not keycloak_log_file.stat.isdir - name: Check default log folder + become: yes ansible.builtin.stat: path: "/var/log/keycloak" register: keycloak_default_log_folder From a97c349f41c8429886b41c7f609d0f96ccce8861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gro=C3=9Fewinkelmann?= Date: Wed, 13 Mar 2024 00:12:15 +0100 Subject: [PATCH 032/205] Utilize comment filter for {{ ansible_maanged }} annotations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Björn Großewinkelmann --- molecule/overridexml/templates/custom.xml.j2 | 2 +- roles/keycloak/templates/15.0.8/standalone-infinispan.xml.j2 | 2 +- roles/keycloak/templates/15.0.8/standalone.xml.j2 | 2 +- roles/keycloak/templates/keycloak-service.sh.j2 | 2 +- roles/keycloak/templates/keycloak-sysconfig.j2 | 2 +- roles/keycloak/templates/keycloak.service.j2 | 2 +- roles/keycloak/templates/standalone-ha.xml.j2 | 2 +- roles/keycloak/templates/standalone-infinispan.xml.j2 | 2 +- roles/keycloak/templates/standalone.xml.j2 | 2 +- roles/keycloak_quarkus/templates/cache-ispn.xml.j2 | 2 +- roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 | 2 +- roles/keycloak_quarkus/templates/keycloak.conf.j2 | 2 +- roles/keycloak_quarkus/templates/keycloak.service.j2 | 2 +- roles/keycloak_quarkus/templates/quarkus.properties.j2 | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/molecule/overridexml/templates/custom.xml.j2 b/molecule/overridexml/templates/custom.xml.j2 index 8686d77..66c5852 100644 --- a/molecule/overridexml/templates/custom.xml.j2 +++ b/molecule/overridexml/templates/custom.xml.j2 @@ -1,5 +1,5 @@ - +{{ ansible_managed | comment('xml') }} diff --git a/roles/keycloak/templates/15.0.8/standalone-infinispan.xml.j2 b/roles/keycloak/templates/15.0.8/standalone-infinispan.xml.j2 index 2d84f3f..25d6cb0 100644 --- a/roles/keycloak/templates/15.0.8/standalone-infinispan.xml.j2 +++ b/roles/keycloak/templates/15.0.8/standalone-infinispan.xml.j2 @@ -1,5 +1,5 @@ - +{{ ansible_managed | comment('xml') }} diff --git a/roles/keycloak/templates/15.0.8/standalone.xml.j2 b/roles/keycloak/templates/15.0.8/standalone.xml.j2 index de175f2..01c317b 100644 --- a/roles/keycloak/templates/15.0.8/standalone.xml.j2 +++ b/roles/keycloak/templates/15.0.8/standalone.xml.j2 @@ -1,5 +1,5 @@ - +{{ ansible_managed | comment('xml') }} diff --git a/roles/keycloak/templates/keycloak-service.sh.j2 b/roles/keycloak/templates/keycloak-service.sh.j2 index 577959e..98efb34 100755 --- a/roles/keycloak/templates/keycloak-service.sh.j2 +++ b/roles/keycloak/templates/keycloak-service.sh.j2 @@ -1,5 +1,5 @@ #!/bin/bash -eu -# {{ ansible_managed }} +{{ ansible_managed | comment }} set +u -o pipefail diff --git a/roles/keycloak/templates/keycloak-sysconfig.j2 b/roles/keycloak/templates/keycloak-sysconfig.j2 index 86a96d6..4c38522 100644 --- a/roles/keycloak/templates/keycloak-sysconfig.j2 +++ b/roles/keycloak/templates/keycloak-sysconfig.j2 @@ -1,4 +1,4 @@ -# {{ ansible_managed }} +{{ ansible_managed | comment }} JAVA_OPTS='{{ keycloak_java_opts }}' JAVA_HOME={{ keycloak_java_home | default(keycloak_rpm_java_home, true) }} JBOSS_HOME={{ keycloak.home }} diff --git a/roles/keycloak/templates/keycloak.service.j2 b/roles/keycloak/templates/keycloak.service.j2 index 15a6ddf..eea3ba1 100644 --- a/roles/keycloak/templates/keycloak.service.j2 +++ b/roles/keycloak/templates/keycloak.service.j2 @@ -1,4 +1,4 @@ -# {{ ansible_managed }} +{{ ansible_managed | comment }} [Unit] Description={{ keycloak.service_name }} Server After=network.target diff --git a/roles/keycloak/templates/standalone-ha.xml.j2 b/roles/keycloak/templates/standalone-ha.xml.j2 index 99399f3..d027c35 100644 --- a/roles/keycloak/templates/standalone-ha.xml.j2 +++ b/roles/keycloak/templates/standalone-ha.xml.j2 @@ -1,5 +1,5 @@ - +{{ ansible_managed | comment('xml') }} diff --git a/roles/keycloak/templates/standalone-infinispan.xml.j2 b/roles/keycloak/templates/standalone-infinispan.xml.j2 index 0b0c8af..18e5a7c 100644 --- a/roles/keycloak/templates/standalone-infinispan.xml.j2 +++ b/roles/keycloak/templates/standalone-infinispan.xml.j2 @@ -1,5 +1,5 @@ - +{{ ansible_managed | comment('xml') }} diff --git a/roles/keycloak/templates/standalone.xml.j2 b/roles/keycloak/templates/standalone.xml.j2 index 72fe4d6..5ee20ed 100644 --- a/roles/keycloak/templates/standalone.xml.j2 +++ b/roles/keycloak/templates/standalone.xml.j2 @@ -1,5 +1,5 @@ - +{{ ansible_managed | comment('xml') }} diff --git a/roles/keycloak_quarkus/templates/cache-ispn.xml.j2 b/roles/keycloak_quarkus/templates/cache-ispn.xml.j2 index 67514d3..fb11cda 100644 --- a/roles/keycloak_quarkus/templates/cache-ispn.xml.j2 +++ b/roles/keycloak_quarkus/templates/cache-ispn.xml.j2 @@ -1,4 +1,4 @@ - +{{ ansible_managed | comment('xml') }} @@ -481,7 +481,7 @@ default - + @@ -520,7 +520,8 @@ - + + @@ -549,7 +550,9 @@ + + diff --git a/molecule/overridexml/verify.yml b/molecule/overridexml/verify.yml index ef973cd..b267fa1 100644 --- a/molecule/overridexml/verify.yml +++ b/molecule/overridexml/verify.yml @@ -1,6 +1,10 @@ --- - name: Verify hosts: all + vars: + keycloak_uri: "http://localhost:8081" + keycloak_management_port: "http://localhost:19990" + keycloak_admin_password: "remembertochangeme" tasks: - name: Populate service facts ansible.builtin.service_facts: @@ -9,3 +13,20 @@ that: - ansible_facts.services["keycloak.service"]["state"] == "running" - ansible_facts.services["keycloak.service"]["status"] == "enabled" + - name: Verify we are running on requested jvm # noqa blocked_modules command-instead-of-module + ansible.builtin.shell: | + set -o pipefail + ps -ef | grep '/etc/alternatives/jre_1.8.0/' | grep -v grep + args: + executable: /bin/bash + changed_when: no + - name: Verify token api call + ansible.builtin.uri: + url: "{{ keycloak_uri }}/auth/realms/master/protocol/openid-connect/token" + method: POST + body: "client_id=admin-cli&username=admin&password={{ keycloak_admin_password }}&grant_type=password" + validate_certs: no + register: keycloak_auth_response + until: keycloak_auth_response.status == 200 + retries: 2 + delay: 2 From b9d9874a00f522709b289ed26b5f8f13d14d07ae Mon Sep 17 00:00:00 2001 From: Malik Kennedy Date: Sat, 16 Mar 2024 18:17:20 +0000 Subject: [PATCH 037/205] feat: ubuntu compatibility --- bindep.txt | 11 ++++---- molecule/default/prepare.yml | 9 ++++++- molecule/quarkus-devmode/prepare.yml | 24 +++++++++++++++++ molecule/quarkus/prepare.yml | 2 +- roles/keycloak/README.md | 1 + roles/keycloak/defaults/main.yml | 4 ++- roles/keycloak/meta/argument_specs.yml | 5 ++++ roles/keycloak/tasks/debian.yml | 6 +++++ roles/keycloak/tasks/fastpackages.yml | 15 ++++++++++- roles/keycloak/tasks/iptables.yml | 23 ++++++++++++++++ roles/keycloak/tasks/main.yml | 15 ++++++++--- roles/keycloak/tasks/prereqs.yml | 6 ++--- roles/keycloak/tasks/redhat.yml | 6 +++++ roles/keycloak/tasks/systemd.yml | 25 +++++++++++++++++ roles/keycloak_quarkus/defaults/main.yml | 2 +- roles/keycloak_quarkus/tasks/debian.yml | 6 +++++ roles/keycloak_quarkus/tasks/fastpackages.yml | 15 ++++++++++- roles/keycloak_quarkus/tasks/iptables.yml | 20 ++++++++++++++ roles/keycloak_quarkus/tasks/main.yml | 14 +++++++--- roles/keycloak_quarkus/tasks/prereqs.yml | 6 ++--- roles/keycloak_quarkus/tasks/redhat.yml | 6 +++++ roles/keycloak_quarkus/tasks/systemd.yml | 27 ++++++++++++++++++- 22 files changed, 222 insertions(+), 26 deletions(-) create mode 100644 roles/keycloak/tasks/debian.yml create mode 100644 roles/keycloak/tasks/iptables.yml create mode 100644 roles/keycloak/tasks/redhat.yml create mode 100644 roles/keycloak_quarkus/tasks/debian.yml create mode 100644 roles/keycloak_quarkus/tasks/iptables.yml create mode 100644 roles/keycloak_quarkus/tasks/redhat.yml diff --git a/bindep.txt b/bindep.txt index 840876b..0014f47 100644 --- a/bindep.txt +++ b/bindep.txt @@ -1,8 +1,9 @@ +python3-dev [compile platform:dpkg] python3-devel [compile platform:rpm] python39-devel [compile platform:centos-8 platform:rhel-8] -git-lfs [platform:rpm] -python3-netaddr [platform:rpm] -python3-lxml [platform:rpm] -python3-jmespath [platform:rpm] -python3-requests [platform:rpm] +git-lfs [platform:rpm platform:dpkg] +python3-netaddr [platform:rpm platform:dpkg] +python3-lxml [platform:rpm platform:dpkg] +python3-jmespath [platform:rpm platform:dpkg] +python3-requests [platform:rpm platform:dpkg] diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml index da1ab18..b707f6c 100644 --- a/molecule/default/prepare.yml +++ b/molecule/default/prepare.yml @@ -18,5 +18,12 @@ name: - java-1.8.0-openjdk state: present + when: ansible_facts['os_family'] == "RedHat" - + - name: Install JDK8 + become: yes + ansible.builtin.apt: + name: + - openjdk-8-jdk + state: present + when: ansible_facts['os_family'] == "Debian" diff --git a/molecule/quarkus-devmode/prepare.yml b/molecule/quarkus-devmode/prepare.yml index 88c2fb3..924aebc 100644 --- a/molecule/quarkus-devmode/prepare.yml +++ b/molecule/quarkus-devmode/prepare.yml @@ -2,19 +2,43 @@ - name: Prepare hosts: all tasks: + - name: Install sudo + ansible.builtin.apt: + name: + - sudo + - openjdk-17-jdk-headless + state: present + when: + - ansible_facts.os_family == 'Debian' + - name: Install sudo ansible.builtin.yum: name: - sudo - java-17-openjdk-headless state: present + when: + - ansible_facts.os_family == 'RedHat' + - name: Link default logs directory + ansible.builtin.file: + state: link + src: "{{ item }}" + dest: /opt/openjdk + force: true + with_fileglob: + - /usr/lib/jvm/java-17-openjdk* + when: + - ansible_facts.os_family == "Debian" + - name: Link default logs directory ansible.builtin.file: state: link src: /usr/lib/jvm/jre-17-openjdk dest: /opt/openjdk force: true + when: + - ansible_facts.os_family == "RedHat" - name: "Display hera_home if defined." ansible.builtin.set_fact: diff --git a/molecule/quarkus/prepare.yml b/molecule/quarkus/prepare.yml index 13d85a8..568bfef 100644 --- a/molecule/quarkus/prepare.yml +++ b/molecule/quarkus/prepare.yml @@ -3,7 +3,7 @@ hosts: all tasks: - name: Install sudo - ansible.builtin.yum: + ansible.builtin.package: name: sudo state: present diff --git a/roles/keycloak/README.md b/roles/keycloak/README.md index c4dfedc..3d3b560 100644 --- a/roles/keycloak/README.md +++ b/roles/keycloak/README.md @@ -10,6 +10,7 @@ Requirements This role requires the `python3-netaddr` library installed on the controller node. * to install via yum/dnf: `dnf install python3-netaddr` +* to install via apt: `apt install python3-netaddr` * or via pip: `pip install netaddr==0.8.0` * or via the collection: `pip install -r requirements.txt` diff --git a/roles/keycloak/defaults/main.yml b/roles/keycloak/defaults/main.yml index 7ffaec6..6658774 100644 --- a/roles/keycloak/defaults/main.yml +++ b/roles/keycloak/defaults/main.yml @@ -8,7 +8,8 @@ keycloak_installdir: "{{ keycloak_dest }}/keycloak-{{ keycloak_version }}" keycloak_offline_install: false ### Install location and service settings -keycloak_jvm_package: java-1.8.0-openjdk-headless +keycloak_jvm_package: "{{ 'java-1.8.0-openjdk-headless' if ansible_facts.os_family == 'RedHat' else 'openjdk-8-jdk-headless' }}" + keycloak_java_home: keycloak_dest: /opt/keycloak keycloak_jboss_home: "{{ keycloak_installdir }}" @@ -33,6 +34,7 @@ keycloak_service_startlimitburst: "5" keycloak_service_restartsec: "10s" keycloak_configure_firewalld: false +keycloak_configure_iptables: false ### administrator console password keycloak_admin_password: '' diff --git a/roles/keycloak/meta/argument_specs.yml b/roles/keycloak/meta/argument_specs.yml index acdb309..ca1cb8b 100644 --- a/roles/keycloak/meta/argument_specs.yml +++ b/roles/keycloak/meta/argument_specs.yml @@ -11,6 +11,11 @@ argument_specs: default: "keycloak-legacy-{{ keycloak_version }}.zip" description: "keycloak install archive filename" type: "str" + keycloak_configure_iptables: + # line 33 of keycloak/defaults/main.yml + default: false + description: "Ensure iptables is running and configure keycloak ports" + type: "bool" keycloak_configure_firewalld: # line 33 of keycloak/defaults/main.yml default: false diff --git a/roles/keycloak/tasks/debian.yml b/roles/keycloak/tasks/debian.yml new file mode 100644 index 0000000..ffb1348 --- /dev/null +++ b/roles/keycloak/tasks/debian.yml @@ -0,0 +1,6 @@ +--- +- name: Include firewall config tasks + ansible.builtin.include_tasks: iptables.yml + when: keycloak_configure_iptables + tags: + - firewall diff --git a/roles/keycloak/tasks/fastpackages.yml b/roles/keycloak/tasks/fastpackages.yml index c9085f8..3b557ef 100644 --- a/roles/keycloak/tasks/fastpackages.yml +++ b/roles/keycloak/tasks/fastpackages.yml @@ -4,14 +4,27 @@ register: rpm_info changed_when: false failed_when: false + when: ansible_facts.os_family == "RedHat" - name: "Add missing packages to the yum install list" ansible.builtin.set_fact: packages_to_install: "{{ packages_to_install | default([]) + rpm_info.stdout_lines | map('regex_findall', 'package (.+) is not installed$') | default([]) | flatten }}" + when: ansible_facts.os_family == "RedHat" - name: "Install packages: {{ packages_to_install }}" become: true ansible.builtin.yum: name: "{{ packages_to_install }}" state: present - when: packages_to_install | default([]) | length > 0 + when: + - packages_to_install | default([]) | length > 0 + - ansible_facts.os_family == "RedHat" + +- name: "Install packages: {{ packages_list }}" + become: true + ansible.builtin.package: + name: "{{ packages_list }}" + state: present + when: + - packages_list | default([]) | length > 0 + - ansible_facts.os_family == "Debian" diff --git a/roles/keycloak/tasks/iptables.yml b/roles/keycloak/tasks/iptables.yml new file mode 100644 index 0000000..8ebc16e --- /dev/null +++ b/roles/keycloak/tasks/iptables.yml @@ -0,0 +1,23 @@ +--- +- name: Ensure required package iptables are installed + ansible.builtin.include_tasks: fastpackages.yml + vars: + packages_list: + - iptables + +- name: "Configure firewall ports for {{ keycloak.service_name }}" + become: true + ansible.builtin.iptables: + destination_port: "{{ item }}" + action: "insert" + rule_num: 6 # magic number I forget why + chain: "INPUT" + policy: "ACCEPT" + protocol: tcp + loop: + - "{{ keycloak_http_port }}" + - "{{ keycloak_https_port }}" + - "{{ keycloak_management_http_port }}" + - "{{ keycloak_management_https_port }}" + - "{{ keycloak_jgroups_port }}" + - "{{ keycloak_ajp_port }}" diff --git a/roles/keycloak/tasks/main.yml b/roles/keycloak/tasks/main.yml index cba503b..284900b 100644 --- a/roles/keycloak/tasks/main.yml +++ b/roles/keycloak/tasks/main.yml @@ -5,11 +5,17 @@ tags: - prereqs -- name: Include firewall config tasks - ansible.builtin.include_tasks: firewalld.yml - when: keycloak_configure_firewalld +- name: Debian specific tasks + ansible.builtin.include_tasks: debian.yml + when: ansible_facts.os_family == "Debian" tags: - - firewall + - unbound + +- name: RedHat specific tasks + ansible.builtin.include_tasks: redhat.yml + when: ansible_facts.os_family == "RedHat" + tags: + - unbound - name: Include install tasks ansible.builtin.include_tasks: install.yml @@ -26,6 +32,7 @@ when: - sso_apply_patches is defined and sso_apply_patches - sso_enable is defined and sso_enable + - ansible_facts.os_family == "RedHat" tags: - install - patch diff --git a/roles/keycloak/tasks/prereqs.yml b/roles/keycloak/tasks/prereqs.yml index aad814b..565931b 100644 --- a/roles/keycloak/tasks/prereqs.yml +++ b/roles/keycloak/tasks/prereqs.yml @@ -42,6 +42,6 @@ packages_list: - "{{ keycloak_jvm_package }}" - unzip - - procps-ng - - initscripts - - tzdata-java + - "{{ 'procps-ng' if ansible_facts.os_family == 'RedHat' else 'procps' }}" + - "{{ 'initscripts' if ansible_facts.os_family == 'RedHat' else 'apt' }}" + - "{{ 'tzdata-java' if ansible_facts.os_family == 'RedHat' else 'tzdata' }}" diff --git a/roles/keycloak/tasks/redhat.yml b/roles/keycloak/tasks/redhat.yml new file mode 100644 index 0000000..596834b --- /dev/null +++ b/roles/keycloak/tasks/redhat.yml @@ -0,0 +1,6 @@ +--- +- name: Include firewall config tasks + ansible.builtin.include_tasks: firewalld.yml + when: keycloak_configure_firewalld + tags: + - firewall diff --git a/roles/keycloak/tasks/systemd.yml b/roles/keycloak/tasks/systemd.yml index cd58345..cf84c32 100644 --- a/roles/keycloak/tasks/systemd.yml +++ b/roles/keycloak/tasks/systemd.yml @@ -10,9 +10,32 @@ notify: - restart keycloak +- name: Determine JAVA_HOME for selected JVM RPM + ansible.builtin.set_fact: + rpm_java_home: "/lib/jvm/java-{{ keycloak_jvm_package | regex_search('(?<=java-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" + when: + - ansible_facts.os_family == 'Debian' + - name: Determine JAVA_HOME for selected JVM RPM ansible.builtin.set_fact: rpm_java_home: "/etc/alternatives/jre_{{ keycloak_jvm_package | regex_search('(?<=java-)[0-9.]+') }}" + when: + - ansible_facts.os_family == 'RedHat' + +- name: "Configure sysconfig file for {{ keycloak.service_name }} service" + become: true + ansible.builtin.template: + src: keycloak-sysconfig.j2 + dest: /etc/default/keycloak + owner: root + group: root + mode: 0644 + vars: + keycloak_rpm_java_home: "{{ rpm_java_home }}" + when: + - ansible_facts.os_family == "Debian" + notify: + - restart keycloak - name: "Configure sysconfig file for {{ keycloak.service_name }} service" become: true @@ -24,6 +47,8 @@ mode: 0644 vars: keycloak_rpm_java_home: "{{ rpm_java_home }}" + when: + - ansible_facts.os_family == "RedHat" notify: - restart keycloak diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index f5cdb82..f2f07a5 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -9,7 +9,7 @@ keycloak_quarkus_installdir: "{{ keycloak_quarkus_dest }}/keycloak-{{ keycloak_q keycloak_quarkus_offline_install: false ### Install location and service settings -keycloak_quarkus_jvm_package: java-17-openjdk-headless +keycloak_quarkus_jvm_package: "{{ 'java-17-openjdk-headless' if ansible_facts.os_family == 'RedHat' else 'openjdk-17-jdk-headless' }}" keycloak_quarkus_java_home: keycloak_quarkus_dest: /opt/keycloak keycloak_quarkus_home: "{{ keycloak_quarkus_installdir }}" diff --git a/roles/keycloak_quarkus/tasks/debian.yml b/roles/keycloak_quarkus/tasks/debian.yml new file mode 100644 index 0000000..ffb1348 --- /dev/null +++ b/roles/keycloak_quarkus/tasks/debian.yml @@ -0,0 +1,6 @@ +--- +- name: Include firewall config tasks + ansible.builtin.include_tasks: iptables.yml + when: keycloak_configure_iptables + tags: + - firewall diff --git a/roles/keycloak_quarkus/tasks/fastpackages.yml b/roles/keycloak_quarkus/tasks/fastpackages.yml index c9085f8..3b557ef 100644 --- a/roles/keycloak_quarkus/tasks/fastpackages.yml +++ b/roles/keycloak_quarkus/tasks/fastpackages.yml @@ -4,14 +4,27 @@ register: rpm_info changed_when: false failed_when: false + when: ansible_facts.os_family == "RedHat" - name: "Add missing packages to the yum install list" ansible.builtin.set_fact: packages_to_install: "{{ packages_to_install | default([]) + rpm_info.stdout_lines | map('regex_findall', 'package (.+) is not installed$') | default([]) | flatten }}" + when: ansible_facts.os_family == "RedHat" - name: "Install packages: {{ packages_to_install }}" become: true ansible.builtin.yum: name: "{{ packages_to_install }}" state: present - when: packages_to_install | default([]) | length > 0 + when: + - packages_to_install | default([]) | length > 0 + - ansible_facts.os_family == "RedHat" + +- name: "Install packages: {{ packages_list }}" + become: true + ansible.builtin.package: + name: "{{ packages_list }}" + state: present + when: + - packages_list | default([]) | length > 0 + - ansible_facts.os_family == "Debian" diff --git a/roles/keycloak_quarkus/tasks/iptables.yml b/roles/keycloak_quarkus/tasks/iptables.yml new file mode 100644 index 0000000..b487b89 --- /dev/null +++ b/roles/keycloak_quarkus/tasks/iptables.yml @@ -0,0 +1,20 @@ +--- +- name: Ensure required package iptables are installed + ansible.builtin.include_tasks: fastpackages.yml + vars: + packages_list: + - iptables + +- name: "Configure firewall ports for {{ keycloak.service_name }}" + become: true + ansible.builtin.iptables: + destination_port: "{{ item }}" + action: "insert" + rule_num: 6 # magic number I forget why + chain: "INPUT" + policy: "ACCEPT" + protocol: tcp + loop: + - "{{ keycloak_quarkus_http_port }}" + - "{{ keycloak_quarkus_https_port }}" + - "{{ keycloak_quarkus_jgroups_port }}" diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index 4e55961..72f4fdd 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -5,11 +5,17 @@ tags: - prereqs -- name: Include firewall config tasks - ansible.builtin.include_tasks: firewalld.yml - when: keycloak_quarkus_configure_firewalld +- name: Debian specific tasks + ansible.builtin.include_tasks: debian.yml + when: ansible_facts.os_family == "Debian" tags: - - firewall + - unbound + +- name: RedHat specific tasks + ansible.builtin.include_tasks: redhat.yml + when: ansible_facts.os_family == "RedHat" + tags: + - unbound - name: Include install tasks ansible.builtin.include_tasks: install.yml diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index ee2abca..252f75f 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -29,6 +29,6 @@ packages_list: - "{{ keycloak_quarkus_jvm_package }}" - unzip - - procps-ng - - initscripts - - tzdata-java + - "{{ 'procps-ng' if ansible_facts.os_family == 'RedHat' else 'procps' }}" + - "{{ 'initscripts' if ansible_facts.os_family == 'RedHat' else 'apt' }}" + - "{{ 'tzdata-java' if ansible_facts.os_family == 'RedHat' else 'tzdata' }}" diff --git a/roles/keycloak_quarkus/tasks/redhat.yml b/roles/keycloak_quarkus/tasks/redhat.yml new file mode 100644 index 0000000..093b930 --- /dev/null +++ b/roles/keycloak_quarkus/tasks/redhat.yml @@ -0,0 +1,6 @@ +--- +- name: Include firewall config tasks + ansible.builtin.include_tasks: firewalld.yml + when: keycloak_quarkus_configure_firewalld + tags: + - firewall diff --git a/roles/keycloak_quarkus/tasks/systemd.yml b/roles/keycloak_quarkus/tasks/systemd.yml index 3d59b3f..65aeeb3 100644 --- a/roles/keycloak_quarkus/tasks/systemd.yml +++ b/roles/keycloak_quarkus/tasks/systemd.yml @@ -2,8 +2,31 @@ - name: Determine JAVA_HOME for selected JVM RPM ansible.builtin.set_fact: rpm_java_home: "/etc/alternatives/jre_{{ keycloak_quarkus_jvm_package | regex_search('(?<=java-)[0-9.]+') }}" + when: + - ansible_facts.os_family == "RedHat" -- name: "Configure sysconfig file for keycloak service" +- name: Determine JAVA_HOME for selected JVM RPM + ansible.builtin.set_fact: + rpm_java_home: "/lib/jvm/java-{{ keycloak_quarkus_jvm_package | regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" + when: + - ansible_facts.os_family == "Debian" + +- name: "Configure sysconfig file for {{ keycloak.service_name }} service" + become: true + ansible.builtin.template: + src: keycloak-sysconfig.j2 + dest: /etc/default/keycloak + owner: root + group: root + mode: 0644 + vars: + keycloak_rpm_java_home: "{{ rpm_java_home }}" + when: + - ansible_facts.os_family == "Debian" + notify: + - restart keycloak + +- name: "Configure sysconfig file for {{ keycloak.service_name }} service" become: true ansible.builtin.template: src: keycloak-sysconfig.j2 @@ -13,6 +36,8 @@ mode: 0644 vars: keycloak_rpm_java_home: "{{ rpm_java_home }}" + when: + - ansible_facts.os_family == "RedHat" notify: - restart keycloak From 56e4a43cf984558bc58bd84e184ec791b853a2d2 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 25 Mar 2024 09:30:25 +0100 Subject: [PATCH 038/205] add keycloak_realm default to sub entities --- roles/keycloak_realm/tasks/main.yml | 6 +++--- roles/keycloak_realm/tasks/manage_client_roles.yml | 2 +- roles/keycloak_realm/tasks/manage_user_client_roles.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/roles/keycloak_realm/tasks/main.yml b/roles/keycloak_realm/tasks/main.yml index c1f66bc..016ab55 100644 --- a/roles/keycloak_realm/tasks/main.yml +++ b/roles/keycloak_realm/tasks/main.yml @@ -41,11 +41,11 @@ auth_realm: "{{ keycloak_auth_realm }}" auth_username: "{{ keycloak_admin_user }}" auth_password: "{{ keycloak_admin_password }}" - realm: "{{ item.realm }}" + realm: "{{ item.realm | default(keycloak_realm) }}" name: "{{ item.name }}" state: present provider_id: "{{ item.provider_id }}" - provider_type: "{{ item.provider_type | default(org.keycloak.storage.UserStorageProvider) }}" + provider_type: "{{ item.provider_type | default(org.keycloak.storage.UserStorageProvider) }}" config: "{{ item.config }}" mappers: "{{ item.mappers | default(omit) }}" no_log: "{{ keycloak_no_log | default('True') }}" @@ -71,7 +71,7 @@ auth_realm: "{{ keycloak_auth_realm }}" auth_username: "{{ keycloak_admin_user }}" auth_password: "{{ keycloak_admin_password }}" - realm: "{{ item.realm }}" + realm: "{{ item.realm | default(keycloak_realm) }}" default_roles: "{{ item.roles | default(omit) }}" client_id: "{{ item.client_id | default(omit) }}" id: "{{ item.id | default(omit) }}" diff --git a/roles/keycloak_realm/tasks/manage_client_roles.yml b/roles/keycloak_realm/tasks/manage_client_roles.yml index 4a261b1..fbb25ac 100644 --- a/roles/keycloak_realm/tasks/manage_client_roles.yml +++ b/roles/keycloak_realm/tasks/manage_client_roles.yml @@ -1,7 +1,7 @@ - name: Create client roles middleware_automation.keycloak.keycloak_role: name: "{{ item }}" - realm: "{{ client.realm }}" + realm: "{{ client.realm | default(keycloak_realm) }}" client_id: "{{ client.name }}" auth_client_id: "{{ keycloak_auth_client }}" auth_keycloak_url: "{{ keycloak_url }}{{ keycloak_context }}" diff --git a/roles/keycloak_realm/tasks/manage_user_client_roles.yml b/roles/keycloak_realm/tasks/manage_user_client_roles.yml index 85de09a..4311daa 100644 --- a/roles/keycloak_realm/tasks/manage_user_client_roles.yml +++ b/roles/keycloak_realm/tasks/manage_user_client_roles.yml @@ -1,7 +1,7 @@ --- - name: "Get Realm for role" ansible.builtin.uri: - url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm }}" + url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm | default(keycloak_realm) }}" method: GET status_code: - 200 @@ -12,7 +12,7 @@ - name: Check if Mapping is available ansible.builtin.uri: - url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm }}/users/{{ (keycloak_user.json | first).id }}/role-mappings/clients/{{ (create_client_result.results | selectattr('end_state.clientId', 'equalto', client_role.client) | list | first).end_state.id }}/available" + url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm | default(keycloak_realm) }}/users/{{ (keycloak_user.json | first).id }}/role-mappings/clients/{{ (create_client_result.results | selectattr('end_state.clientId', 'equalto', client_role.client) | list | first).end_state.id }}/available" method: GET status_code: - 200 @@ -23,7 +23,7 @@ - name: "Create Role Mapping" ansible.builtin.uri: - url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm }}/users/{{ (keycloak_user.json | first).id }}/role-mappings/clients/{{ (create_client_result.results | selectattr('end_state.clientId', 'equalto', client_role.client) | list | first).end_state.id }}" + url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm | default(keycloak_realm) }}/users/{{ (keycloak_user.json | first).id }}/role-mappings/clients/{{ (create_client_result.results | selectattr('end_state.clientId', 'equalto', client_role.client) | list | first).end_state.id }}" method: POST body: - id: "{{ item.id }}" From dd6171f0247733fc12534698111f78dbd8b206e7 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 25 Mar 2024 10:19:08 +0100 Subject: [PATCH 039/205] Add ansible_family based vars loading --- roles/keycloak_quarkus/defaults/main.yml | 1 - roles/keycloak_quarkus/meta/main.yml | 6 ++++++ roles/keycloak_quarkus/tasks/prereqs.yml | 22 +++++++++++++++------- roles/keycloak_quarkus/vars/debian.yml | 11 +++++++++++ roles/keycloak_quarkus/vars/redhat.yml | 11 +++++++++++ 5 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 roles/keycloak_quarkus/vars/debian.yml create mode 100644 roles/keycloak_quarkus/vars/redhat.yml diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index f2f07a5..e630bd3 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -9,7 +9,6 @@ keycloak_quarkus_installdir: "{{ keycloak_quarkus_dest }}/keycloak-{{ keycloak_q keycloak_quarkus_offline_install: false ### Install location and service settings -keycloak_quarkus_jvm_package: "{{ 'java-17-openjdk-headless' if ansible_facts.os_family == 'RedHat' else 'openjdk-17-jdk-headless' }}" keycloak_quarkus_java_home: keycloak_quarkus_dest: /opt/keycloak keycloak_quarkus_home: "{{ keycloak_quarkus_installdir }}" diff --git a/roles/keycloak_quarkus/meta/main.yml b/roles/keycloak_quarkus/meta/main.yml index 8d7331d..0f82003 100644 --- a/roles/keycloak_quarkus/meta/main.yml +++ b/roles/keycloak_quarkus/meta/main.yml @@ -14,6 +14,11 @@ galaxy_info: - name: EL versions: - "8" + - "9" + - name: Fedora + - name: Debian + - name: Ubuntu + galaxy_tags: - keycloak @@ -25,3 +30,4 @@ galaxy_info: - identity - security - rhbk + - debian diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index 252f75f..7a33a48 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -6,7 +6,7 @@ quiet: true fail_msg: "The console administrator password is empty or invalid. Please set the keycloak_quarkus_admin_pass variable to a 12+ char long string" success_msg: "{{ 'Console administrator password OK' }}" - + - name: Validate relative path ansible.builtin.assert: that: @@ -23,12 +23,20 @@ fail_msg: "Cannot install HA setup without a backend database service. Check keycloak_quarkus_ha_enabled and keycloak_quarkus_db_enabled" success_msg: "{{ 'Configuring HA' if keycloak_quarkus_ha_enabled else 'Configuring standalone' }}" +- name: Validate OS family + ansible.builtin.assert: + that: + - ansible_os_family in ["RedHat", "Debian"] + quiet: true + fail_msg: "Can only install on RedHat or Debian OS families; found {{ ansible_os_family }}" + success_msg: "Installing on {{ ansible_os_family }}" + +- name: Load OS specific variables + ansible.builtin.include_vars: "vars/{{ ansible_os_family | lower }}.yml" + tags: + - always + - name: Ensure required packages are installed ansible.builtin.include_tasks: fastpackages.yml vars: - packages_list: - - "{{ keycloak_quarkus_jvm_package }}" - - unzip - - "{{ 'procps-ng' if ansible_facts.os_family == 'RedHat' else 'procps' }}" - - "{{ 'initscripts' if ansible_facts.os_family == 'RedHat' else 'apt' }}" - - "{{ 'tzdata-java' if ansible_facts.os_family == 'RedHat' else 'tzdata' }}" + packages_list: "{{ keycloak_prereq_package_list }}" diff --git a/roles/keycloak_quarkus/vars/debian.yml b/roles/keycloak_quarkus/vars/debian.yml new file mode 100644 index 0000000..6c7ed90 --- /dev/null +++ b/roles/keycloak_quarkus/vars/debian.yml @@ -0,0 +1,11 @@ +--- +keycloak_quarkus_jvm_package: openjdk-17-jdk-headless +keycloak_prereq_package_list: + - "{{ keycloak_quarkus_jvm_package }}" + - unzip + - procps + - apt + - tzdata +keycloak_quarkus_configure_iptables: True +keycloak_quarkus_sysconf_file: /etc/default/keycloak +keycloak_quarkus_pkg_java_home: "/lib/jvm/java-{{ keycloak_quarkus_jvm_package | regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" diff --git a/roles/keycloak_quarkus/vars/redhat.yml b/roles/keycloak_quarkus/vars/redhat.yml new file mode 100644 index 0000000..775f983 --- /dev/null +++ b/roles/keycloak_quarkus/vars/redhat.yml @@ -0,0 +1,11 @@ +--- +keycloak_quarkus_jvm_package: java-17-openjdk-headless +keycloak_prereq_package_list: + - "{{ keycloak_quarkus_jvm_package }}" + - unzip + - procps-ng + - initscripts + - tzdata-java +keycloak_quarkus_configure_iptables: False +keycloak_quarkus_sysconf_file: /etc/sysconfig/keycloak +keycloak_quarkus_pkg_java_home: "/etc/alternatives/jre_{{ keycloak_quarkus_jvm_package | regex_search('(?<=java-)[0-9.]+') }}" From 3b1534d700c02ca2d863a62cfa0b89e439fd440f Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 25 Mar 2024 10:19:28 +0100 Subject: [PATCH 040/205] refactor --- roles/keycloak_quarkus/tasks/debian.yml | 2 +- roles/keycloak_quarkus/tasks/fastpackages.yml | 2 +- roles/keycloak_quarkus/tasks/main.yml | 10 ++---- roles/keycloak_quarkus/tasks/systemd.yml | 33 ++----------------- .../templates/keycloak-sysconfig.j2 | 4 +-- .../templates/keycloak.service.j2 | 2 +- 6 files changed, 9 insertions(+), 44 deletions(-) diff --git a/roles/keycloak_quarkus/tasks/debian.yml b/roles/keycloak_quarkus/tasks/debian.yml index ffb1348..4a36661 100644 --- a/roles/keycloak_quarkus/tasks/debian.yml +++ b/roles/keycloak_quarkus/tasks/debian.yml @@ -1,6 +1,6 @@ --- - name: Include firewall config tasks ansible.builtin.include_tasks: iptables.yml - when: keycloak_configure_iptables + when: keycloak_quarkus_configure_iptables tags: - firewall diff --git a/roles/keycloak_quarkus/tasks/fastpackages.yml b/roles/keycloak_quarkus/tasks/fastpackages.yml index 3b557ef..5affe64 100644 --- a/roles/keycloak_quarkus/tasks/fastpackages.yml +++ b/roles/keycloak_quarkus/tasks/fastpackages.yml @@ -13,7 +13,7 @@ - name: "Install packages: {{ packages_to_install }}" become: true - ansible.builtin.yum: + ansible.builtin.dnf: name: "{{ packages_to_install }}" state: present when: diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index 72f4fdd..86b3211 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -4,16 +4,10 @@ ansible.builtin.include_tasks: prereqs.yml tags: - prereqs + - always - name: Debian specific tasks - ansible.builtin.include_tasks: debian.yml - when: ansible_facts.os_family == "Debian" - tags: - - unbound - -- name: RedHat specific tasks - ansible.builtin.include_tasks: redhat.yml - when: ansible_facts.os_family == "RedHat" + ansible.builtin.include_tasks: "{{ ansible_os_family | lower }}.yml" tags: - unbound diff --git a/roles/keycloak_quarkus/tasks/systemd.yml b/roles/keycloak_quarkus/tasks/systemd.yml index 65aeeb3..58dbc7e 100644 --- a/roles/keycloak_quarkus/tasks/systemd.yml +++ b/roles/keycloak_quarkus/tasks/systemd.yml @@ -1,43 +1,14 @@ --- -- name: Determine JAVA_HOME for selected JVM RPM - ansible.builtin.set_fact: - rpm_java_home: "/etc/alternatives/jre_{{ keycloak_quarkus_jvm_package | regex_search('(?<=java-)[0-9.]+') }}" - when: - - ansible_facts.os_family == "RedHat" - -- name: Determine JAVA_HOME for selected JVM RPM - ansible.builtin.set_fact: - rpm_java_home: "/lib/jvm/java-{{ keycloak_quarkus_jvm_package | regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" - when: - - ansible_facts.os_family == "Debian" - - name: "Configure sysconfig file for {{ keycloak.service_name }} service" become: true ansible.builtin.template: src: keycloak-sysconfig.j2 - dest: /etc/default/keycloak + dest: "{{ keycloak_quarkus_sysconf_file }}" owner: root group: root mode: 0644 vars: - keycloak_rpm_java_home: "{{ rpm_java_home }}" - when: - - ansible_facts.os_family == "Debian" - notify: - - restart keycloak - -- name: "Configure sysconfig file for {{ keycloak.service_name }} service" - become: true - ansible.builtin.template: - src: keycloak-sysconfig.j2 - dest: /etc/sysconfig/keycloak - owner: root - group: root - mode: 0644 - vars: - keycloak_rpm_java_home: "{{ rpm_java_home }}" - when: - - ansible_facts.os_family == "RedHat" + keycloak_pkg_java_home: "{{ keycloak_quarkus_pkg_java_home }}" notify: - restart keycloak diff --git a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 index aa6aef7..358794c 100644 --- a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 +++ b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 @@ -1,6 +1,6 @@ {{ ansible_managed | comment }} KEYCLOAK_ADMIN={{ keycloak_quarkus_admin_user }} KEYCLOAK_ADMIN_PASSWORD='{{ keycloak_quarkus_admin_pass }}' -PATH={{ keycloak_quarkus_java_home | default(keycloak_rpm_java_home, true) }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -JAVA_HOME={{ keycloak_quarkus_java_home | default(keycloak_rpm_java_home, true) }} +PATH={{ keycloak_quarkus_java_home | default(keycloak_pkg_java_home, true) }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +JAVA_HOME={{ keycloak_quarkus_java_home | default(keycloak_pkg_java_home, true) }} JAVA_OPTS_APPEND={{ keycloak_quarkus_java_opts }} diff --git a/roles/keycloak_quarkus/templates/keycloak.service.j2 b/roles/keycloak_quarkus/templates/keycloak.service.j2 index af61007..3cdfacf 100644 --- a/roles/keycloak_quarkus/templates/keycloak.service.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.service.j2 @@ -5,7 +5,7 @@ After=network.target [Service] Type=simple -EnvironmentFile=-/etc/sysconfig/keycloak +EnvironmentFile=-{{ keycloak_quarkus_sysconf_file }} PIDFile={{ keycloak_quarkus_service_pidfile }} {% if keycloak_quarkus_start_dev %} ExecStart={{ keycloak.home }}/bin/kc.sh start-dev From 3400b64b105e19c2b8690bedba518fe8295130df Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 25 Mar 2024 14:34:25 +0100 Subject: [PATCH 041/205] add to ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index afb1403..509bebb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,4 +15,4 @@ jobs: with: fqcn: 'middleware_automation/keycloak' molecule_tests: >- - [ "default", "overridexml", "https_revproxy", "quarkus", "quarkus-devmode" ] + [ "default", "overridexml", "https_revproxy", "quarkus", "quarkus-devmode", "debian" ] From 0e4df659f431f563b7800bf31b49867051305911 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 25 Mar 2024 14:34:36 +0100 Subject: [PATCH 042/205] add test --- molecule/debian/converge.yml | 40 ++++++++++++++++++ molecule/debian/molecule.yml | 44 ++++++++++++++++++++ molecule/debian/prepare.yml | 11 +++++ molecule/debian/roles | 1 + molecule/debian/verify.yml | 52 ++++++++++++++++++++++++ roles/keycloak_quarkus/tasks/main.yml | 2 +- roles/keycloak_quarkus/tasks/prereqs.yml | 2 +- roles/keycloak_quarkus/vars/debian.yml | 2 +- roles/keycloak_quarkus/vars/redhat.yml | 2 +- 9 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 molecule/debian/converge.yml create mode 100644 molecule/debian/molecule.yml create mode 100644 molecule/debian/prepare.yml create mode 120000 molecule/debian/roles create mode 100644 molecule/debian/verify.yml diff --git a/molecule/debian/converge.yml b/molecule/debian/converge.yml new file mode 100644 index 0000000..0be6a85 --- /dev/null +++ b/molecule/debian/converge.yml @@ -0,0 +1,40 @@ +--- +- name: Converge + hosts: all + vars: + keycloak_admin_password: "remembertochangeme" + keycloak_quarkus_admin_pass: "remembertochangeme" + keycloak_realm: TestRealm + keycloak_quarkus_log: file + keycloak_quarkus_frontend_url: 'http://localhost:8080/' + keycloak_quarkus_start_dev: True + keycloak_quarkus_proxy_mode: none + keycloak_client_default_roles: + - TestRoleAdmin + - TestRoleUser + keycloak_client_users: + - username: TestUser + password: password + client_roles: + - client: TestClient + role: TestRoleUser + - username: TestAdmin + password: password + client_roles: + - client: TestClient + role: TestRoleUser + - client: TestClient + role: TestRoleAdmin + keycloak_clients: + - name: TestClient + roles: "{{ keycloak_client_default_roles }}" + public_client: "{{ keycloak_client_public }}" + web_origins: "{{ keycloak_client_web_origins }}" + users: "{{ keycloak_client_users }}" + client_id: TestClient + attributes: + post.logout.redirect.uris: '/public/logout' + roles: + - role: keycloak_quarkus + - role: keycloak_realm + keycloak_realm: TestRealm diff --git a/molecule/debian/molecule.yml b/molecule/debian/molecule.yml new file mode 100644 index 0000000..78b102c --- /dev/null +++ b/molecule/debian/molecule.yml @@ -0,0 +1,44 @@ +--- +driver: + name: docker +platforms: + - name: instance + image: ghcr.io/hspaans/molecule-containers:debian-11 + pre_build_image: true + privileged: true + port_bindings: + - "8080/tcp" + - "8443/tcp" + - "8009/tcp" +provisioner: + name: ansible + config_options: + defaults: + interpreter_python: auto_silent + ssh_connection: + pipelining: false + playbooks: + prepare: prepare.yml + converge: converge.yml + verify: verify.yml + inventory: + host_vars: + localhost: + ansible_python_interpreter: /usr/bin/python3 + env: + ANSIBLE_FORCE_COLOR: "true" + ANSIBLE_REMOTE_TMP: /tmp/.ansible/tmp +verifier: + name: ansible +scenario: + test_sequence: + - cleanup + - destroy + - create + - prepare + - converge + - idempotence + - side_effect + - verify + - cleanup + - destroy diff --git a/molecule/debian/prepare.yml b/molecule/debian/prepare.yml new file mode 100644 index 0000000..6025ef9 --- /dev/null +++ b/molecule/debian/prepare.yml @@ -0,0 +1,11 @@ +--- +- name: Prepare + hosts: all + gather_facts: yes + tasks: + - name: Install sudo + ansible.builtin.apt: + name: + - sudo + - openjdk-17-jdk-headless + state: present diff --git a/molecule/debian/roles b/molecule/debian/roles new file mode 120000 index 0000000..b741aa3 --- /dev/null +++ b/molecule/debian/roles @@ -0,0 +1 @@ +../../roles \ No newline at end of file diff --git a/molecule/debian/verify.yml b/molecule/debian/verify.yml new file mode 100644 index 0000000..040558a --- /dev/null +++ b/molecule/debian/verify.yml @@ -0,0 +1,52 @@ +--- +- name: Verify + hosts: all + vars: + keycloak_admin_password: "remembertochangeme" + keycloak_uri: "http://localhost:{{ 8080 + ( keycloak_jboss_port_offset | default(0) ) }}" + keycloak_management_port: "http://localhost:{{ 9990 + ( keycloak_jboss_port_offset | default(0) ) }}" + keycloak_jboss_port_offset: 10 + tasks: + - name: Populate service facts + ansible.builtin.service_facts: + + - name: Check if keycloak service started + ansible.builtin.assert: + that: + - ansible_facts.services["keycloak.service"]["state"] == "running" + - ansible_facts.services["keycloak.service"]["status"] == "enabled" + + - name: Verify we are running on requested JAVA_HOME # noqa blocked_modules command-instead-of-module + ansible.builtin.shell: | + set -o pipefail + ps -ef | grep '/opt/openjdk' | grep -v grep + args: + executable: /bin/bash + changed_when: False + + - name: Set internal envvar + ansible.builtin.set_fact: + hera_home: "{{ lookup('env', 'HERA_HOME') }}" + + - name: Verify openid config + block: + - name: Fetch openID config # noqa blocked_modules command-instead-of-module + ansible.builtin.shell: | + set -o pipefail + curl http://localhost:8080/realms/master/.well-known/openid-configuration -k | jq . + args: + executable: /bin/bash + delegate_to: localhost + register: openid_config + changed_when: False + - name: Verify endpoint URLs + ansible.builtin.assert: + that: + - (openid_config.stdout | from_json)["backchannel_authentication_endpoint"] == 'http://localhost:8080/realms/master/protocol/openid-connect/ext/ciba/auth' + - (openid_config.stdout | from_json)['issuer'] == 'http://localhost:8080/realms/master' + - (openid_config.stdout | from_json)['authorization_endpoint'] == 'http://localhost:8080/realms/master/protocol/openid-connect/auth' + - (openid_config.stdout | from_json)['token_endpoint'] == 'http://localhost:8080/realms/master/protocol/openid-connect/token' + delegate_to: localhost + when: + - hera_home is defined + - hera_home | length == 0 diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index 86b3211..decb63b 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -6,7 +6,7 @@ - prereqs - always -- name: Debian specific tasks +- name: Distro specific tasks ansible.builtin.include_tasks: "{{ ansible_os_family | lower }}.yml" tags: - unbound diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index 7a33a48..a9fbeaa 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -39,4 +39,4 @@ - name: Ensure required packages are installed ansible.builtin.include_tasks: fastpackages.yml vars: - packages_list: "{{ keycloak_prereq_package_list }}" + packages_list: "{{ keycloak_quarkus_prereq_package_list }}" diff --git a/roles/keycloak_quarkus/vars/debian.yml b/roles/keycloak_quarkus/vars/debian.yml index 6c7ed90..8ff6775 100644 --- a/roles/keycloak_quarkus/vars/debian.yml +++ b/roles/keycloak_quarkus/vars/debian.yml @@ -1,6 +1,6 @@ --- keycloak_quarkus_jvm_package: openjdk-17-jdk-headless -keycloak_prereq_package_list: +keycloak_quarkus_prereq_package_list: - "{{ keycloak_quarkus_jvm_package }}" - unzip - procps diff --git a/roles/keycloak_quarkus/vars/redhat.yml b/roles/keycloak_quarkus/vars/redhat.yml index 775f983..e40a94a 100644 --- a/roles/keycloak_quarkus/vars/redhat.yml +++ b/roles/keycloak_quarkus/vars/redhat.yml @@ -1,6 +1,6 @@ --- keycloak_quarkus_jvm_package: java-17-openjdk-headless -keycloak_prereq_package_list: +keycloak_quarkus_prereq_package_list: - "{{ keycloak_quarkus_jvm_package }}" - unzip - procps-ng From e17505fe423eb2500aff3a73e0fa99941a462151 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 25 Mar 2024 15:37:02 +0100 Subject: [PATCH 043/205] update molecule for debian container --- molecule/debian/molecule.yml | 4 ++++ molecule/requirements.yml | 2 +- roles/keycloak_quarkus/vars/debian.yml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/molecule/debian/molecule.yml b/molecule/debian/molecule.yml index 78b102c..afe29c5 100644 --- a/molecule/debian/molecule.yml +++ b/molecule/debian/molecule.yml @@ -10,6 +10,10 @@ platforms: - "8080/tcp" - "8443/tcp" - "8009/tcp" + cgroupns_mode: host + command: "/lib/systemd/systemd" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw provisioner: name: ansible config_options: diff --git a/molecule/requirements.yml b/molecule/requirements.yml index c87fd9a..5c8bb43 100644 --- a/molecule/requirements.yml +++ b/molecule/requirements.yml @@ -5,7 +5,7 @@ collections: - name: community.general - name: ansible.posix - name: community.docker - version: ">=1.9.1" + version: ">=3.8.0" roles: - name: elan.simple_nginx_reverse_proxy diff --git a/roles/keycloak_quarkus/vars/debian.yml b/roles/keycloak_quarkus/vars/debian.yml index 8ff6775..e8c90e3 100644 --- a/roles/keycloak_quarkus/vars/debian.yml +++ b/roles/keycloak_quarkus/vars/debian.yml @@ -8,4 +8,4 @@ keycloak_quarkus_prereq_package_list: - tzdata keycloak_quarkus_configure_iptables: True keycloak_quarkus_sysconf_file: /etc/default/keycloak -keycloak_quarkus_pkg_java_home: "/lib/jvm/java-{{ keycloak_quarkus_jvm_package | regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" +keycloak_quarkus_pkg_java_home: "/usr/lib/jvm/java-{{ keycloak_quarkus_jvm_package | regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" From 467cfda0f7ef1d62157970d7e91a03b4929842e0 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 25 Mar 2024 15:41:57 +0100 Subject: [PATCH 044/205] same changes for keycloak-legacy --- molecule/debian/converge.yml | 3 ++- molecule/debian/verify.yml | 12 ----------- roles/keycloak/defaults/main.yml | 2 -- roles/keycloak/tasks/main.yml | 11 ++-------- roles/keycloak/tasks/prereqs.yml | 20 ++++++++++++------ roles/keycloak/tasks/systemd.yml | 21 +------------------ .../keycloak/templates/keycloak-sysconfig.j2 | 2 +- roles/keycloak/templates/keycloak.service.j2 | 2 +- roles/keycloak/vars/debian.yml | 11 ++++++++++ roles/keycloak/vars/redhat.yml | 11 ++++++++++ 10 files changed, 43 insertions(+), 52 deletions(-) create mode 100644 roles/keycloak/vars/debian.yml create mode 100644 roles/keycloak/vars/redhat.yml diff --git a/molecule/debian/converge.yml b/molecule/debian/converge.yml index 0be6a85..17517b8 100644 --- a/molecule/debian/converge.yml +++ b/molecule/debian/converge.yml @@ -2,7 +2,6 @@ - name: Converge hosts: all vars: - keycloak_admin_password: "remembertochangeme" keycloak_quarkus_admin_pass: "remembertochangeme" keycloak_realm: TestRealm keycloak_quarkus_log: file @@ -38,3 +37,5 @@ - role: keycloak_quarkus - role: keycloak_realm keycloak_realm: TestRealm + keycloak_admin_password: "remembertochangeme" + keycloak_context: '' diff --git a/molecule/debian/verify.yml b/molecule/debian/verify.yml index 040558a..59bf483 100644 --- a/molecule/debian/verify.yml +++ b/molecule/debian/verify.yml @@ -16,18 +16,6 @@ - ansible_facts.services["keycloak.service"]["state"] == "running" - ansible_facts.services["keycloak.service"]["status"] == "enabled" - - name: Verify we are running on requested JAVA_HOME # noqa blocked_modules command-instead-of-module - ansible.builtin.shell: | - set -o pipefail - ps -ef | grep '/opt/openjdk' | grep -v grep - args: - executable: /bin/bash - changed_when: False - - - name: Set internal envvar - ansible.builtin.set_fact: - hera_home: "{{ lookup('env', 'HERA_HOME') }}" - - name: Verify openid config block: - name: Fetch openID config # noqa blocked_modules command-instead-of-module diff --git a/roles/keycloak/defaults/main.yml b/roles/keycloak/defaults/main.yml index 6658774..cfa9a3f 100644 --- a/roles/keycloak/defaults/main.yml +++ b/roles/keycloak/defaults/main.yml @@ -8,8 +8,6 @@ keycloak_installdir: "{{ keycloak_dest }}/keycloak-{{ keycloak_version }}" keycloak_offline_install: false ### Install location and service settings -keycloak_jvm_package: "{{ 'java-1.8.0-openjdk-headless' if ansible_facts.os_family == 'RedHat' else 'openjdk-8-jdk-headless' }}" - keycloak_java_home: keycloak_dest: /opt/keycloak keycloak_jboss_home: "{{ keycloak_installdir }}" diff --git a/roles/keycloak/tasks/main.yml b/roles/keycloak/tasks/main.yml index 284900b..a21f359 100644 --- a/roles/keycloak/tasks/main.yml +++ b/roles/keycloak/tasks/main.yml @@ -5,15 +5,8 @@ tags: - prereqs -- name: Debian specific tasks - ansible.builtin.include_tasks: debian.yml - when: ansible_facts.os_family == "Debian" - tags: - - unbound - -- name: RedHat specific tasks - ansible.builtin.include_tasks: redhat.yml - when: ansible_facts.os_family == "RedHat" +- name: Distro specific tasks + ansible.builtin.include_tasks: "{{ ansible_os_family | lower }}.yml" tags: - unbound diff --git a/roles/keycloak/tasks/prereqs.yml b/roles/keycloak/tasks/prereqs.yml index 565931b..c92bb1c 100644 --- a/roles/keycloak/tasks/prereqs.yml +++ b/roles/keycloak/tasks/prereqs.yml @@ -36,12 +36,20 @@ success_msg: "Configuring JDBC persistence using {{ keycloak_jdbc_engine }} database" when: keycloak_db_enabled +- name: Validate OS family + ansible.builtin.assert: + that: + - ansible_os_family in ["RedHat", "Debian"] + quiet: true + fail_msg: "Can only install on RedHat or Debian OS families; found {{ ansible_os_family }}" + success_msg: "Installing on {{ ansible_os_family }}" + +- name: Load OS specific variables + ansible.builtin.include_vars: "vars/{{ ansible_os_family | lower }}.yml" + tags: + - always + - name: Ensure required packages are installed ansible.builtin.include_tasks: fastpackages.yml vars: - packages_list: - - "{{ keycloak_jvm_package }}" - - unzip - - "{{ 'procps-ng' if ansible_facts.os_family == 'RedHat' else 'procps' }}" - - "{{ 'initscripts' if ansible_facts.os_family == 'RedHat' else 'apt' }}" - - "{{ 'tzdata-java' if ansible_facts.os_family == 'RedHat' else 'tzdata' }}" + packages_list: "{{ keycloak_prereq_package_list }}" diff --git a/roles/keycloak/tasks/systemd.yml b/roles/keycloak/tasks/systemd.yml index cf84c32..40fa6b8 100644 --- a/roles/keycloak/tasks/systemd.yml +++ b/roles/keycloak/tasks/systemd.yml @@ -26,29 +26,10 @@ become: true ansible.builtin.template: src: keycloak-sysconfig.j2 - dest: /etc/default/keycloak + dest: "{{ keycloak_sysconf_file }}" owner: root group: root mode: 0644 - vars: - keycloak_rpm_java_home: "{{ rpm_java_home }}" - when: - - ansible_facts.os_family == "Debian" - notify: - - restart keycloak - -- name: "Configure sysconfig file for {{ keycloak.service_name }} service" - become: true - ansible.builtin.template: - src: keycloak-sysconfig.j2 - dest: /etc/sysconfig/keycloak - owner: root - group: root - mode: 0644 - vars: - keycloak_rpm_java_home: "{{ rpm_java_home }}" - when: - - ansible_facts.os_family == "RedHat" notify: - restart keycloak diff --git a/roles/keycloak/templates/keycloak-sysconfig.j2 b/roles/keycloak/templates/keycloak-sysconfig.j2 index 4c38522..33889df 100644 --- a/roles/keycloak/templates/keycloak-sysconfig.j2 +++ b/roles/keycloak/templates/keycloak-sysconfig.j2 @@ -1,6 +1,6 @@ {{ ansible_managed | comment }} JAVA_OPTS='{{ keycloak_java_opts }}' -JAVA_HOME={{ keycloak_java_home | default(keycloak_rpm_java_home, true) }} +JAVA_HOME={{ keycloak_java_home | default(keycloak_pkg_java_home, true) }} JBOSS_HOME={{ keycloak.home }} KEYCLOAK_BIND_ADDRESS={{ keycloak_bind_address }} KEYCLOAK_HTTP_PORT={{ keycloak_http_port }} diff --git a/roles/keycloak/templates/keycloak.service.j2 b/roles/keycloak/templates/keycloak.service.j2 index eea3ba1..9a04e88 100644 --- a/roles/keycloak/templates/keycloak.service.j2 +++ b/roles/keycloak/templates/keycloak.service.j2 @@ -11,7 +11,7 @@ StartLimitBurst={{ keycloak_service_startlimitburst }} User={{ keycloak_service_user }} Group={{ keycloak_service_group }} {% endif -%} -EnvironmentFile=-/etc/sysconfig/keycloak +EnvironmentFile=-{{ keycloak_sysconf_file }} PIDFile={{ keycloak_service_pidfile }} ExecStart={{ keycloak.home }}/bin/standalone.sh $WILDFLY_OPTS WorkingDirectory={{ keycloak.home }} diff --git a/roles/keycloak/vars/debian.yml b/roles/keycloak/vars/debian.yml new file mode 100644 index 0000000..ac3df14 --- /dev/null +++ b/roles/keycloak/vars/debian.yml @@ -0,0 +1,11 @@ +--- +keycloak_jvm_package: openjdk-11-jdk-headless +keycloak_prereq_package_list: + - "{{ keycloak_jvm_package }}" + - unzip + - procps + - apt + - tzdata +keycloak_configure_iptables: True +keycloak_sysconf_file: /etc/default/keycloak +keycloak_pkg_java_home: "/usr/lib/jvm/java-{{ keycloak_jvm_package | regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" diff --git a/roles/keycloak/vars/redhat.yml b/roles/keycloak/vars/redhat.yml new file mode 100644 index 0000000..206251e --- /dev/null +++ b/roles/keycloak/vars/redhat.yml @@ -0,0 +1,11 @@ +--- +keycloak_jvm_package: java-1.8.0-openjdk-headless +keycloak_prereq_package_list: + - "{{ keycloak_jvm_package }}" + - unzip + - procps-ng + - initscripts + - tzdata-java +keycloak_configure_iptables: False +keycloak_sysconf_file: /etc/sysconfig/keycloak +keycloak_pkg_java_home: "/etc/alternatives/jre_{{ keycloak_jvm_package | regex_search('(?<=java-)[0-9.]+') }}" From 2bbf7d9cc4a94f75942d8a35a56abcd04a33cd3b Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 25 Mar 2024 16:30:13 +0100 Subject: [PATCH 045/205] revert JVM var that cannot be overridden --- molecule/default/converge.yml | 2 +- roles/keycloak/meta/argument_specs.yml | 55 +------------------ roles/keycloak/tasks/systemd.yml | 12 ---- roles/keycloak/vars/debian.yml | 6 +- roles/keycloak/vars/redhat.yml | 7 +-- roles/keycloak_quarkus/defaults/main.yml | 4 +- .../keycloak_quarkus/meta/argument_specs.yml | 41 ++------------ roles/keycloak_quarkus/vars/debian.yml | 7 +-- roles/keycloak_quarkus/vars/redhat.yml | 7 +-- 9 files changed, 22 insertions(+), 119 deletions(-) diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index ace4743..5927ff9 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -1,7 +1,7 @@ --- - name: Converge hosts: all - vars: + vars: keycloak_admin_password: "remembertochangeme" keycloak_jvm_package: java-11-openjdk-headless keycloak_modcluster_enabled: True diff --git a/roles/keycloak/meta/argument_specs.yml b/roles/keycloak/meta/argument_specs.yml index ca1cb8b..7ba6509 100644 --- a/roles/keycloak/meta/argument_specs.yml +++ b/roles/keycloak/meta/argument_specs.yml @@ -2,47 +2,38 @@ argument_specs: main: options: keycloak_version: - # line 3 of keycloak/defaults/main.yml default: "18.0.2" description: "keycloak.org package version" type: "str" keycloak_archive: - # line 4 of keycloak/defaults/main.yml default: "keycloak-legacy-{{ keycloak_version }}.zip" description: "keycloak install archive filename" type: "str" keycloak_configure_iptables: - # line 33 of keycloak/defaults/main.yml default: false description: "Ensure iptables is running and configure keycloak ports" type: "bool" keycloak_configure_firewalld: - # line 33 of keycloak/defaults/main.yml default: false description: "Ensure firewalld is running and configure keycloak ports" type: "bool" keycloak_download_url: - # line 5 of keycloak/defaults/main.yml default: "https://github.com/keycloak/keycloak/releases/download/{{ keycloak_version }}/{{ keycloak_archive }}" description: "Download URL for keycloak" type: "str" keycloak_download_url_9x: - # line 6 of keycloak/defaults/main.yml default: "https://downloads.jboss.org/keycloak/{{ keycloak_version }}/{{ keycloak_archive }}" description: "Download URL for keycloak (deprecated)" type: "str" keycloak_installdir: - # line 7 of keycloak/defaults/main.yml default: "{{ keycloak_dest }}/keycloak-{{ keycloak_version }}" description: "Installation path" type: "str" keycloak_offline_install: - # line 20 of keycloak/defaults/main.yml default: false description: "Perform an offline install" type: "bool" keycloak_jvm_package: - # line 23 of keycloak/defaults/main.yml default: "java-1.8.0-openjdk-headless" description: "RHEL java package runtime rpm" type: "str" @@ -50,12 +41,10 @@ argument_specs: description: "JAVA_HOME of installed JRE, leave empty for using specified keycloak_jvm_package RPM path" type: "str" keycloak_dest: - # line 24 of keycloak/defaults/main.yml default: "/opt/keycloak" description: "Root installation directory" type: "str" keycloak_jboss_home: - # line 25 of keycloak/defaults/main.yml default: "{{ keycloak_installdir }}" description: "Installation work directory" type: "str" @@ -64,52 +53,42 @@ argument_specs: description: "Port offset for the JBoss socket binding" type: "int" keycloak_config_dir: - # line 26 of keycloak/defaults/main.yml default: "{{ keycloak_jboss_home }}/standalone/configuration" description: "Path for configuration" type: "str" keycloak_config_standalone_xml: - # line 27 of keycloak/defaults/main.yml default: "keycloak.xml" description: "Service configuration filename" type: "str" keycloak_config_path_to_standalone_xml: - # line 28 of keycloak/defaults/main.yml default: "{{ keycloak_jboss_home }}/standalone/configuration/{{ keycloak_config_standalone_xml }}" description: "Custom path for configuration" type: "str" keycloak_config_override_template: - # line 30 of keycloak/defaults/main.yml default: "" description: "Path to custom template for standalone.xml configuration" type: "str" - keycloak_service_runas: - # line 20 of keycloak/defaults/main.yml + keycloak_service_runas: default: false description: "Enable execution of service as `keycloak_service_user`" type: "bool" keycloak_service_user: - # line 29 of keycloak/defaults/main.yml default: "keycloak" description: "posix account username" type: "str" keycloak_service_group: - # line 30 of keycloak/defaults/main.yml default: "keycloak" description: "posix account group" type: "str" keycloak_service_pidfile: - # line 31 of keycloak/defaults/main.yml default: "/run/keycloak/keycloak.pid" description: "PID file path for service" type: "str" keycloak_features: - # line 17 of keycloak/defaults/main.yml default: "[]" description: "List of `name`/`status` pairs of features (also known as profiles on RH-SSO) to `enable` or `disable`, example: `[ { name: 'docker', status: 'enabled' } ]`" type: "list" keycloak_bind_address: - # line 34 of keycloak/defaults/main.yml default: "0.0.0.0" description: "Address for binding service ports" type: "str" @@ -118,52 +97,42 @@ argument_specs: description: "Address for binding the management ports" type: "str" keycloak_host: - # line 35 of keycloak/defaults/main.yml default: "localhost" description: "Hostname for service" type: "str" keycloak_http_port: - # line 36 of keycloak/defaults/main.yml default: 8080 description: "Listening HTTP port" type: "int" keycloak_https_port: - # line 37 of keycloak/defaults/main.yml default: 8443 description: "Listening HTTPS port" type: "int" keycloak_ajp_port: - # line 38 of keycloak/defaults/main.yml default: 8009 description: "Listening AJP port" type: "int" keycloak_jgroups_port: - # line 39 of keycloak/defaults/main.yml default: 7600 description: "jgroups cluster tcp port" type: "int" keycloak_management_http_port: - # line 40 of keycloak/defaults/main.yml default: 9990 description: "Management port (http)" type: "int" keycloak_management_https_port: - # line 41 of keycloak/defaults/main.yml default: 9993 description: "Management port (https)" type: "int" keycloak_java_opts: - # line 42 of keycloak/defaults/main.yml default: "-Xms1024m -Xmx2048m" description: "Additional JVM options" type: "str" keycloak_prefer_ipv4: - # line 43 of keycloak/defaults/main.yml default: true description: "Prefer IPv4 stack and addresses for port binding" type: "bool" keycloak_ha_enabled: - # line 46 of keycloak/defaults/main.yml default: false description: "Enable auto configuration for database backend, clustering and remote caches on infinispan" type: "bool" @@ -172,27 +141,22 @@ argument_specs: description: "Discovery protocol for HA cluster members" type: "str" keycloak_db_enabled: - # line 48 of keycloak/defaults/main.yml default: "{{ True if keycloak_ha_enabled else False }}" description: "Enable auto configuration for database backend" type: "bool" keycloak_admin_user: - # line 51 of keycloak/defaults/main.yml default: "admin" description: "Administration console user account" type: "str" keycloak_auth_realm: - # line 52 of keycloak/defaults/main.yml default: "master" description: "Name for rest authentication realm" type: "str" keycloak_auth_client: - # line 53 of keycloak/defaults/main.yml default: "admin-cli" description: "Authentication client for configuration REST calls" type: "str" keycloak_force_install: - # line 55 of keycloak/defaults/main.yml default: false description: "Remove pre-existing versions of service" type: "bool" @@ -201,7 +165,6 @@ argument_specs: description: "Enable configuration for modcluster subsystem" type: "bool" keycloak_modcluster_url: - # line 58 of keycloak/defaults/main.yml default: "localhost" description: "URL for the modcluster reverse proxy" type: "str" @@ -214,7 +177,6 @@ argument_specs: description: "List of modproxy node URLs in the format { host, port } for the modcluster reverse proxy" type: "list" keycloak_frontend_url: - # line 59 of keycloak/defaults/main.yml default: "http://localhost" description: "Frontend URL for keycloak endpoints when a reverse proxy is used" type: "str" @@ -223,77 +185,62 @@ argument_specs: description: "Force backend requests to use the frontend URL" type: "bool" keycloak_infinispan_user: - # line 62 of keycloak/defaults/main.yml default: "supervisor" description: "Username for connecting to infinispan" type: "str" keycloak_infinispan_pass: - # line 63 of keycloak/defaults/main.yml default: "supervisor" description: "Password for connecting to infinispan" type: "str" keycloak_infinispan_url: - # line 64 of keycloak/defaults/main.yml default: "localhost" description: "URL for the infinispan remote-cache server" type: "str" keycloak_infinispan_sasl_mechanism: - # line 65 of keycloak/defaults/main.yml default: "SCRAM-SHA-512" description: "Authentication type to infinispan server" type: "str" keycloak_infinispan_use_ssl: - # line 66 of keycloak/defaults/main.yml default: false description: "Enable hotrod client TLS communication" type: "bool" keycloak_infinispan_trust_store_path: - # line 68 of keycloak/defaults/main.yml default: "/etc/pki/java/cacerts" description: "TODO document argument" type: "str" keycloak_infinispan_trust_store_password: - # line 69 of keycloak/defaults/main.yml default: "changeit" description: "Path to truststore containing infinispan server certificate" type: "str" keycloak_jdbc_engine: - # line 72 of keycloak/defaults/main.yml default: "postgres" description: "Backend database flavour when db is enabled: [ postgres, mariadb, sqlserver ]" type: "str" keycloak_db_user: - # line 74 of keycloak/defaults/main.yml default: "keycloak-user" description: "Username for connecting to database" type: "str" keycloak_db_pass: - # line 75 of keycloak/defaults/main.yml default: "keycloak-pass" description: "Password for connecting to database" type: "str" keycloak_jdbc_url: - # line 76 of keycloak/defaults/main.yml default: "{{ keycloak_default_jdbc[keycloak_jdbc_engine].url }}" description: "URL for connecting to backend database" type: "str" keycloak_jdbc_driver_version: - # line 77 of keycloak/defaults/main.yml default: "{{ keycloak_default_jdbc[keycloak_jdbc_engine].version }}" description: "Version for the JDBC driver to download" type: "str" keycloak_admin_password: - # line 4 of keycloak/vars/main.yml required: true description: "Password for the administration console user account" type: "str" keycloak_url: - # line 12 of keycloak/vars/main.yml default: "http://{{ keycloak_host }}:{{ keycloak_http_port + keycloak_jboss_port_offset }}" description: "URL for configuration rest calls" type: "str" keycloak_management_url: - # line 13 of keycloak/vars/main.yml default: "http://{{ keycloak_host }}:{{ keycloak_management_http_port + keycloak_jboss_port_offset }}" description: "URL for management console rest calls" type: "str" diff --git a/roles/keycloak/tasks/systemd.yml b/roles/keycloak/tasks/systemd.yml index 40fa6b8..797eb7b 100644 --- a/roles/keycloak/tasks/systemd.yml +++ b/roles/keycloak/tasks/systemd.yml @@ -10,18 +10,6 @@ notify: - restart keycloak -- name: Determine JAVA_HOME for selected JVM RPM - ansible.builtin.set_fact: - rpm_java_home: "/lib/jvm/java-{{ keycloak_jvm_package | regex_search('(?<=java-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" - when: - - ansible_facts.os_family == 'Debian' - -- name: Determine JAVA_HOME for selected JVM RPM - ansible.builtin.set_fact: - rpm_java_home: "/etc/alternatives/jre_{{ keycloak_jvm_package | regex_search('(?<=java-)[0-9.]+') }}" - when: - - ansible_facts.os_family == 'RedHat' - - name: "Configure sysconfig file for {{ keycloak.service_name }} service" become: true ansible.builtin.template: diff --git a/roles/keycloak/vars/debian.yml b/roles/keycloak/vars/debian.yml index ac3df14..60cdfa8 100644 --- a/roles/keycloak/vars/debian.yml +++ b/roles/keycloak/vars/debian.yml @@ -1,11 +1,11 @@ --- -keycloak_jvm_package: openjdk-11-jdk-headless +keycloak_varjvm_package: "{{ keycloak_jvm_package | default('openjdk-11-jdk-headless') }}" keycloak_prereq_package_list: - - "{{ keycloak_jvm_package }}" + - "{{ keycloak_varjvm_package }}" - unzip - procps - apt - tzdata keycloak_configure_iptables: True keycloak_sysconf_file: /etc/default/keycloak -keycloak_pkg_java_home: "/usr/lib/jvm/java-{{ keycloak_jvm_package | regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" +keycloak_pkg_java_home: "/usr/lib/jvm/java-{{ keycloak_varjvm_package | regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" diff --git a/roles/keycloak/vars/redhat.yml b/roles/keycloak/vars/redhat.yml index 206251e..6c36847 100644 --- a/roles/keycloak/vars/redhat.yml +++ b/roles/keycloak/vars/redhat.yml @@ -1,11 +1,10 @@ --- -keycloak_jvm_package: java-1.8.0-openjdk-headless +keycloak_varjvm_package: "{{ keycloak_jvm_package | default('java-1.8.0-openjdk-headless') }}" keycloak_prereq_package_list: - - "{{ keycloak_jvm_package }}" + - "{{ keycloak_varjvm_package }}" - unzip - procps-ng - initscripts - tzdata-java -keycloak_configure_iptables: False keycloak_sysconf_file: /etc/sysconfig/keycloak -keycloak_pkg_java_home: "/etc/alternatives/jre_{{ keycloak_jvm_package | regex_search('(?<=java-)[0-9.]+') }}" +keycloak_pkg_java_home: "/etc/alternatives/jre_{{ keycloak_varjvm_package | regex_search('(?<=java-)[0-9.]+') }}" diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index e630bd3..d931cab 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -17,11 +17,13 @@ keycloak_quarkus_start_dev: false keycloak_quarkus_service_user: keycloak keycloak_quarkus_service_group: keycloak keycloak_quarkus_service_pidfile: "/run/keycloak/keycloak.pid" -keycloak_quarkus_configure_firewalld: false keycloak_quarkus_service_restart_always: false keycloak_quarkus_service_restart_on_failure: false keycloak_quarkus_service_restartsec: "10s" +keycloak_quarkus_configure_firewalld: false +keycloak_quarkus_configure_iptables: false + ### administrator console password keycloak_quarkus_admin_user: admin keycloak_quarkus_admin_pass: diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index b1baea2..c7cd446 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -2,32 +2,26 @@ argument_specs: main: options: keycloak_quarkus_version: - # line 3 of defaults/main.yml - default: "17.0.1" + default: "23.0.7" description: "keycloak.org package version" type: "str" keycloak_quarkus_archive: - # line 4 of defaults/main.yml default: "keycloak-{{ keycloak_quarkus_version }}.zip" description: "keycloak install archive filename" type: "str" keycloak_quarkus_download_url: - # line 5 of defaults/main.yml default: "https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}" description: "Download URL for keycloak" type: "str" keycloak_quarkus_installdir: - # line 6 of defaults/main.yml default: "{{ keycloak_quarkus_dest }}/keycloak-{{ keycloak_quarkus_version }}" description: "Installation path" type: "str" keycloak_quarkus_offline_install: - # line 9 of defaults/main.yml default: false description: "Perform an offline install" type: "bool" keycloak_quarkus_jvm_package: - # line 12 of defaults/main.yml default: "java-11-openjdk-headless" description: "RHEL java package runtime" type: "str" @@ -35,37 +29,34 @@ argument_specs: description: "JAVA_HOME of installed JRE, leave empty for using specified keycloak_jvm_package RPM path" type: "str" keycloak_quarkus_dest: - # line 13 of defaults/main.yml default: "/opt/keycloak" description: "Installation root path" type: "str" keycloak_quarkus_home: - # line 14 of defaults/main.yml default: "{{ keycloak_quarkus_installdir }}" description: "Installation work directory" type: "str" keycloak_quarkus_config_dir: - # line 15 of defaults/main.yml default: "{{ keycloak_quarkus_home }}/conf" description: "Path for configuration" type: "str" keycloak_quarkus_service_user: - # line 16 of defaults/main.yml default: "keycloak" description: "Posix account username" type: "str" keycloak_quarkus_service_group: - # line 17 of defaults/main.yml default: "keycloak" description: "Posix account group" type: "str" keycloak_quarkus_service_pidfile: - # line 18 of defaults/main.yml default: "/run/keycloak/keycloak.pid" description: "Pid file path for service" type: "str" keycloak_quarkus_configure_firewalld: - # line 19 of defaults/main.yml + default: false + description: "Ensure firewalld is running and configure keycloak ports" + type: "bool" + keycloak_quarkus_configure_iptables: default: false description: "Ensure firewalld is running and configure keycloak ports" type: "bool" @@ -90,12 +81,10 @@ argument_specs: description: "Password of console admin account" type: "str" keycloak_quarkus_master_realm: - # line 24 of defaults/main.yml default: "master" description: "Name for rest authentication realm" type: "str" keycloak_quarkus_bind_address: - # line 27 of defaults/main.yml default: "0.0.0.0" description: "Address for binding service ports" type: "str" @@ -116,7 +105,6 @@ argument_specs: description: "Enable listener on HTTP port" type: "bool" keycloak_quarkus_http_port: - # line 29 of defaults/main.yml default: 8080 description: "HTTP port" type: "int" @@ -157,27 +145,22 @@ argument_specs: description: "Password for the trust store" type: "str" keycloak_quarkus_https_port: - # line 30 of defaults/main.yml default: 8443 description: "HTTPS port" type: "int" keycloak_quarkus_ajp_port: - # line 31 of defaults/main.yml default: 8009 description: "AJP port" type: "int" keycloak_quarkus_jgroups_port: - # line 32 of defaults/main.yml default: 7800 description: "jgroups cluster tcp port" type: "int" keycloak_quarkus_java_opts: - # line 33 of defaults/main.yml default: "-Xms1024m -Xmx2048m" description: "Additional JVM options" type: "str" keycloak_quarkus_ha_enabled: - # line 36 of defaults/main.yml default: false description: "Enable auto configuration for database backend, clustering and remote caches on infinispan" type: "bool" @@ -186,7 +169,6 @@ argument_specs: description: "Discovery protocol for HA cluster members" type: "str" keycloak_quarkus_db_enabled: - # line 38 of defaults/main.yml default: "{{ True if keycloak_quarkus_ha_enabled else False }}" description: "Enable auto configuration for database backend" type: "str" @@ -204,7 +186,6 @@ argument_specs: description: "Service URL for the admin console" type: "str" keycloak_quarkus_metrics_enabled: - # line 43 of defaults/main.yml default: false description: "Whether to enable metrics" type: "bool" @@ -213,62 +194,50 @@ argument_specs: description: "If the server should expose health check endpoints" type: "bool" keycloak_quarkus_ispn_user: - # line 46 of defaults/main.yml default: "supervisor" description: "Username for connecting to infinispan" type: "str" keycloak_quarkus_ispn_pass: - # line 47 of defaults/main.yml default: "supervisor" description: "Password for connecting to infinispan" type: "str" keycloak_quarkus_ispn_hosts: - # line 48 of defaults/main.yml default: "localhost:11222" description: "host name/port for connecting to infinispan, eg. host1:11222;host2:11222" type: "str" keycloak_quarkus_ispn_sasl_mechanism: - # line 49 of defaults/main.yml default: "SCRAM-SHA-512" description: "Infinispan auth mechanism" type: "str" keycloak_quarkus_ispn_use_ssl: - # line 50 of defaults/main.yml default: false description: "Whether infinispan uses TLS connection" type: "bool" keycloak_quarkus_ispn_trust_store_path: - # line 52 of defaults/main.yml default: "/etc/pki/java/cacerts" description: "Path to infinispan server trust certificate" type: "str" keycloak_quarkus_ispn_trust_store_password: - # line 53 of defaults/main.yml default: "changeit" description: "Password for infinispan certificate keystore" type: "str" keycloak_quarkus_jdbc_engine: - # line 56 of defaults/main.yml default: "postgres" description: "Database engine [mariadb,postres,mssql]" type: "str" keycloak_quarkus_db_user: - # line 58 of defaults/main.yml default: "keycloak-user" description: "User for database connection" type: "str" keycloak_quarkus_db_pass: - # line 59 of defaults/main.yml default: "keycloak-pass" description: "Password for database connection" type: "str" keycloak_quarkus_jdbc_url: - # line 60 of defaults/main.yml default: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].url }}" description: "JDBC URL for connecting to database" type: "str" keycloak_quarkus_jdbc_driver_version: - # line 61 of defaults/main.yml default: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].version }}" description: "Version for JDBC driver" type: "str" diff --git a/roles/keycloak_quarkus/vars/debian.yml b/roles/keycloak_quarkus/vars/debian.yml index e8c90e3..a42eb5f 100644 --- a/roles/keycloak_quarkus/vars/debian.yml +++ b/roles/keycloak_quarkus/vars/debian.yml @@ -1,11 +1,10 @@ --- -keycloak_quarkus_jvm_package: openjdk-17-jdk-headless +keycloak_quarkus_varjvm_package: "{{ keycloak_quarkus_jvm_package | default('openjdk-17-jdk-headless') }}" keycloak_quarkus_prereq_package_list: - - "{{ keycloak_quarkus_jvm_package }}" + - "{{ keycloak_quarkus_varjvm_package }}" - unzip - procps - apt - tzdata -keycloak_quarkus_configure_iptables: True keycloak_quarkus_sysconf_file: /etc/default/keycloak -keycloak_quarkus_pkg_java_home: "/usr/lib/jvm/java-{{ keycloak_quarkus_jvm_package | regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" +keycloak_quarkus_pkg_java_home: "/usr/lib/jvm/java-{{ keycloak_quarkus_varjvm_package | regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" diff --git a/roles/keycloak_quarkus/vars/redhat.yml b/roles/keycloak_quarkus/vars/redhat.yml index e40a94a..c311321 100644 --- a/roles/keycloak_quarkus/vars/redhat.yml +++ b/roles/keycloak_quarkus/vars/redhat.yml @@ -1,11 +1,10 @@ --- -keycloak_quarkus_jvm_package: java-17-openjdk-headless +keycloak_quarkus_varjvm_package: "{{ keycloak_quarkus_jvm_package | default('java-17-openjdk-headless') }}" keycloak_quarkus_prereq_package_list: - - "{{ keycloak_quarkus_jvm_package }}" + - "{{ keycloak_quarkus_varjvm_package }}" - unzip - procps-ng - initscripts - tzdata-java -keycloak_quarkus_configure_iptables: False keycloak_quarkus_sysconf_file: /etc/sysconfig/keycloak -keycloak_quarkus_pkg_java_home: "/etc/alternatives/jre_{{ keycloak_quarkus_jvm_package | regex_search('(?<=java-)[0-9.]+') }}" +keycloak_quarkus_pkg_java_home: "/etc/alternatives/jre_{{ keycloak_quarkus_varjvm_package | regex_search('(?<=java-)[0-9.]+') }}" From c2e456e1d55ad8943c5f053d1e05b3f3fc0ce14f Mon Sep 17 00:00:00 2001 From: avskor Date: Thu, 4 Apr 2024 11:22:18 +0300 Subject: [PATCH 046/205] Fix #125. Permission error when the become variable is set to true in the playbook --- roles/keycloak_quarkus/tasks/install.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index e865b72..0162266 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -50,6 +50,7 @@ path: "{{ lookup('env', 'PWD') }}" register: local_path delegate_to: localhost + become: false - name: Download keycloak archive ansible.builtin.get_url: # noqa risky-file-permissions delegated, uses controller host user @@ -57,6 +58,7 @@ dest: "{{ local_path.stat.path }}/{{ keycloak.bundle }}" mode: 0640 delegate_to: localhost + become: false run_once: true when: - archive_path is defined From 8f8de33350fa7b2abfdd030ef26c0d1678cff0f4 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 8 Apr 2024 16:47:49 +0200 Subject: [PATCH 047/205] JVM arguments go IN JAVA_OPTS --- molecule/default/converge.yml | 2 +- roles/keycloak_quarkus/README.md | 4 +++- roles/keycloak_quarkus/defaults/main.yml | 7 ++++++- roles/keycloak_quarkus/meta/argument_specs.yml | 12 ++++++++++-- .../keycloak_quarkus/templates/keycloak-sysconfig.j2 | 2 +- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index 5927ff9..07cd724 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -52,7 +52,7 @@ pre_tasks: - name: "Retrieve assets server from env" ansible.builtin.set_fact: - assets_server: "{{ lookup('env','MIDDLEWARE_DOWNLOAD_RELEASE_SERVER_URL') }}" + assets_server: "{{ lookup('env', 'MIDDLEWARE_DOWNLOAD_RELEASE_SERVER_URL') }}" - name: "Set offline when assets server from env is defined" ansible.builtin.set_fact: diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 7c01eae..db02574 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -38,7 +38,9 @@ Role Defaults |`keycloak_quarkus_service_pidfile`| Pid file path for service | `/run/keycloak.pid` | |`keycloak_quarkus_jvm_package`| RHEL java package runtime | `java-17-openjdk-headless` | |`keycloak_quarkus_java_home`| JAVA_HOME of installed JRE, leave empty for using specified keycloak_quarkus_jvm_package RPM path | `None` | -|`keycloak_quarkus_java_opts`| Additional JVM options | `-Xms1024m -Xmx2048m` | +|`keycloak_quarkus_java_opts`| Heap memory JVM setting | `-Xms1024m -Xmx2048m` | +|`keycloak_quarkus_java_jvm_opts`| Other JVM settings | same as keycloak | +|`keycloak_quarkus_java_opts`| JVM arguments; if overriden, it takes precedence over `keycloak_quarkus_java_*` | `{{ keycloak_quarkus_java_heap_opts + ' ' + keycloak_quarkus_java_jvm_opts }}` | |`keycloak_quarkus_frontend_url`| Set the base URL for frontend URLs, including scheme, host, port and path | | |`keycloak_quarkus_admin_url`| Set the base URL for accessing the administration console, including scheme, host, port and path | | |`keycloak_quarkus_http_relative_path` | Set the path relative to / for serving resources. The path must start with a / | `/` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index d931cab..6848acf 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -39,7 +39,12 @@ keycloak_quarkus_http_port: 8080 keycloak_quarkus_https_port: 8443 keycloak_quarkus_ajp_port: 8009 keycloak_quarkus_jgroups_port: 7800 -keycloak_quarkus_java_opts: "-Xms1024m -Xmx2048m" +keycloak_quarkus_java_heap_opts: "-Xms1024m -Xmx2048m" +keycloak_quarkus_java_jvm_opts: "-XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 + -Dsun.err.encoding=UTF-8 -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8 -XX:+ExitOnOutOfMemoryError + -Djava.security.egd=file:/dev/urandom -XX:+UseParallelGC -XX:GCTimeRatio=4 + -XX:AdaptiveSizePolicyWeight=90 -XX:FlightRecorderOptions=stackdepth=512" +keycloak_quarkus_java_opts: "{{ keycloak_quarkus_java_heap_opts + ' ' + keycloak_quarkus_java_jvm_opts }}" ### TLS/HTTPS configuration keycloak_quarkus_https_key_file_enabled: false diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index c7cd446..f4b87d7 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -156,9 +156,17 @@ argument_specs: default: 7800 description: "jgroups cluster tcp port" type: "int" - keycloak_quarkus_java_opts: + keycloak_quarkus_java_heap_opts: default: "-Xms1024m -Xmx2048m" - description: "Additional JVM options" + description: "Heap memory JVM setting" + type: "str" + keycloak_quarkus_java_jvm_opts: + default: "-XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.err.encoding=UTF-8 -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8 -XX:+ExitOnOutOfMemoryError -Djava.security.egd=file:/dev/urandom -XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:FlightRecorderOptions=stackdepth=512" + description: "Other JVM settings" + type: "str" + keycloak_quarkus_java_opts: + default: "{{ keycloak_quarkus_java_heap_opts + ' ' + keycloak_quarkus_java_jvm_opts }}" + description: "JVM arguments, by default heap_opts + jvm_opts, if overriden it takes precedence over them" type: "str" keycloak_quarkus_ha_enabled: default: false diff --git a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 index 358794c..2ec71e0 100644 --- a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 +++ b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 @@ -3,4 +3,4 @@ KEYCLOAK_ADMIN={{ keycloak_quarkus_admin_user }} KEYCLOAK_ADMIN_PASSWORD='{{ keycloak_quarkus_admin_pass }}' PATH={{ keycloak_quarkus_java_home | default(keycloak_pkg_java_home, true) }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin JAVA_HOME={{ keycloak_quarkus_java_home | default(keycloak_pkg_java_home, true) }} -JAVA_OPTS_APPEND={{ keycloak_quarkus_java_opts }} +JAVA_OPTS={{ keycloak_quarkus_java_opts }} From 8e2f3eb77f0687c12761305205b16c5efdfeaaaf Mon Sep 17 00:00:00 2001 From: Christian Iuga Date: Mon, 15 Apr 2024 14:41:56 +0200 Subject: [PATCH 048/205] Permit parse reverse proxy headers - Via created a new optional variable : keycloak_quarkus_proxy_headers - Fix enhancement #183 - see https://www.keycloak.org/server/reverseproxy about the official documentation --- roles/keycloak_quarkus/README.md | 2 +- roles/keycloak_quarkus/templates/keycloak.service.j2 | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index db02574..d6fa46d 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -54,7 +54,7 @@ Role Defaults |`keycloak_quarkus_https_trust_store_enabled`| Enalbe confiugration of a trust store | `False` | |`keycloak_quarkus_trust_store_file`| The file pat to the trust store | `{{ keycloak.home }}/conf/trust_store.p12` | |`keycloak_quarkus_trust_store_password`| Password for the trust store | `""` | - +|`keycloak_quarkus_proxy_headers`| Parse reverse proxy headers (`forwarded` or `xforwardedPassword`) | `""` | * Hostname configuration diff --git a/roles/keycloak_quarkus/templates/keycloak.service.j2 b/roles/keycloak_quarkus/templates/keycloak.service.j2 index 3cdfacf..77395c6 100644 --- a/roles/keycloak_quarkus/templates/keycloak.service.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.service.j2 @@ -8,10 +8,10 @@ Type=simple EnvironmentFile=-{{ keycloak_quarkus_sysconf_file }} PIDFile={{ keycloak_quarkus_service_pidfile }} {% if keycloak_quarkus_start_dev %} -ExecStart={{ keycloak.home }}/bin/kc.sh start-dev -{% else %} -ExecStart={{ keycloak.home }}/bin/kc.sh start --optimized -{% endif %} +ExecStart={{ keycloak.home }}/bin/kc.sh start-dev{% if keycloak_quarkus_proxy_headers is defined %} --proxy-headers {{ keycloak_quarkus_proxy_headers }}{% endif -%}{{ '\n' }} +{% else -%} +ExecStart={{ keycloak.home }}/bin/kc.sh start --optimized{% if keycloak_quarkus_proxy_headers is defined %} --proxy-headers {{ keycloak_quarkus_proxy_headers }}{% endif -%}{{ '\n' }} +{%- endif %} User={{ keycloak.service_user }} Group={{ keycloak.service_group }} {% if keycloak_quarkus_service_restart_always %} From 4aa862101c2f3b566686b8c77ea9d95407acb80e Mon Sep 17 00:00:00 2001 From: Christian Iuga Date: Mon, 15 Apr 2024 15:48:02 +0200 Subject: [PATCH 049/205] Add new variable keycloak_quarkus_proxy_headers into meta/argument_specs.yml Fix comment https://github.com/ansible-middleware/keycloak/pull/187#discussion_r1565772058 --- roles/keycloak_quarkus/meta/argument_specs.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index f4b87d7..36f5adc 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -285,6 +285,10 @@ argument_specs: default: 'edge' type: "str" description: "The proxy address forwarding mode if the server is behind a reverse proxy. Set to 'none' if not using a proxy" + keycloak_quarkus_proxy_headers: + default: "" + type: "str" + description: "Parse reverse proxy headers (`forwarded` or `xforwardedPassword`), overrides the deprecated keycloak_quarkus_proxy_mode argument" keycloak_quarkus_start_dev: default: false type: "bool" From 27717d7b4eef4696dba6db8d3499c02782270854 Mon Sep 17 00:00:00 2001 From: Christian Iuga Date: Mon, 15 Apr 2024 15:50:55 +0200 Subject: [PATCH 050/205] Avoid cmd-line arguments Fix https://github.com/ansible-middleware/keycloak/pull/187#discussion_r1565779164 --- roles/keycloak_quarkus/templates/keycloak.service.j2 | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/roles/keycloak_quarkus/templates/keycloak.service.j2 b/roles/keycloak_quarkus/templates/keycloak.service.j2 index 77395c6..46c7f34 100644 --- a/roles/keycloak_quarkus/templates/keycloak.service.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.service.j2 @@ -7,11 +7,15 @@ After=network.target Type=simple EnvironmentFile=-{{ keycloak_quarkus_sysconf_file }} PIDFile={{ keycloak_quarkus_service_pidfile }} -{% if keycloak_quarkus_start_dev %} -ExecStart={{ keycloak.home }}/bin/kc.sh start-dev{% if keycloak_quarkus_proxy_headers is defined %} --proxy-headers {{ keycloak_quarkus_proxy_headers }}{% endif -%}{{ '\n' }} +{% if keycloak_quarkus_start_dev and keycloak_quarkus_proxy_headers is defined %} +ExecStart={{ keycloak.home }}/bin/kc.sh start-dev --proxy-headers {{ keycloak_quarkus_proxy_headers }} +{% elif keycloak_quarkus_start_dev and keycloak_quarkus_proxy_headers is not defined %} +ExecStart={{ keycloak.home }}/bin/kc.sh start-dev +{% elif not keycloak_quarkus_start_dev and keycloak_quarkus_proxy_headers is defined %} +ExecStart={{ keycloak.home }}/bin/kc.sh start --optimized --proxy-headers {{ keycloak_quarkus_proxy_headers }} {% else -%} -ExecStart={{ keycloak.home }}/bin/kc.sh start --optimized{% if keycloak_quarkus_proxy_headers is defined %} --proxy-headers {{ keycloak_quarkus_proxy_headers }}{% endif -%}{{ '\n' }} -{%- endif %} +ExecStart={{ keycloak.home }}/bin/kc.sh start --optimized +{% endif %} User={{ keycloak.service_user }} Group={{ keycloak.service_group }} {% if keycloak_quarkus_service_restart_always %} From 3fbae4882e0d2c058cd42ee2cfd6b0b41f7a29f8 Mon Sep 17 00:00:00 2001 From: Christian Iuga Date: Tue, 16 Apr 2024 13:39:33 +0200 Subject: [PATCH 051/205] move keycloak_quarkus_proxy_headers into keycloak.conf --- roles/keycloak_quarkus/templates/keycloak.conf.j2 | 7 ++++++- roles/keycloak_quarkus/templates/keycloak.service.j2 | 6 +----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index b23a250..20d3f7f 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -54,9 +54,14 @@ cache-config-file=cache-ispn.xml {% endif %} {% if keycloak_quarkus_proxy_mode is defined and keycloak_quarkus_proxy_mode != "none" %} -# Proxy +# Deprecated Proxy configuration proxy={{ keycloak_quarkus_proxy_mode }} {% endif %} +{% if keycloak_quarkus_proxy_headers is defined and keycloak_quarkus_proxy_headers != "none" %} +# Proxy +proxy-headers={{ keycloak_quarkus_proxy_headers }} +{% endif %} + spi-sticky-session-encoder-infinispan-should-attach-route={{ keycloak_quarkus_spi_sticky_session_encoder_infinispan_should_attach_route | d(true) | lower }} # Transaction diff --git a/roles/keycloak_quarkus/templates/keycloak.service.j2 b/roles/keycloak_quarkus/templates/keycloak.service.j2 index 46c7f34..30f4273 100644 --- a/roles/keycloak_quarkus/templates/keycloak.service.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.service.j2 @@ -7,12 +7,8 @@ After=network.target Type=simple EnvironmentFile=-{{ keycloak_quarkus_sysconf_file }} PIDFile={{ keycloak_quarkus_service_pidfile }} -{% if keycloak_quarkus_start_dev and keycloak_quarkus_proxy_headers is defined %} -ExecStart={{ keycloak.home }}/bin/kc.sh start-dev --proxy-headers {{ keycloak_quarkus_proxy_headers }} -{% elif keycloak_quarkus_start_dev and keycloak_quarkus_proxy_headers is not defined %} +{% if keycloak_quarkus_start_dev %} ExecStart={{ keycloak.home }}/bin/kc.sh start-dev -{% elif not keycloak_quarkus_start_dev and keycloak_quarkus_proxy_headers is defined %} -ExecStart={{ keycloak.home }}/bin/kc.sh start --optimized --proxy-headers {{ keycloak_quarkus_proxy_headers }} {% else -%} ExecStart={{ keycloak.home }}/bin/kc.sh start --optimized {% endif %} From ea57f8b68942a0c4f07b371bdc9f893242a55667 Mon Sep 17 00:00:00 2001 From: Christian Iuga Date: Tue, 16 Apr 2024 13:41:09 +0200 Subject: [PATCH 052/205] remove unwanted extra code --- roles/keycloak_quarkus/templates/keycloak.service.j2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/keycloak_quarkus/templates/keycloak.service.j2 b/roles/keycloak_quarkus/templates/keycloak.service.j2 index 30f4273..3cdfacf 100644 --- a/roles/keycloak_quarkus/templates/keycloak.service.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.service.j2 @@ -9,7 +9,7 @@ EnvironmentFile=-{{ keycloak_quarkus_sysconf_file }} PIDFile={{ keycloak_quarkus_service_pidfile }} {% if keycloak_quarkus_start_dev %} ExecStart={{ keycloak.home }}/bin/kc.sh start-dev -{% else -%} +{% else %} ExecStart={{ keycloak.home }}/bin/kc.sh start --optimized {% endif %} User={{ keycloak.service_user }} From 1229a0b0231fe837a77ed2b03866da7c7a0c4c57 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 10:46:23 +0200 Subject: [PATCH 053/205] Unrelax configuration file permissions --- roles/keycloak_quarkus/tasks/install.yml | 6 +++--- roles/keycloak_quarkus/tasks/jdbc_driver.yml | 2 +- roles/keycloak_quarkus/tasks/main.yml | 8 ++++---- roles/keycloak_quarkus/tasks/systemd.yml | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index 0162266..3cf4b55 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -31,7 +31,7 @@ state: directory owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" - mode: 0750 + mode: '0750' ## check remote archive - name: Set download archive path @@ -56,7 +56,7 @@ ansible.builtin.get_url: # noqa risky-file-permissions delegated, uses controller host user url: "{{ keycloak_quarkus_download_url }}" dest: "{{ local_path.stat.path }}/{{ keycloak.bundle }}" - mode: 0640 + mode: '0640' delegate_to: localhost become: false run_once: true @@ -118,7 +118,7 @@ dest: "{{ archive }}" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" - mode: 0640 + mode: '0640' register: new_version_downloaded when: - not archive_path.stat.exists diff --git a/roles/keycloak_quarkus/tasks/jdbc_driver.yml b/roles/keycloak_quarkus/tasks/jdbc_driver.yml index 0d03030..c95ef2b 100644 --- a/roles/keycloak_quarkus/tasks/jdbc_driver.yml +++ b/roles/keycloak_quarkus/tasks/jdbc_driver.yml @@ -6,7 +6,7 @@ dest: "{{ keycloak.home }}/providers" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" - mode: 0640 + mode: '0640' become: true notify: - restart keycloak diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index decb63b..ad97709 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -27,7 +27,7 @@ dest: "{{ keycloak.home }}/conf/keycloak.conf" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" - mode: 0644 + mode: '0640' become: true notify: - rebuild keycloak config @@ -39,7 +39,7 @@ dest: "{{ keycloak.home }}/conf/quarkus.properties" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" - mode: 0644 + mode: '0640' become: true notify: - restart keycloak @@ -64,7 +64,7 @@ dest: "{{ keycloak.home }}/conf/cache-ispn.xml" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" - mode: 0644 + mode: '0640' become: true notify: - rebuild keycloak config @@ -76,7 +76,7 @@ path: "{{ keycloak.log.file | dirname }}" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" - mode: 0775 + mode: '0775' become: true - name: Flush pending handlers diff --git a/roles/keycloak_quarkus/tasks/systemd.yml b/roles/keycloak_quarkus/tasks/systemd.yml index 58dbc7e..fcc1a71 100644 --- a/roles/keycloak_quarkus/tasks/systemd.yml +++ b/roles/keycloak_quarkus/tasks/systemd.yml @@ -6,7 +6,7 @@ dest: "{{ keycloak_quarkus_sysconf_file }}" owner: root group: root - mode: 0644 + mode: '0640' vars: keycloak_pkg_java_home: "{{ keycloak_quarkus_pkg_java_home }}" notify: @@ -18,7 +18,7 @@ dest: /etc/systemd/system/keycloak.service owner: root group: root - mode: 0644 + mode: '0644' become: true register: systemdunit notify: From ad6021c29a104447dc4d5429dca5b75cee7900bd Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Wed, 17 Apr 2024 08:58:43 +0000 Subject: [PATCH 054/205] Update changelog for release 2.1.1 Signed-off-by: ansible-middleware-core --- CHANGELOG.rst | 18 ++++++++++++++++++ changelogs/changelog.yaml | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 15c2fbf..ce72edf 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,24 @@ middleware\_automation.keycloak Release Notes This changelog describes changes after version 0.2.6. +v2.1.1 +====== + +Minor Changes +------------- + +- Add reverse ``proxy_headers`` config, supersedes ``proxy_mode`` `#187 `_ +- Debian/Ubuntu compatibility `#178 `_ +- Use ``keycloak_realm`` as default for sub-entities `#180 `_ + +Bugfixes +-------- + +- Fix permissions on controller-side downloaded artifacts `#184 `_ +- JVM args moved to ``JAVA_OPTS`` envvar (instead of JAVA_OPTS_APPEND) `#186 `_ +- Unrelax configuration file permissions `#191 `_ +- Utilize comment filter for ``ansible_managed`` annotations `#176 `_ + v2.1.0 ====== diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index dd44253..a8ed730 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -419,3 +419,38 @@ releases: - 167.yaml - 171.yaml release_date: '2024-02-28' + 2.1.1: + changes: + bugfixes: + - 'Fix permissions on controller-side downloaded artifacts `#184 `_ + + ' + - 'JVM args moved to ``JAVA_OPTS`` envvar (instead of JAVA_OPTS_APPEND) `#186 + `_ + + ' + - 'Unrelax configuration file permissions `#191 `_ + + ' + - 'Utilize comment filter for ``ansible_managed`` annotations `#176 `_ + + ' + minor_changes: + - 'Add reverse ``proxy_headers`` config, supersedes ``proxy_mode`` `#187 `_ + + ' + - 'Debian/Ubuntu compatibility `#178 `_ + + ' + - 'Use ``keycloak_realm`` as default for sub-entities `#180 `_ + + ' + fragments: + - 176.yaml + - 178.yaml + - 180.yaml + - 184.yaml + - 186.yaml + - 187.yaml + - 191.yaml + release_date: '2024-04-17' From 2cf3e2470dab694e03926d8224d2d39d8a9b7654 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Wed, 17 Apr 2024 08:58:56 +0000 Subject: [PATCH 055/205] Bump version to 2.1.2 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index dd55345..a1e9cdb 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.1.1" +version: "2.1.2" readme: README.md authors: - Romain Pelisse From 5464a01a627b6f36e6b18b7e8dae7af630c1fec8 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 11:08:04 +0200 Subject: [PATCH 056/205] ci: update doc links, test triggers --- .github/workflows/release.yml | 4 +++- docs/_gh_include/header.inc | 17 +++++++++-------- docs/index.rst | 17 +++++++++-------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7ea4aab..9dbf255 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,14 +8,16 @@ jobs: uses: ansible-middleware/github-actions/.github/workflows/release.yml@main with: collection_fqcn: 'middleware_automation.keycloak' + downstream_name: 'rhbk' secrets: galaxy_token: ${{ secrets.ANSIBLE_GALAXY_API_KEY }} + jira_webhook: ${{ secrets.JIRA_WEBHOOK_CREATE_VERSION }} dispatch: needs: release strategy: matrix: - repo: ['ansible-middleware/cross-dc-rhsso-demo', 'ansible-middleware/flange-demo', 'ansible-middleware/ansible-middleware-ee'] + repo: ['ansible-middleware/ansible-middleware-ee'] runs-on: ubuntu-latest steps: - name: Repository Dispatch diff --git a/docs/_gh_include/header.inc b/docs/_gh_include/header.inc index 7c5103b..d97c7f1 100644 --- a/docs/_gh_include/header.inc +++ b/docs/_gh_include/header.inc @@ -24,14 +24,15 @@ diff --git a/docs/index.rst b/docs/index.rst index 6d8670c..38dec5b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -29,11 +29,12 @@ Welcome to Keycloak Collection documentation :maxdepth: 2 :caption: Middleware collections - Infinispan / Red Hat Data Grid - Keycloak / Red Hat Single Sign-On - Wildfly / Red Hat JBoss EAP - Tomcat / Red Hat JWS - ActiveMQ / Red Hat AMQ Broker - Kafka / Red Hat AMQ Streams - Red Hat CSP Download - JCliff + Infinispan / Red Hat Data Grid + Keycloak / Red Hat Single Sign-On + Wildfly / Red Hat JBoss EAP + Tomcat / Red Hat JWS + ActiveMQ / Red Hat AMQ Broker + Kafka / Red Hat AMQ Streams + Ansible Middleware utilities + Red Hat CSP Download + JCliff From 7bedb08f6eebde9caa8aacfdc628f54ac34ad32d Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 11:14:38 +0200 Subject: [PATCH 057/205] ci: update release wf params --- .github/workflows/release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9dbf255..d0d14d8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,6 +2,10 @@ name: Release collection on: workflow_dispatch: + inputs: + release_summary: + description: 'Optional release summary for changelogs' + required: false jobs: release: @@ -9,6 +13,7 @@ jobs: with: collection_fqcn: 'middleware_automation.keycloak' downstream_name: 'rhbk' + release_summary: "${{ github.event.inputs.release_summary }}" secrets: galaxy_token: ${{ secrets.ANSIBLE_GALAXY_API_KEY }} jira_webhook: ${{ secrets.JIRA_WEBHOOK_CREATE_VERSION }} From 0c0c4e19eaeeca0e4450b1dbf6c33d4ef9725d77 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 11:57:44 +0200 Subject: [PATCH 058/205] downstream: update rhbk to 2.0.10 --- galaxy.yml | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy.yml b/galaxy.yml index a1e9cdb..dd55345 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.1.2" +version: "2.1.1" readme: README.md authors: - Romain Pelisse diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 36f5adc..da32de0 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -312,7 +312,7 @@ argument_specs: downstream: options: rhbk_version: - default: "22.0.6" + default: "22.0.10" description: "Red Hat Build of Keycloak version" type: "str" rhbk_archive: From 1ff6f237a904326b5efb0fea38a03698938a1209 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 11:58:11 +0200 Subject: [PATCH 059/205] Bump 2.1.1 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index dd55345..a1e9cdb 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.1.1" +version: "2.1.2" readme: README.md authors: - Romain Pelisse From d17c36425763d3ff0899d25e20478dee334ba6ec Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 12:14:25 +0200 Subject: [PATCH 060/205] downstream: ci sudo workaround --- galaxy.yml | 2 +- molecule/quarkus/prepare.yml | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/galaxy.yml b/galaxy.yml index a1e9cdb..dd55345 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.1.2" +version: "2.1.1" readme: README.md authors: - Romain Pelisse diff --git a/molecule/quarkus/prepare.yml b/molecule/quarkus/prepare.yml index 89ac436..03e5b89 100644 --- a/molecule/quarkus/prepare.yml +++ b/molecule/quarkus/prepare.yml @@ -2,15 +2,10 @@ - name: Prepare hosts: all tasks: - - name: Install sudo - ansible.builtin.package: - name: sudo - state: present - - name: "Display hera_home if defined." ansible.builtin.set_fact: hera_home: "{{ lookup('env', 'HERA_HOME') }}" - + - name: "Ensure common prepare phase are set." ansible.builtin.include_tasks: ../prepare.yml From 1f910bd40066b080d8d4ea28f585026afe79b3ca Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 15:45:11 +0200 Subject: [PATCH 061/205] Comprehensive linter warning fixes --- galaxy.yml | 1 - molecule/prepare.yml | 5 ++-- molecule/quarkus-devmode/prepare.yml | 6 ++--- roles/keycloak_quarkus/defaults/main.yml | 6 +++-- roles/keycloak_quarkus/handlers/main.yml | 2 +- .../keycloak_quarkus/meta/argument_specs.yml | 25 ++++++++++++++----- roles/keycloak_quarkus/tasks/fastpackages.yml | 7 +++--- roles/keycloak_quarkus/tasks/install.yml | 2 +- roles/keycloak_quarkus/tasks/jdbc_driver.yml | 1 - roles/keycloak_quarkus/tasks/prereqs.yml | 12 +++++---- roles/keycloak_quarkus/tasks/systemd.yml | 2 +- .../templates/keycloak-sysconfig.j2 | 4 +-- roles/keycloak_quarkus/vars/debian.yml | 2 +- roles/keycloak_realm/defaults/main.yml | 16 ++++++------ roles/keycloak_realm/meta/argument_specs.yml | 2 +- .../tasks/manage_client_users.yml | 2 +- .../tasks/manage_user_client_roles.yml | 8 ++++-- 17 files changed, 62 insertions(+), 41 deletions(-) diff --git a/galaxy.yml b/galaxy.yml index dd55345..2e996a0 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -35,7 +35,6 @@ issues: https://github.com/ansible-middleware/keycloak/issues build_ignore: - .gitignore - .github - - .ansible-lint - .yamllint - '*.tar.gz' - '*.zip' diff --git a/molecule/prepare.yml b/molecule/prepare.yml index f122f9d..27486a3 100644 --- a/molecule/prepare.yml +++ b/molecule/prepare.yml @@ -25,7 +25,7 @@ fail_msg: "sudo is not installed on target system" - name: "Install iproute" - become: yes + become: true ansible.builtin.yum: name: - iproute @@ -33,7 +33,7 @@ - name: "Retrieve assets server from env" ansible.builtin.set_fact: - assets_server: "{{ lookup('env','MIDDLEWARE_DOWNLOAD_RELEASE_SERVER_URL') }}" + assets_server: "{{ lookup('env', 'MIDDLEWARE_DOWNLOAD_RELEASE_SERVER_URL') }}" - name: "Download artefacts only if assets_server is set" when: @@ -51,6 +51,7 @@ url: "{{ asset }}" dest: "{{ lookup('env', 'PWD') }}" validate_certs: no + mode: '0644' delegate_to: localhost loop: "{{ assets }}" loop_control: diff --git a/molecule/quarkus-devmode/prepare.yml b/molecule/quarkus-devmode/prepare.yml index 3a9bcb9..9ce721e 100644 --- a/molecule/quarkus-devmode/prepare.yml +++ b/molecule/quarkus-devmode/prepare.yml @@ -30,11 +30,11 @@ src: "{{ item }}" dest: /opt/openjdk force: true - with_fileglob: - - /usr/lib/jvm/java-17-openjdk* + with_fileglob: + - /usr/lib/jvm/java-17-openjdk* when: - ansible_facts.os_family == "Debian" - + - name: Link default logs directory ansible.builtin.file: state: link diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 6848acf..5821aca 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -86,7 +86,8 @@ keycloak_quarkus_proxy_mode: edge # disable xa transactions keycloak_quarkus_transaction_xa_enabled: true -# If the route should be attached to cookies to reflect the node that owns a particular session. If false, route is not attached to cookies and we rely on the session affinity capabilities from reverse proxy +# If the route should be attached to cookies to reflect the node that owns a particular session. +# If false, route is not attached to cookies and we rely on the session affinity capabilities from reverse proxy keycloak_quarkus_spi_sticky_session_encoder_infinispan_should_attach_route: true keycloak_quarkus_metrics_enabled: false @@ -120,7 +121,8 @@ keycloak_quarkus_default_jdbc: mssql: url: 'jdbc:sqlserver://localhost:1433;databaseName=keycloak;' version: 12.2.0 - driver_jar_url: "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/12.2.0.jre11/mssql-jdbc-12.2.0.jre11.jar" # cf. https://access.redhat.com/documentation/en-us/red_hat_build_of_keycloak/22.0/html/server_guide/db-#db-installing-the-microsoft-sql-server-driver + driver_jar_url: "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/12.2.0.jre11/mssql-jdbc-12.2.0.jre11.jar" + # cf. https://access.redhat.com/documentation/en-us/red_hat_build_of_keycloak/22.0/html/server_guide/db-#db-installing-the-microsoft-sql-server-driver ### logging configuration keycloak_quarkus_log: file keycloak_quarkus_log_level: info diff --git a/roles/keycloak_quarkus/handlers/main.yml b/roles/keycloak_quarkus/handlers/main.yml index 6cbe276..82e229b 100644 --- a/roles/keycloak_quarkus/handlers/main.yml +++ b/roles/keycloak_quarkus/handlers/main.yml @@ -5,4 +5,4 @@ listen: "rebuild keycloak config" - name: "Restart {{ keycloak.service_name }}" ansible.builtin.include_tasks: restart.yml - listen: "restart keycloak" \ No newline at end of file + listen: "restart keycloak" diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index da32de0..657ebbf 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -161,7 +161,10 @@ argument_specs: description: "Heap memory JVM setting" type: "str" keycloak_quarkus_java_jvm_opts: - default: "-XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.err.encoding=UTF-8 -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8 -XX:+ExitOnOutOfMemoryError -Djava.security.egd=file:/dev/urandom -XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:FlightRecorderOptions=stackdepth=512" + default: > + -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.err.encoding=UTF-8 + -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8 -XX:+ExitOnOutOfMemoryError -Djava.security.egd=file:/dev/urandom -XX:+UseParallelGC + -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:FlightRecorderOptions=stackdepth=512 description: "Other JVM settings" type: "str" keycloak_quarkus_java_opts: @@ -272,7 +275,9 @@ argument_specs: keycloak_quarkus_log_max_file_size: default: 10M type: "str" - description: "Set the maximum log file size before a log rotation happens; A size configuration option recognises string in this format (shown as a regular expression): [0-9]+[KkMmGgTtPpEeZzYy]?. If no suffix is given, assume bytes." + description: > + Set the maximum log file size before a log rotation happens; A size configuration option recognises string in this format (shown as a regular + expression): [0-9]+[KkMmGgTtPpEeZzYy]?. If no suffix is given, assume bytes. keycloak_quarkus_log_max_backup_index: default: 10 type: "str" @@ -280,7 +285,9 @@ argument_specs: keycloak_quarkus_log_file_suffix: default: '.yyyy-MM-dd.zip' type: "str" - description: "Set the log file handler rotation file suffix. When used, the file will be rotated based on its suffix; Note: If the suffix ends with .zip or .gz, the rotation file will also be compressed." + description: > + Set the log file handler rotation file suffix. When used, the file will be rotated based on its suffix. Note: If the suffix ends + with .zip or .gz, the rotation file will also be compressed. keycloak_quarkus_proxy_mode: default: 'edge' type: "str" @@ -300,15 +307,21 @@ argument_specs: keycloak_quarkus_hostname_strict: default: true type: "bool" - description: "Disables dynamically resolving the hostname from request headers. Should always be set to true in production, unless proxy verifies the Host header." + description: > + Disables dynamically resolving the hostname from request headers. Should always be set to true in production, unless + proxy verifies the Host header. keycloak_quarkus_hostname_strict_backchannel: default: false type: "bool" - description: "By default backchannel URLs are dynamically resolved from request headers to allow internal and external applications. If all applications use the public URL this option should be enabled." + description: > + By default backchannel URLs are dynamically resolved from request headers to allow internal and external applications. If all + applications use the public URL this option should be enabled. keycloak_quarkus_spi_sticky_session_encoder_infinispan_should_attach_route: default: true type: "bool" - description: "If the route should be attached to cookies to reflect the node that owns a particular session. If false, route is not attached to cookies and we rely on the session affinity capabilities from reverse proxy" + description: > + If the route should be attached to cookies to reflect the node that owns a particular session. If false, route is not attached to cookies + and we rely on the session affinity capabilities from reverse proxy downstream: options: rhbk_version: diff --git a/roles/keycloak_quarkus/tasks/fastpackages.yml b/roles/keycloak_quarkus/tasks/fastpackages.yml index 5affe64..9dc1621 100644 --- a/roles/keycloak_quarkus/tasks/fastpackages.yml +++ b/roles/keycloak_quarkus/tasks/fastpackages.yml @@ -8,7 +8,8 @@ - name: "Add missing packages to the yum install list" ansible.builtin.set_fact: - packages_to_install: "{{ packages_to_install | default([]) + rpm_info.stdout_lines | map('regex_findall', 'package (.+) is not installed$') | default([]) | flatten }}" + packages_to_install: "{{ packages_to_install | default([]) + rpm_info.stdout_lines | \ + map('regex_findall', 'package (.+) is not installed$') | default([]) | flatten }}" when: ansible_facts.os_family == "RedHat" - name: "Install packages: {{ packages_to_install }}" @@ -17,8 +18,8 @@ name: "{{ packages_to_install }}" state: present when: - - packages_to_install | default([]) | length > 0 - - ansible_facts.os_family == "RedHat" + - packages_to_install | default([]) | length > 0 + - ansible_facts.os_family == "RedHat" - name: "Install packages: {{ packages_list }}" become: true diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index 3cf4b55..cc2aa7f 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -132,7 +132,7 @@ register: path_to_workdir become: true -- name: "Extract Keycloak archive on target" +- name: "Extract Keycloak archive on target" # noqa no-handler need to run this here ansible.builtin.unarchive: remote_src: true src: "{{ archive }}" diff --git a/roles/keycloak_quarkus/tasks/jdbc_driver.yml b/roles/keycloak_quarkus/tasks/jdbc_driver.yml index c95ef2b..310509a 100644 --- a/roles/keycloak_quarkus/tasks/jdbc_driver.yml +++ b/roles/keycloak_quarkus/tasks/jdbc_driver.yml @@ -1,5 +1,4 @@ --- - - name: "Retrieve JDBC Driver from {{ keycloak_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url }}" ansible.builtin.get_url: url: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url }}" diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index a9fbeaa..d344e98 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -4,7 +4,7 @@ that: - keycloak_quarkus_admin_pass | length > 12 quiet: true - fail_msg: "The console administrator password is empty or invalid. Please set the keycloak_quarkus_admin_pass variable to a 12+ char long string" + fail_msg: "The console administrator password is empty or invalid. Please set the keycloak_quarkus_admin_pass to a 12+ char long string" success_msg: "{{ 'Console administrator password OK' }}" - name: Validate relative path @@ -12,15 +12,17 @@ that: - keycloak_quarkus_http_relative_path is regex('^/.*') quiet: true - fail_msg: "the relative path must begin with /" - success_msg: "{{ 'relative path OK' }}" + fail_msg: "The relative path for keycloak_quarkus_http_relative_path must begin with /" + success_msg: "{{ 'Relative path OK' }}" - name: Validate configuration ansible.builtin.assert: that: - - (keycloak_quarkus_ha_enabled and keycloak_quarkus_db_enabled) or (not keycloak_quarkus_ha_enabled and keycloak_quarkus_db_enabled) or (not keycloak_quarkus_ha_enabled and not keycloak_quarkus_db_enabled) + - (keycloak_quarkus_ha_enabled and keycloak_quarkus_db_enabled) or + (not keycloak_quarkus_ha_enabled and keycloak_quarkus_db_enabled) or + (not keycloak_quarkus_ha_enabled and not keycloak_quarkus_db_enabled) quiet: true - fail_msg: "Cannot install HA setup without a backend database service. Check keycloak_quarkus_ha_enabled and keycloak_quarkus_db_enabled" + fail_msg: "HA setup requires a backend database service. Check keycloak_quarkus_ha_enabled and keycloak_quarkus_db_enabled" success_msg: "{{ 'Configuring HA' if keycloak_quarkus_ha_enabled else 'Configuring standalone' }}" - name: Validate OS family diff --git a/roles/keycloak_quarkus/tasks/systemd.yml b/roles/keycloak_quarkus/tasks/systemd.yml index fcc1a71..47f0570 100644 --- a/roles/keycloak_quarkus/tasks/systemd.yml +++ b/roles/keycloak_quarkus/tasks/systemd.yml @@ -8,7 +8,7 @@ group: root mode: '0640' vars: - keycloak_pkg_java_home: "{{ keycloak_quarkus_pkg_java_home }}" + keycloak_sys_pkg_java_home: "{{ keycloak_quarkus_pkg_java_home }}" notify: - restart keycloak diff --git a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 index 2ec71e0..4667596 100644 --- a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 +++ b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 @@ -1,6 +1,6 @@ {{ ansible_managed | comment }} KEYCLOAK_ADMIN={{ keycloak_quarkus_admin_user }} KEYCLOAK_ADMIN_PASSWORD='{{ keycloak_quarkus_admin_pass }}' -PATH={{ keycloak_quarkus_java_home | default(keycloak_pkg_java_home, true) }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -JAVA_HOME={{ keycloak_quarkus_java_home | default(keycloak_pkg_java_home, true) }} +PATH={{ keycloak_quarkus_java_home | default(keycloak_sys_pkg_java_home, true) }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +JAVA_HOME={{ keycloak_quarkus_java_home | default(keycloak_sys_pkg_java_home, true) }} JAVA_OPTS={{ keycloak_quarkus_java_opts }} diff --git a/roles/keycloak_quarkus/vars/debian.yml b/roles/keycloak_quarkus/vars/debian.yml index a42eb5f..e63c0d1 100644 --- a/roles/keycloak_quarkus/vars/debian.yml +++ b/roles/keycloak_quarkus/vars/debian.yml @@ -1,7 +1,7 @@ --- keycloak_quarkus_varjvm_package: "{{ keycloak_quarkus_jvm_package | default('openjdk-17-jdk-headless') }}" keycloak_quarkus_prereq_package_list: - - "{{ keycloak_quarkus_varjvm_package }}" + - "{{ keycloak_quarkus_varjvm_package }}" - unzip - procps - apt diff --git a/roles/keycloak_realm/defaults/main.yml b/roles/keycloak_realm/defaults/main.yml index c396481..e488207 100644 --- a/roles/keycloak_realm/defaults/main.yml +++ b/roles/keycloak_realm/defaults/main.yml @@ -26,14 +26,14 @@ keycloak_admin_password: '' # and users is a list of account, see below for the format definition # an empty name will skip the creation of the client # -#keycloak_clients: -# - name: '' -# roles: "{{ keycloak_client_default_roles }}" -# realm: "{{ keycloak_realm }}" -# public_client: "{{ keycloak_client_public }}" -# web_origins: "{{ keycloak_client_web_origins }}" -# redirect_uris: "{{ keycloak_client_redirect_uris }}" -# users: "{{ keycloak_client_users }}" +# keycloak_clients: +# - name: '' +# roles: "{{ keycloak_client_default_roles }}" +# realm: "{{ keycloak_realm }}" +# public_client: "{{ keycloak_client_public }}" +# web_origins: "{{ keycloak_client_web_origins }}" +# redirect_uris: "{{ keycloak_client_redirect_uris }}" +# users: "{{ keycloak_client_users }}" keycloak_clients: [] # list of roles to create in the client diff --git a/roles/keycloak_realm/meta/argument_specs.yml b/roles/keycloak_realm/meta/argument_specs.yml index ca174dc..ed87ee6 100644 --- a/roles/keycloak_realm/meta/argument_specs.yml +++ b/roles/keycloak_realm/meta/argument_specs.yml @@ -10,7 +10,7 @@ argument_specs: # line 5 of keycloak_realm/defaults/main.yml default: "/auth" description: "Context path for rest calls" - type: "str" + type: "str" keycloak_http_port: # line 4 of keycloak_realm/defaults/main.yml default: 8080 diff --git a/roles/keycloak_realm/tasks/manage_client_users.yml b/roles/keycloak_realm/tasks/manage_client_users.yml index ed9fb03..5234cb1 100644 --- a/roles/keycloak_realm/tasks/manage_client_users.yml +++ b/roles/keycloak_realm/tasks/manage_client_users.yml @@ -10,4 +10,4 @@ loop: "{{ client.users | flatten }}" loop_control: loop_var: user - when: "'client_roles' in user" \ No newline at end of file + when: "'client_roles' in user" diff --git a/roles/keycloak_realm/tasks/manage_user_client_roles.yml b/roles/keycloak_realm/tasks/manage_user_client_roles.yml index 4311daa..3884f42 100644 --- a/roles/keycloak_realm/tasks/manage_user_client_roles.yml +++ b/roles/keycloak_realm/tasks/manage_user_client_roles.yml @@ -12,7 +12,9 @@ - name: Check if Mapping is available ansible.builtin.uri: - url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm | default(keycloak_realm) }}/users/{{ (keycloak_user.json | first).id }}/role-mappings/clients/{{ (create_client_result.results | selectattr('end_state.clientId', 'equalto', client_role.client) | list | first).end_state.id }}/available" + url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm | \ + default(keycloak_realm) }}/users/{{ (keycloak_user.json | first).id }}/role-mappings/clients/{{ (create_client_result.results | \ + selectattr('end_state.clientId', 'equalto', client_role.client) | list | first).end_state.id }}/available" method: GET status_code: - 200 @@ -23,7 +25,9 @@ - name: "Create Role Mapping" ansible.builtin.uri: - url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm | default(keycloak_realm) }}/users/{{ (keycloak_user.json | first).id }}/role-mappings/clients/{{ (create_client_result.results | selectattr('end_state.clientId', 'equalto', client_role.client) | list | first).end_state.id }}" + url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm | \ + default(keycloak_realm) }}/users/{{ (keycloak_user.json | first).id }}/role-mappings/clients/{{ (create_client_result.results | \ + selectattr('end_state.clientId', 'equalto', client_role.client) | list | first).end_state.id }}" method: POST body: - id: "{{ item.id }}" From 5b459f3ddeeb3f01b3597448bf7900d2aa090f48 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 16:48:24 +0200 Subject: [PATCH 062/205] ci: more linter fixes --- plugins/modules/keycloak_client.py | 2 +- plugins/modules/keycloak_role.py | 16 +- plugins/modules/keycloak_user_federation.py | 180 ++++++++++---------- roles/keycloak_quarkus/tasks/main.yml | 2 +- roles/keycloak_quarkus/tasks/start.yml | 2 +- roles/keycloak_quarkus/vars/debian.yml | 3 +- roles/keycloak_quarkus/vars/main.yml | 5 +- 7 files changed, 106 insertions(+), 104 deletions(-) diff --git a/plugins/modules/keycloak_client.py b/plugins/modules/keycloak_client.py index e1f0e19..dc824ca 100644 --- a/plugins/modules/keycloak_client.py +++ b/plugins/modules/keycloak_client.py @@ -637,7 +637,7 @@ EXAMPLES = ''' - test01 - test02 authentication_flow_binding_overrides: - browser: 4c90336b-bf1d-4b87-916d-3677ba4e5fbb + browser: 4c90336b-bf1d-4b87-916d-3677ba4e5fbb protocol_mappers: - config: access.token.claim: true diff --git a/plugins/modules/keycloak_role.py b/plugins/modules/keycloak_role.py index 0045d0e..558f362 100644 --- a/plugins/modules/keycloak_role.py +++ b/plugins/modules/keycloak_role.py @@ -142,14 +142,14 @@ EXAMPLES = ''' auth_password: PASSWORD name: my-new-role attributes: - attrib1: value1 - attrib2: value2 - attrib3: - - with - - numerous - - individual - - list - - items + attrib1: value1 + attrib2: value2 + attrib3: + - with + - numerous + - individual + - list + - items delegate_to: localhost ''' diff --git a/plugins/modules/keycloak_user_federation.py b/plugins/modules/keycloak_user_federation.py index bc84d8d..08c672e 100644 --- a/plugins/modules/keycloak_user_federation.py +++ b/plugins/modules/keycloak_user_federation.py @@ -475,99 +475,99 @@ author: ''' EXAMPLES = ''' - - name: Create LDAP user federation - middleware_automation.keycloak.keycloak_user_federation: - auth_keycloak_url: https://keycloak.example.com/auth - auth_realm: master - auth_username: admin - auth_password: password - realm: my-realm - name: my-ldap - state: present - provider_id: ldap - provider_type: org.keycloak.storage.UserStorageProvider - config: - priority: 0 - enabled: true - cachePolicy: DEFAULT - batchSizeForSync: 1000 - editMode: READ_ONLY - importEnabled: true - syncRegistrations: false - vendor: other - usernameLDAPAttribute: uid - rdnLDAPAttribute: uid - uuidLDAPAttribute: entryUUID - userObjectClasses: inetOrgPerson, organizationalPerson - connectionUrl: ldaps://ldap.example.com:636 - usersDn: ou=Users,dc=example,dc=com - authType: simple - bindDn: cn=directory reader - bindCredential: password - searchScope: 1 - validatePasswordPolicy: false - trustEmail: false - useTruststoreSpi: ldapsOnly - connectionPooling: true - pagination: true - allowKerberosAuthentication: false - debug: false - useKerberosForPasswordAuthentication: false - mappers: - - name: "full name" - providerId: "full-name-ldap-mapper" - providerType: "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" - config: - ldap.full.name.attribute: cn - read.only: true - write.only: false +- name: Create LDAP user federation + middleware_automation.keycloak.keycloak_user_federation: + auth_keycloak_url: https://keycloak.example.com/auth + auth_realm: master + auth_username: admin + auth_password: password + realm: my-realm + name: my-ldap + state: present + provider_id: ldap + provider_type: org.keycloak.storage.UserStorageProvider + config: + priority: 0 + enabled: true + cachePolicy: DEFAULT + batchSizeForSync: 1000 + editMode: READ_ONLY + importEnabled: true + syncRegistrations: false + vendor: other + usernameLDAPAttribute: uid + rdnLDAPAttribute: uid + uuidLDAPAttribute: entryUUID + userObjectClasses: inetOrgPerson, organizationalPerson + connectionUrl: ldaps://ldap.example.com:636 + usersDn: ou=Users,dc=example,dc=com + authType: simple + bindDn: cn=directory reader + bindCredential: password + searchScope: 1 + validatePasswordPolicy: false + trustEmail: false + useTruststoreSpi: ldapsOnly + connectionPooling: true + pagination: true + allowKerberosAuthentication: false + debug: false + useKerberosForPasswordAuthentication: false + mappers: + - name: "full name" + providerId: "full-name-ldap-mapper" + providerType: "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" + config: + ldap.full.name.attribute: cn + read.only: true + write.only: false - - name: Create Kerberos user federation - middleware_automation.keycloak.keycloak_user_federation: - auth_keycloak_url: https://keycloak.example.com/auth - auth_realm: master - auth_username: admin - auth_password: password - realm: my-realm - name: my-kerberos - state: present - provider_id: kerberos - provider_type: org.keycloak.storage.UserStorageProvider - config: - priority: 0 - enabled: true - cachePolicy: DEFAULT - kerberosRealm: EXAMPLE.COM - serverPrincipal: HTTP/host.example.com@EXAMPLE.COM - keyTab: keytab - allowPasswordAuthentication: false - updateProfileFirstLogin: false +- name: Create Kerberos user federation + middleware_automation.keycloak.keycloak_user_federation: + auth_keycloak_url: https://keycloak.example.com/auth + auth_realm: master + auth_username: admin + auth_password: password + realm: my-realm + name: my-kerberos + state: present + provider_id: kerberos + provider_type: org.keycloak.storage.UserStorageProvider + config: + priority: 0 + enabled: true + cachePolicy: DEFAULT + kerberosRealm: EXAMPLE.COM + serverPrincipal: HTTP/host.example.com@EXAMPLE.COM + keyTab: keytab + allowPasswordAuthentication: false + updateProfileFirstLogin: false - - name: Create sssd user federation - middleware_automation.keycloak.keycloak_user_federation: - auth_keycloak_url: https://keycloak.example.com/auth - auth_realm: master - auth_username: admin - auth_password: password - realm: my-realm - name: my-sssd - state: present - provider_id: sssd - provider_type: org.keycloak.storage.UserStorageProvider - config: - priority: 0 - enabled: true - cachePolicy: DEFAULT +- name: Create sssd user federation + middleware_automation.keycloak.keycloak_user_federation: + auth_keycloak_url: https://keycloak.example.com/auth + auth_realm: master + auth_username: admin + auth_password: password + realm: my-realm + name: my-sssd + state: present + provider_id: sssd + provider_type: org.keycloak.storage.UserStorageProvider + config: + priority: 0 + enabled: true + cachePolicy: DEFAULT - - name: Delete user federation - middleware_automation.keycloak.keycloak_user_federation: - auth_keycloak_url: https://keycloak.example.com/auth - auth_realm: master - auth_username: admin - auth_password: password - realm: my-realm - name: my-federation - state: absent +- name: Delete user federation + middleware_automation.keycloak.keycloak_user_federation: + auth_keycloak_url: https://keycloak.example.com/auth + auth_realm: master + auth_username: admin + auth_password: password + realm: my-realm + name: my-federation + state: absent ''' RETURN = ''' diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index ad97709..44fd3d1 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -73,7 +73,7 @@ - name: Ensure logdirectory exists ansible.builtin.file: state: directory - path: "{{ keycloak.log.file | dirname }}" + path: "{{ keycloak.log.file | dirname }}" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" mode: '0775' diff --git a/roles/keycloak_quarkus/tasks/start.yml b/roles/keycloak_quarkus/tasks/start.yml index 7ccc1b9..a640e89 100644 --- a/roles/keycloak_quarkus/tasks/start.yml +++ b/roles/keycloak_quarkus/tasks/start.yml @@ -13,4 +13,4 @@ register: keycloak_status until: keycloak_status.status == 200 retries: 25 - delay: 10 \ No newline at end of file + delay: 10 diff --git a/roles/keycloak_quarkus/vars/debian.yml b/roles/keycloak_quarkus/vars/debian.yml index e63c0d1..29f190a 100644 --- a/roles/keycloak_quarkus/vars/debian.yml +++ b/roles/keycloak_quarkus/vars/debian.yml @@ -7,4 +7,5 @@ keycloak_quarkus_prereq_package_list: - apt - tzdata keycloak_quarkus_sysconf_file: /etc/default/keycloak -keycloak_quarkus_pkg_java_home: "/usr/lib/jvm/java-{{ keycloak_quarkus_varjvm_package | regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" +keycloak_quarkus_pkg_java_home: "/usr/lib/jvm/java-{{ keycloak_quarkus_varjvm_package | \ + regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" diff --git a/roles/keycloak_quarkus/vars/main.yml b/roles/keycloak_quarkus/vars/main.yml index 0ef6844..6f92f4f 100644 --- a/roles/keycloak_quarkus/vars/main.yml +++ b/roles/keycloak_quarkus/vars/main.yml @@ -1,10 +1,11 @@ --- -keycloak: +keycloak: # noqa var-naming this is an internal dict of interpolated values home: "{{ keycloak_quarkus_home }}" config_dir: "{{ keycloak_quarkus_config_dir }}" bundle: "{{ keycloak_quarkus_archive }}" service_name: "keycloak" - health_url: "http://{{ keycloak_quarkus_host }}:{{ keycloak_quarkus_http_port }}{{ keycloak_quarkus_http_relative_path }}{{ '/' if keycloak_quarkus_http_relative_path | length > 1 else '' }}realms/master/.well-known/openid-configuration" + health_url: "http://{{ keycloak_quarkus_host }}:{{ keycloak_quarkus_http_port }}{{ keycloak_quarkus_http_relative_path }}{{ '/' \ + if keycloak_quarkus_http_relative_path | length > 1 else '' }}realms/master/.well-known/openid-configuration" cli_path: "{{ keycloak_quarkus_home }}/bin/kcadm.sh" service_user: "{{ keycloak_quarkus_service_user }}" service_group: "{{ keycloak_quarkus_service_group }}" From 50d189ee14f0825a80b554be3b833d4f0c32589a Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 16:56:56 +0200 Subject: [PATCH 063/205] ci: more linter fixes --- plugins/modules/keycloak_user_federation.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/modules/keycloak_user_federation.py b/plugins/modules/keycloak_user_federation.py index 08c672e..36fe440 100644 --- a/plugins/modules/keycloak_user_federation.py +++ b/plugins/modules/keycloak_user_federation.py @@ -514,13 +514,13 @@ EXAMPLES = ''' debug: false useKerberosForPasswordAuthentication: false mappers: - - name: "full name" + - name: "full name" providerId: "full-name-ldap-mapper" providerType: "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" config: - ldap.full.name.attribute: cn - read.only: true - write.only: false + ldap.full.name.attribute: cn + read.only: true + write.only: false - name: Create Kerberos user federation middleware_automation.keycloak.keycloak_user_federation: From 921364b451c3bd7459cacc546605711f1eefa685 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 15 Apr 2024 15:28:00 +0200 Subject: [PATCH 064/205] Fix docs --- roles/keycloak_quarkus/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index d6fa46d..098af91 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -38,7 +38,7 @@ Role Defaults |`keycloak_quarkus_service_pidfile`| Pid file path for service | `/run/keycloak.pid` | |`keycloak_quarkus_jvm_package`| RHEL java package runtime | `java-17-openjdk-headless` | |`keycloak_quarkus_java_home`| JAVA_HOME of installed JRE, leave empty for using specified keycloak_quarkus_jvm_package RPM path | `None` | -|`keycloak_quarkus_java_opts`| Heap memory JVM setting | `-Xms1024m -Xmx2048m` | +|`keycloak_quarkus_java_heap_opts`| Heap memory JVM setting | `-Xms1024m -Xmx2048m` | |`keycloak_quarkus_java_jvm_opts`| Other JVM settings | same as keycloak | |`keycloak_quarkus_java_opts`| JVM arguments; if overriden, it takes precedence over `keycloak_quarkus_java_*` | `{{ keycloak_quarkus_java_heap_opts + ' ' + keycloak_quarkus_java_jvm_opts }}` | |`keycloak_quarkus_frontend_url`| Set the base URL for frontend URLs, including scheme, host, port and path | | From 60ca798e1a5f795fe6a9387d8cab97043b0809de Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 15 Apr 2024 15:43:59 +0200 Subject: [PATCH 065/205] Rename `keycloak_quarkus_*_store_*` attributes --- roles/keycloak_quarkus/README.md | 12 ++++--- roles/keycloak_quarkus/defaults/main.yml | 8 ++--- roles/keycloak_quarkus/handlers/main.yml | 5 +++ .../keycloak_quarkus/meta/argument_specs.yml | 16 ++++++--- roles/keycloak_quarkus/tasks/deprecations.yml | 36 +++++++++++++++++++ roles/keycloak_quarkus/tasks/main.yml | 5 +++ .../templates/keycloak.conf.j2 | 8 ++--- 7 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 roles/keycloak_quarkus/tasks/deprecations.yml diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 098af91..a518cca 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -49,11 +49,13 @@ Role Defaults |`keycloak_quarkus_key_file`| The file path to a private key in PEM format | `{{ keycloak.home }}/conf/server.key.pem` | |`keycloak_quarkus_cert_file`| The file path to a server certificate or certificate chain in PEM format | `{{ keycloak.home }}/conf/server.crt.pem` | |`keycloak_quarkus_https_key_store_enabled`| Enable configuration of HTTPS via a key store | `False` | -|`keycloak_quarkus_key_store_file`| The file pat to the key store | `{{ keycloak.home }}/conf/key_store.p12` | -|`keycloak_quarkus_key_store_password`| Password for the key store | `""` | -|`keycloak_quarkus_https_trust_store_enabled`| Enalbe confiugration of a trust store | `False` | -|`keycloak_quarkus_trust_store_file`| The file pat to the trust store | `{{ keycloak.home }}/conf/trust_store.p12` | -|`keycloak_quarkus_trust_store_password`| Password for the trust store | `""` | +|`keycloak_quarkus_key_store_file`| Deprecated, use `keycloak_quarkus_https_key_store_file` instead. || +|`keycloak_quarkus_key_store_password`| Deprecated, use `keycloak_quarkus_https_key_store_password` instead.|| +|`keycloak_quarkus_https_key_store_file`| The file path to the key store | `{{ keycloak.home }}/conf/key_store.p12` | +|`keycloak_quarkus_https_key_store_password`| Password for the key store | `""` | +|`keycloak_quarkus_https_trust_store_enabled`| Enable configuration of the https trust store | `False` | +|`keycloak_quarkus_https_trust_store_file`| The file path to the trust store | `{{ keycloak.home }}/conf/trust_store.p12` | +|`keycloak_quarkus_https_trust_store_password`| Password for the trust store | `""` | |`keycloak_quarkus_proxy_headers`| Parse reverse proxy headers (`forwarded` or `xforwardedPassword`) | `""` | * Hostname configuration diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 5821aca..b1045e8 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -52,12 +52,12 @@ keycloak_quarkus_key_file: "{{ keycloak.home }}/conf/server.key.pem" keycloak_quarkus_cert_file: "{{ keycloak.home }}/conf/server.crt.pem" #### key store configuration keycloak_quarkus_https_key_store_enabled: false -keycloak_quarkus_key_store_file: "{{ keycloak.home }}/conf/key_store.p12" -keycloak_quarkus_key_store_password: '' +keycloak_quarkus_https_key_store_file: "{{ keycloak.home }}/conf/key_store.p12" +keycloak_quarkus_https_key_store_password: '' ##### trust store configuration keycloak_quarkus_https_trust_store_enabled: false -keycloak_quarkus_trust_store_file: "{{ keycloak.home }}/conf/trust_store.p12" -keycloak_quarkus_trust_store_password: '' +keycloak_quarkus_https_trust_store_file: "{{ keycloak.home }}/conf/trust_store.p12" +keycloak_quarkus_https_trust_store_password: '' ### Enable configuration for database backend, clustering and remote caches on infinispan keycloak_quarkus_ha_enabled: false diff --git a/roles/keycloak_quarkus/handlers/main.yml b/roles/keycloak_quarkus/handlers/main.yml index 82e229b..bbdf61c 100644 --- a/roles/keycloak_quarkus/handlers/main.yml +++ b/roles/keycloak_quarkus/handlers/main.yml @@ -6,3 +6,8 @@ - name: "Restart {{ keycloak.service_name }}" ansible.builtin.include_tasks: restart.yml listen: "restart keycloak" +- name: "Print deprecation warning" + ansible.builtin.fail: + msg: "Deprecation warning: you are using the deprecated variable '{{ deprecated_variable | d('NotSet') }}', check docs on how to upgrade." + ignore_errors: True + listen: "print deprecation warning" diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 657ebbf..928d900 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -125,22 +125,30 @@ argument_specs: description: "Enable configuration of HTTPS via a key store" type: "bool" keycloak_quarkus_key_store_file: + default: "" + description: "Deprecated, use `keycloak_quarkus_https_key_store_file` instead." + type: "str" + keycloak_quarkus_key_store_password: + default: "" + description: "Deprecated, use `keycloak_quarkus_https_key_store_password` instead." + type: "str" + keycloak_quarkus_https_key_store_file: default: "{{ keycloak.home }}/conf/key_store.p12" description: "The file path to the key store" type: "str" - keycloak_quarkus_key_store_password: + keycloak_quarkus_https_key_store_password: default: "" description: "Password for the key store" type: "str" keycloak_quarkus_https_trust_store_enabled: default: false - description: "Enalbe confiugration of a trust store" + description: "Enable configuration of the https trust store" type: "bool" - keycloak_quarkus_trust_store_file: + keycloak_quarkus_https_trust_store_file: default: "{{ keycloak.home }}/conf/trust_store.p12" description: "The file path to the trust store" type: "str" - keycloak_quarkus_trust_store_password: + keycloak_quarkus_https_trust_store_password: default: "" description: "Password for the trust store" type: "str" diff --git a/roles/keycloak_quarkus/tasks/deprecations.yml b/roles/keycloak_quarkus/tasks/deprecations.yml new file mode 100644 index 0000000..9fed05e --- /dev/null +++ b/roles/keycloak_quarkus/tasks/deprecations.yml @@ -0,0 +1,36 @@ +--- +- name: keycloak_quarkus_key_store -> keycloak_quarkus_http_key_store renaming + delegate_to: localhost + run_once: true + when: + - keycloak_quarkus_https_key_store_enabled + block: + - name: Ensure backward compatibility for `keycloak_quarkus_key_store_file`, superseded by `keycloak_quarkus_https_key_store_file` + when: + - keycloak_quarkus_key_store_file is defined + - keycloak_quarkus_key_store_file != '' + - keycloak_quarkus_https_key_store_file == keycloak.home + "/conf/key_store.p12" # default value + changed_when: true + ansible.builtin.set_fact: + keycloak_quarkus_https_key_store_file: "{{ keycloak_quarkus_key_store_file }}" + deprecated_variable: "keycloak_quarkus_key_store_file" # read in deprecation handler + notify: + - print deprecation warning + + - name: Flush handlers + meta: flush_handlers + + - name: Ensure backward compatibility for `keycloak_quarkus_key_store_password`, superseded by `keycloak_quarkus_https_key_store_password` + when: + - keycloak_quarkus_key_store_password is defined + - keycloak_quarkus_key_store_password != '' + - keycloak_quarkus_https_key_store_password == "" # default value + changed_when: true + ansible.builtin.set_fact: + keycloak_quarkus_https_key_store_password: "{{ keycloak_quarkus_key_store_password }}" + deprecated_variable: "keycloak_quarkus_key_store_password" # read in deprecation handler + notify: + - print deprecation warning + + - name: Flush handlers + meta: flush_handlers diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index 44fd3d1..44c461f 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -6,6 +6,11 @@ - prereqs - always +- name: Check for deprecations + ansible.builtin.include_tasks: deprecations.yml + tags: + - always + - name: Distro specific tasks ansible.builtin.include_tasks: "{{ ansible_os_family | lower }}.yml" tags: diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index 20d3f7f..d13a4cb 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -24,12 +24,12 @@ https-certificate-file={{ keycloak_quarkus_cert_file}} https-certificate-key-file={{ keycloak_quarkus_key_file }} {% endif %} {% if keycloak_quarkus_https_key_store_enabled %} -https-key-store-file={{ keycloak_quarkus_key_store_file }} -https-key-store-password={{ keycloak_quarkus_key_store_password }} +https-key-store-file={{ keycloak_quarkus_https_key_store_file }} +https-key-store-password={{ keycloak_quarkus_https_key_store_password }} {% endif %} {% if keycloak_quarkus_https_trust_store_enabled %} -https-trust-store-file={{ keycloak_quarkus_trust_store_file }} -https-trust-store-password={{ keycloak_quarkus_trust_store_password }} +https-trust-store-file={{ keycloak_quarkus_https_trust_store_file }} +https-trust-store-password={{ keycloak_quarkus_https_trust_store_password }} {% endif %} # Client URL configuration From 0ee29eb483a83704d6506d7628ecb72a9ba1ad2b Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 16 Apr 2024 09:39:03 +0200 Subject: [PATCH 066/205] #188: keycloak_quarkus: allow setting "sensitive options" using a Java KeyStore file #188 --- roles/keycloak_quarkus/README.md | 3 + roles/keycloak_quarkus/defaults/main.yml | 3 + .../keycloak_quarkus/meta/argument_specs.yml | 8 +++ roles/keycloak_quarkus/tasks/config_store.yml | 64 +++++++++++++++++++ roles/keycloak_quarkus/tasks/main.yml | 6 ++ .../templates/keycloak.conf.j2 | 9 +++ roles/keycloak_quarkus/vars/main.yml | 1 + 7 files changed, 94 insertions(+) create mode 100644 roles/keycloak_quarkus/tasks/config_store.yml diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index a518cca..ce45411 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -57,6 +57,9 @@ Role Defaults |`keycloak_quarkus_https_trust_store_file`| The file path to the trust store | `{{ keycloak.home }}/conf/trust_store.p12` | |`keycloak_quarkus_https_trust_store_password`| Password for the trust store | `""` | |`keycloak_quarkus_proxy_headers`| Parse reverse proxy headers (`forwarded` or `xforwardedPassword`) | `""` | +|`keycloak_quarkus_config_key_store_file`| Path to the configuration key store; only used if `keycloak_quarkus_keystore_password` is not empty | `{{ keycloak.home }}/conf/conf_store.p12` if `keycloak_quarkus_keystore_password`!='', else '' | +|`keycloak_quarkus_config_key_store_password`| Password of the configuration key store; if non-empty, `keycloak_quarkus_db_pass` will be saved to the key store at `keycloak_quarkus_config_key_store_file` (instead of being written to the configuration file in clear text | `""` | + * Hostname configuration diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index b1045e8..37d7fb6 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -58,6 +58,9 @@ keycloak_quarkus_https_key_store_password: '' keycloak_quarkus_https_trust_store_enabled: false keycloak_quarkus_https_trust_store_file: "{{ keycloak.home }}/conf/trust_store.p12" keycloak_quarkus_https_trust_store_password: '' +### configuration key store configuration +keycloak_quarkus_config_key_store_file: "{{ keycloak.home }}/conf/conf_store.p12" +keycloak_quarkus_config_key_store_password: '' ### Enable configuration for database backend, clustering and remote caches on infinispan keycloak_quarkus_ha_enabled: false diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 928d900..0e7cdae 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -152,6 +152,14 @@ argument_specs: default: "" description: "Password for the trust store" type: "str" + keycloak_quarkus_config_key_store_file: + default: "{{ keycloak.home }}/conf/conf_store.p12" + description: "Path to the configuration key store; only used if `keycloak_quarkus_keystore_password` is not empty" + type: "str" + keycloak_quarkus_config_key_store_password: + default: "" + description: "Password of the configuration key store; if non-empty, `keycloak_quarkus_db_pass` will be saved to the key store at `keycloak_quarkus_config_key_store_file` (instead of being written to the configuration file in clear text" + type: "str" keycloak_quarkus_https_port: default: 8443 description: "HTTPS port" diff --git a/roles/keycloak_quarkus/tasks/config_store.yml b/roles/keycloak_quarkus/tasks/config_store.yml new file mode 100644 index 0000000..6919705 --- /dev/null +++ b/roles/keycloak_quarkus/tasks/config_store.yml @@ -0,0 +1,64 @@ +--- +- name: "Check if keytool exists in path" + block: + - name: "Attempt to run keytool" + ansible.builtin.command: keytool -help + register: keytool_check + ignore_errors: true + + - name: "Fail when no keytool found" + when: keytool_check.rc != 0 + ansible.builtin.fail: + msg: "keytool NOT found in the PATH, but is required for setting up the configuration key store" + +- name: "Initialize configuration key store variables to be written" + ansible.builtin.set_fact: + store_items: + - key: "kc.db-password" + value: "{{ keycloak_quarkus_db_pass }}" + +- name: "Initialize empty configuration key store" + become: true + # keytool doesn't allow creating an empty key store, so this is a hacky way around it + ansible.builtin.shell: | + set -o nounset # abort on unbound variable + set -o pipefail # do not hide errors within pipes + set -o errexit # abort on nonzero exit status + + echo dummy | keytool -noprompt -importpass -alias dummy -keystore {{ keycloak_quarkus_config_key_store_file | quote }} -storepass {{ keycloak_quarkus_config_key_store_password | quote }} -storetype PKCS12 + keytool -delete -alias dummy -keystore {{ keycloak_quarkus_config_key_store_file | quote }} -storepass {{ keycloak_quarkus_config_key_store_password | quote }} + args: + creates: "{{ keycloak_quarkus_config_key_store_file }}" + +- name: "Set configuration key store using keytool" + ansible.builtin.shell: | + set -o nounset # abort on unbound variable + set -o pipefail # do not hide errors within pipes + + keytool -list -alias {{ item.key | quote }} -keystore {{ keycloak_quarkus_config_key_store_file | quote }} -storepass {{ keycloak_quarkus_config_key_store_password | quote }} + retVal=$? + + set -o errexit # abort on nonzero exit status + + if [ $retVal -eq 0 ]; then + # value is already in keystore, but keytool has no replace function: delete and re-create instead + # note that we can not read whether the value has changed either[^1], so we need to override it + # [^1]: https://stackoverflow.com/a/37491400 + keytool -delete -alias {{ item.key | quote }} -keystore {{ keycloak_quarkus_config_key_store_file | quote }} -storepass {{ keycloak_quarkus_config_key_store_password | quote }} + fi + + echo {{ item.value | quote }} | keytool -noprompt -importpass -alias {{ item.key | quote }} -keystore {{ keycloak_quarkus_config_key_store_file | quote }} -storepass {{ keycloak_quarkus_config_key_store_password | quote }} -storetype PKCS12 + with_items: "{{ store_items }}" + no_log: true + become: true + changed_when: true + notify: + - restart keycloak + +- name: "Set owner of configuration key store {{ keycloak_quarkus_config_key_store_file }}" + ansible.builtin.file: + path: "{{ keycloak_quarkus_config_key_store_file }}" + owner: "{{ keycloak.service_user }}" + group: "{{ keycloak.service_group }}" + mode: '0400' + become: true diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index 44c461f..8ca24cc 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -26,6 +26,12 @@ tags: - systemd +- name: Include configuration key store tasks + when: keycloak.config_key_store_enabled + ansible.builtin.include_tasks: config_store.yml + tags: + - install + - name: "Configure config for keycloak service" ansible.builtin.template: src: keycloak.conf.j2 diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index d13a4cb..6c9433e 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -5,8 +5,17 @@ db={{ keycloak_quarkus_jdbc_engine }} db-url={{ keycloak_quarkus_jdbc_url }} db-username={{ keycloak_quarkus_db_user }} +{% if not keycloak.config_key_store_enabled %} db-password={{ keycloak_quarkus_db_pass }} {% endif %} +{% endif %} + +{% if keycloak.config_key_store_enabled %} +# Config store +config-keystore={{ keycloak_quarkus_config_key_store_file }} +config-keystore-password={{ keycloak_quarkus_config_key_store_password }} +config-keystore-type=PKCS12 +{% endif %} # Observability metrics-enabled={{ keycloak_quarkus_metrics_enabled | lower }} diff --git a/roles/keycloak_quarkus/vars/main.yml b/roles/keycloak_quarkus/vars/main.yml index 6f92f4f..84fbeaa 100644 --- a/roles/keycloak_quarkus/vars/main.yml +++ b/roles/keycloak_quarkus/vars/main.yml @@ -10,6 +10,7 @@ keycloak: # noqa var-naming this is an internal dict of interpolated values service_user: "{{ keycloak_quarkus_service_user }}" service_group: "{{ keycloak_quarkus_service_group }}" offline_install: "{{ keycloak_quarkus_offline_install }}" + config_key_store_enabled: "{{ keycloak_quarkus_config_key_store_password != '' }}" log: file: "{{ keycloak_quarkus_home }}/{{ keycloak_quarkus_log_file }}" level: "{{ keycloak_quarkus_log_level }}" From c38642e0cd4b6fd244350dc214bff6e2b713fc89 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Wed, 17 Apr 2024 14:33:37 +0200 Subject: [PATCH 067/205] #188: fail early when no `keytool` installed --- roles/keycloak_quarkus/tasks/config_store.yml | 12 ------------ roles/keycloak_quarkus/tasks/prereqs.yml | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/roles/keycloak_quarkus/tasks/config_store.yml b/roles/keycloak_quarkus/tasks/config_store.yml index 6919705..40acc65 100644 --- a/roles/keycloak_quarkus/tasks/config_store.yml +++ b/roles/keycloak_quarkus/tasks/config_store.yml @@ -1,16 +1,4 @@ --- -- name: "Check if keytool exists in path" - block: - - name: "Attempt to run keytool" - ansible.builtin.command: keytool -help - register: keytool_check - ignore_errors: true - - - name: "Fail when no keytool found" - when: keytool_check.rc != 0 - ansible.builtin.fail: - msg: "keytool NOT found in the PATH, but is required for setting up the configuration key store" - - name: "Initialize configuration key store variables to be written" ansible.builtin.set_fact: store_items: diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index d344e98..d96c09e 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -42,3 +42,17 @@ ansible.builtin.include_tasks: fastpackages.yml vars: packages_list: "{{ keycloak_quarkus_prereq_package_list }}" + +- name: "Validate keytool" + when: keycloak.config_key_store_enabled + block: + - name: "Attempt to run keytool" + changed_when: false + ansible.builtin.command: keytool -help + register: keytool_check + ignore_errors: true + + - name: "Fail when no keytool found" + when: keytool_check.rc != 0 + ansible.builtin.fail: + msg: "keytool NOT found in the PATH, but is required for setting up the configuration key store" From d469d389f3a886b2f9b0df09b1f20d94fd193242 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Wed, 17 Apr 2024 16:29:11 +0200 Subject: [PATCH 068/205] Fix linter issues --- roles/keycloak_quarkus/tasks/deprecations.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/keycloak_quarkus/tasks/deprecations.yml b/roles/keycloak_quarkus/tasks/deprecations.yml index 9fed05e..a81c808 100644 --- a/roles/keycloak_quarkus/tasks/deprecations.yml +++ b/roles/keycloak_quarkus/tasks/deprecations.yml @@ -1,5 +1,5 @@ --- -- name: keycloak_quarkus_key_store -> keycloak_quarkus_http_key_store renaming +- name: Check deprecation keycloak_quarkus_key_store -> keycloak_quarkus_http_key_store delegate_to: localhost run_once: true when: @@ -18,7 +18,7 @@ - print deprecation warning - name: Flush handlers - meta: flush_handlers + ansible.builtin.meta: flush_handlers - name: Ensure backward compatibility for `keycloak_quarkus_key_store_password`, superseded by `keycloak_quarkus_https_key_store_password` when: @@ -33,4 +33,4 @@ - print deprecation warning - name: Flush handlers - meta: flush_handlers + ansible.builtin.meta: flush_handlers From e991bd32c834190835ae892a61ac6fb5e897c366 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Wed, 17 Apr 2024 16:45:10 +0200 Subject: [PATCH 069/205] Fix typos --- roles/keycloak_quarkus/README.md | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index ce45411..e5bb5bf 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -56,7 +56,7 @@ Role Defaults |`keycloak_quarkus_https_trust_store_enabled`| Enable configuration of the https trust store | `False` | |`keycloak_quarkus_https_trust_store_file`| The file path to the trust store | `{{ keycloak.home }}/conf/trust_store.p12` | |`keycloak_quarkus_https_trust_store_password`| Password for the trust store | `""` | -|`keycloak_quarkus_proxy_headers`| Parse reverse proxy headers (`forwarded` or `xforwardedPassword`) | `""` | +|`keycloak_quarkus_proxy_headers`| Parse reverse proxy headers (`forwarded` or `xforwarded`) | `""` | |`keycloak_quarkus_config_key_store_file`| Path to the configuration key store; only used if `keycloak_quarkus_keystore_password` is not empty | `{{ keycloak.home }}/conf/conf_store.p12` if `keycloak_quarkus_keystore_password`!='', else '' | |`keycloak_quarkus_config_key_store_password`| Password of the configuration key store; if non-empty, `keycloak_quarkus_db_pass` will be saved to the key store at `keycloak_quarkus_config_key_store_file` (instead of being written to the configuration file in clear text | `""` | diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 0e7cdae..6cca9de 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -311,7 +311,7 @@ argument_specs: keycloak_quarkus_proxy_headers: default: "" type: "str" - description: "Parse reverse proxy headers (`forwarded` or `xforwardedPassword`), overrides the deprecated keycloak_quarkus_proxy_mode argument" + description: "Parse reverse proxy headers (`forwarded` or `xforwarded`), overrides the deprecated keycloak_quarkus_proxy_mode argument" keycloak_quarkus_start_dev: default: false type: "bool" From 6706fd9bf512cfd5a20bada37f7bd80f70f88bd3 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 17:24:57 +0200 Subject: [PATCH 070/205] ci: bump and fix final linter warnings --- galaxy.yml | 2 +- roles/keycloak_realm/meta/argument_specs.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/galaxy.yml b/galaxy.yml index 2e996a0..4eac8bd 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.1.1" +version: "2.1.2" readme: README.md authors: - Romain Pelisse diff --git a/roles/keycloak_realm/meta/argument_specs.yml b/roles/keycloak_realm/meta/argument_specs.yml index ed87ee6..b124be2 100644 --- a/roles/keycloak_realm/meta/argument_specs.yml +++ b/roles/keycloak_realm/meta/argument_specs.yml @@ -112,7 +112,7 @@ argument_specs: sso_enable: default: true description: "Enable Red Hat Single Sign-on installation" - type: "str" + type: "bool" rhbk_version: default: "22.0.6" description: "Red Hat Build of Keycloak version" @@ -132,4 +132,4 @@ argument_specs: rhbk_enable: default: true description: "Enable Red Hat Build of Keycloak installation" - type: "str" + type: "bool" From 74636e86299b9f37157198549344120817501c8f Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 17:29:38 +0200 Subject: [PATCH 071/205] ci: final round of linting --- roles/keycloak_quarkus/meta/argument_specs.yml | 2 +- roles/keycloak_quarkus/tasks/install.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 657ebbf..57dec30 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -347,7 +347,7 @@ argument_specs: rhbk_enable: default: true description: "Enable Red Hat Build of Keycloak installation" - type: "str" + type: "bool" rhbk_offline_install: default: false description: "Perform an offline install" diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index cc2aa7f..818487f 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -22,7 +22,7 @@ name: "{{ keycloak.service_user }}" home: /opt/keycloak system: true - create_home: no + create_home: false - name: "Create {{ keycloak.service_name }} install location" become: true From 903938ca1684a3961705f2f58911aed8c74d8049 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Wed, 17 Apr 2024 15:49:00 +0000 Subject: [PATCH 072/205] Update changelog for release 2.1.2 Signed-off-by: ansible-middleware-core --- CHANGELOG.rst | 3 +++ changelogs/changelog.yaml | 2 ++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ce72edf..e55bc0c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,9 @@ middleware\_automation.keycloak Release Notes This changelog describes changes after version 0.2.6. +v2.1.2 +====== + v2.1.1 ====== diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index a8ed730..39ed404 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -454,3 +454,5 @@ releases: - 187.yaml - 191.yaml release_date: '2024-04-17' + 2.1.2: + release_date: '2024-04-17' From 462389cf0f84330ebee4b00756dd8151a926f723 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Wed, 17 Apr 2024 15:49:15 +0000 Subject: [PATCH 073/205] Bump version to 2.1.3 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index 4eac8bd..0270d91 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.1.2" +version: "2.1.3" readme: README.md authors: - Romain Pelisse From 8060dd7fb84310ab1a348e69d7fb0f04895ccf78 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 17:51:33 +0200 Subject: [PATCH 074/205] Bump minor and start 2.2 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index 0270d91..02838e3 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.1.3" +version: "2.2.0" readme: README.md authors: - Romain Pelisse From 5808d055ae21d293b4687be43596be84d8889b4a Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 17:53:13 +0200 Subject: [PATCH 075/205] Update keycloak to 24.0 --- roles/keycloak_quarkus/README.md | 2 +- roles/keycloak_quarkus/defaults/main.yml | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index e5bb5bf..4b7b46f 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -11,7 +11,7 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| -|`keycloak_quarkus_version`| keycloak.org package version | `23.0.7` | +|`keycloak_quarkus_version`| keycloak.org package version | `24.0.3` | * Service configuration diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 37d7fb6..35ea39a 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -1,6 +1,6 @@ --- ### Configuration specific to keycloak -keycloak_quarkus_version: 23.0.7 +keycloak_quarkus_version: 24.0.3 keycloak_quarkus_archive: "keycloak-{{ keycloak_quarkus_version }}.zip" keycloak_quarkus_download_url: "https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}" keycloak_quarkus_installdir: "{{ keycloak_quarkus_dest }}/keycloak-{{ keycloak_quarkus_version }}" diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index bdc0615..7a74e64 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -2,7 +2,7 @@ argument_specs: main: options: keycloak_quarkus_version: - default: "23.0.7" + default: "24.0.3" description: "keycloak.org package version" type: "str" keycloak_quarkus_archive: From 10057262bcbc8f92d8357dfc18ce705a8882df5e Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 17 Apr 2024 18:07:42 +0200 Subject: [PATCH 076/205] 'fix' changelog --- CHANGELOG.rst | 12 ++++++++++++ changelogs/changelog.yaml | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e55bc0c..89d0992 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,12 @@ This changelog describes changes after version 0.2.6. v2.1.2 ====== +Release Summary +--------------- + +Internal release, documentation or test changes only. + + v2.1.1 ====== @@ -275,6 +281,12 @@ Minor Changes v1.0.4 ====== +Release Summary +--------------- + +Internal release, documentation or test changes only. + + v1.0.3 ====== diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 39ed404..3fd8b1b 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -59,6 +59,10 @@ releases: - 31.yaml release_date: '2022-05-09' 1.0.4: + changes: + release_summary: 'Internal release, documentation or test changes only. + + ' release_date: '2022-05-11' 1.0.5: changes: @@ -455,4 +459,8 @@ releases: - 191.yaml release_date: '2024-04-17' 2.1.2: + changes: + release_summary: 'Internal release, documentation or test changes only. + + ' release_date: '2024-04-17' From 3e28b3f4f792a5f5027078e063446ec56ff3ff10 Mon Sep 17 00:00:00 2001 From: Deven Phillips Date: Wed, 17 Apr 2024 16:52:18 -0400 Subject: [PATCH 077/205] Added hostname-strict-https option --- roles/keycloak_quarkus/templates/keycloak.conf.j2 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index 6c9433e..f31e110 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -10,6 +10,10 @@ db-password={{ keycloak_quarkus_db_pass }} {% endif %} {% endif %} +{% if keycloak_quarkus_hostname_strict_https -%} +hostname-strict-https={{ keycloak_quarkus_hostname_strict_https }} +{% endif -%} + {% if keycloak.config_key_store_enabled %} # Config store config-keystore={{ keycloak_quarkus_config_key_store_file }} From 47e6644fdd165d6f1307003a70aadb22666c90b5 Mon Sep 17 00:00:00 2001 From: Deven Phillips Date: Wed, 17 Apr 2024 16:57:52 -0400 Subject: [PATCH 078/205] Ensure that value for keycloak_quarkus_hostname_strict_https is boolean, otherwise ignore it --- roles/keycloak_quarkus/templates/keycloak.conf.j2 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index f31e110..3b064b1 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -10,8 +10,11 @@ db-password={{ keycloak_quarkus_db_pass }} {% endif %} {% endif %} -{% if keycloak_quarkus_hostname_strict_https -%} -hostname-strict-https={{ keycloak_quarkus_hostname_strict_https }} +{% if keycloak_quarkus_hostname_strict_https and keycloak_quarkus_hostname_strict_https is sameas true -%} +hostname-strict-https=true +{% endif -%} +{% if keycloak_quarkus_hostname_strict_https and keycloak_quarkus_hostname_strict_https is sameas false -%} +hostname-strict-https=false {% endif -%} {% if keycloak.config_key_store_enabled %} From cd8d61afc358fdf3e4fc917665f26beebb75381f Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 18 Apr 2024 10:43:48 +0200 Subject: [PATCH 079/205] Update molecule test for keystore vault --- molecule/quarkus/converge.yml | 8 ++++++-- molecule/quarkus/prepare.yml | 8 +++++++- molecule/quarkus/verify.yml | 19 ++++++++++++++++--- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index 1b989ce..ea04de2 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -1,16 +1,20 @@ --- - name: Converge hosts: all - vars: + vars: keycloak_quarkus_admin_pass: "remembertochangeme" keycloak_admin_password: "remembertochangeme" keycloak_realm: TestRealm keycloak_quarkus_host: instance keycloak_quarkus_log: file - keycloak_quarkus_https_key_file_enabled: True + keycloak_quarkus_log_level: debug + keycloak_quarkus_https_key_file_enabled: true keycloak_quarkus_key_file: "/opt/keycloak/certs/key.pem" keycloak_quarkus_cert_file: "/opt/keycloak/certs/cert.pem" keycloak_quarkus_log_target: /tmp/keycloak + keycloak_quarkus_ks_vault_enabled: true + keycloak_quarkus_ks_vault_file: "/opt/keycloak/certs/keystore.p12" + keycloak_quarkus_ks_vault_pass: keystorepassword roles: - role: keycloak_quarkus - role: keycloak_realm diff --git a/molecule/quarkus/prepare.yml b/molecule/quarkus/prepare.yml index 03e5b89..b4f2431 100644 --- a/molecule/quarkus/prepare.yml +++ b/molecule/quarkus/prepare.yml @@ -21,7 +21,12 @@ path: "/opt/keycloak/certs/" mode: 0755 - - name: Copy certificates + - name: Create vault keystore + ansible.builtin.command: keytool -importpass -alias TestRealm_testalias -keystore keystore.p12 -storepass keystorepassword + delegate_to: localhost + changed_when: False + + - name: Copy certificates and vault become: yes ansible.builtin.copy: src: "{{ item }}" @@ -30,3 +35,4 @@ loop: - cert.pem - key.pem + - keystore.p12 diff --git a/molecule/quarkus/verify.yml b/molecule/quarkus/verify.yml index a58a13f..0216f1c 100644 --- a/molecule/quarkus/verify.yml +++ b/molecule/quarkus/verify.yml @@ -10,6 +10,7 @@ that: - ansible_facts.services["keycloak.service"]["state"] == "running" - ansible_facts.services["keycloak.service"]["status"] == "enabled" + fail_msg: "Service not running" - name: Set internal envvar ansible.builtin.set_fact: @@ -40,7 +41,7 @@ - name: Check log folder ansible.builtin.stat: - path: "/tmp/keycloak" + path: /tmp/keycloak register: keycloak_log_folder - name: Check that keycloak log folder exists and is a link @@ -49,11 +50,12 @@ - keycloak_log_folder.stat.exists - not keycloak_log_folder.stat.isdir - keycloak_log_folder.stat.islnk + fail_msg: "Service log symlink not correctly created" - name: Check log file become: yes ansible.builtin.stat: - path: "/tmp/keycloak/keycloak.log" + path: /tmp/keycloak/keycloak.log register: keycloak_log_file - name: Check if keycloak file exists @@ -65,7 +67,7 @@ - name: Check default log folder become: yes ansible.builtin.stat: - path: "/var/log/keycloak" + path: /var/log/keycloak register: keycloak_default_log_folder failed_when: false @@ -73,3 +75,14 @@ ansible.builtin.assert: that: - not keycloak_default_log_folder.stat.exists + + - name: Read content of logs + ansible.builtin.slurp: + src: /tmp/keycloak/keycloak.log + register: slurped_log + + - name: Verify keystore vault loaded + ansible.builtin.assert: + that: + - "'Configured KeystoreVaultProviderFactory with the keystore file' in slurped_log.content | b64decode" + fail_msg: "Service failed to use keystore vault correctly" From 89db3fa36ffe43ead59ac8d5d498b4138ed7242f Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 18 Apr 2024 10:44:17 +0200 Subject: [PATCH 080/205] Implement vault config --- roles/keycloak_quarkus/defaults/main.yml | 6 ++++++ roles/keycloak_quarkus/handlers/main.yml | 4 +++- roles/keycloak_quarkus/templates/keycloak.conf.j2 | 8 ++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 35ea39a..e3e2504 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -135,3 +135,9 @@ keycloak_quarkus_log_target: /var/log/keycloak keycloak_quarkus_log_max_file_size: 10M keycloak_quarkus_log_max_backup_index: 10 keycloak_quarkus_log_file_suffix: '.yyyy-MM-dd.zip' + +# keystore-based vault +keycloak_quarkus_ks_vault_enabled: false +keycloak_quarkus_ks_vault_file: "{{ keycloak_quarkus_config_dir }}/keystore.p12" +keycloak_quarkus_ks_vault_type: PKCS12 +keycloak_quarkus_ks_vault_pass: diff --git a/roles/keycloak_quarkus/handlers/main.yml b/roles/keycloak_quarkus/handlers/main.yml index bbdf61c..965ea8f 100644 --- a/roles/keycloak_quarkus/handlers/main.yml +++ b/roles/keycloak_quarkus/handlers/main.yml @@ -3,11 +3,13 @@ - name: "Rebuild {{ keycloak.service_name }} config" ansible.builtin.include_tasks: rebuild_config.yml listen: "rebuild keycloak config" + - name: "Restart {{ keycloak.service_name }}" ansible.builtin.include_tasks: restart.yml listen: "restart keycloak" + - name: "Print deprecation warning" ansible.builtin.fail: msg: "Deprecation warning: you are using the deprecated variable '{{ deprecated_variable | d('NotSet') }}', check docs on how to upgrade." - ignore_errors: True + ignore_errors: true listen: "print deprecation warning" diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index 6c9433e..17ba34b 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -82,3 +82,11 @@ log={{ keycloak_quarkus_log }} log-level={{ keycloak.log.level }} log-file={{ keycloak.log.file }} log-file-format={{ keycloak.log.format }} + +# Vault +{% if keycloak_quarkus_ks_vault_enabled %} +vault=keystore +vault-file={{ keycloak_quarkus_ks_vault_file }} +vault-type={{ keycloak_quarkus_ks_vault_type }} +vault-pass={{ keycloak_quarkus_ks_vault_pass }} +{% endif %} From d06dcea9988b8be7a92b9b528938cad9edefa8d3 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 18 Apr 2024 10:49:38 +0200 Subject: [PATCH 081/205] Add argument specs, update README --- roles/keycloak_quarkus/README.md | 25 +++++++++++++------ .../keycloak_quarkus/meta/argument_specs.yml | 16 ++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 4b7b46f..52304e6 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -7,14 +7,14 @@ Install [keycloak](https://keycloak.org/) >= 20.0.0 (quarkus) server configurati Role Defaults ------------- -* Installation options +#### Installation options | Variable | Description | Default | |:---------|:------------|:--------| |`keycloak_quarkus_version`| keycloak.org package version | `24.0.3` | -* Service configuration +#### Service configuration | Variable | Description | Default | |:---------|:------------|:--------| @@ -61,7 +61,7 @@ Role Defaults |`keycloak_quarkus_config_key_store_password`| Password of the configuration key store; if non-empty, `keycloak_quarkus_db_pass` will be saved to the key store at `keycloak_quarkus_config_key_store_file` (instead of being written to the configuration file in clear text | `""` | -* Hostname configuration +#### Hostname configuration | Variable | Description | Default | |:---------|:------------|:--------| @@ -70,7 +70,7 @@ Role Defaults |`keycloak_quarkus_hostname_strict_backchannel`| By default backchannel URLs are dynamically resolved from request headers to allow internal and external applications. If all applications use the public URL this option should be enabled. | `false` | -* Database configuration +#### Database configuration | Variable | Description | Default | |:---------|:------------|:--------| @@ -81,7 +81,7 @@ Role Defaults |`keycloak_quarkus_jdbc_driver_version` | Version for JDBC driver | `9.4.1212` | -* Remote caches configuration +#### Remote caches configuration | Variable | Description | Default | |:---------|:------------|:--------| @@ -94,7 +94,7 @@ Role Defaults |`keycloak_quarkus_ispn_trust_store_password` | Password for infinispan certificate keystore | `changeit` | -* Install options +#### Install options | Variable | Description | Default | |:---------|:------------|:---------| @@ -105,7 +105,7 @@ Role Defaults |`keycloak_quarkus_configure_firewalld` | Ensure firewalld is running and configure keycloak ports | `False` | -* Miscellaneous configuration +#### Miscellaneous configuration | Variable | Description | Default | |:---------|:------------|:--------| @@ -132,6 +132,16 @@ Role Defaults |`keycloak_quarkus_transaction_xa_enabled`| Whether to use XA transactions | `True` | |`keycloak_quarkus_spi_sticky_session_encoder_infinispan_should_attach_route`| If the route should be attached to cookies to reflect the node that owns a particular session. If false, route is not attached to cookies and we rely on the session affinity capabilities from reverse proxy | `True` | + +#### Vault SPI + +| Variable | Description | Default | +|:---------|:------------|:--------| +|`keycloak_quarkus_ks_vault_enabled`| Whether to enable the vault SPI | `false` | +|`keycloak_quarkus_ks_vault_file`| The keystore path for the vault SPI | `{{ keycloak_quarkus_config_dir }}/keystore.p12` | +|`keycloak_quarkus_ks_vault_type`| Type of the keystore used for the vault SPI | `PKCS12` | + + Role Variables -------------- @@ -140,6 +150,7 @@ Role Variables |`keycloak_quarkus_admin_pass`| Password of console admin account | `yes` | |`keycloak_quarkus_frontend_url`| Base URL for frontend URLs, including scheme, host, port and path | `no` | |`keycloak_quarkus_admin_url`| Base URL for accessing the administration console, including scheme, host, port and path | `no` | +|`keycloak_quarkus_ks_vault_pass`| The password for accessing the keystore vault SPI | `no` | License diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 7a74e64..0f4ea98 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -338,6 +338,22 @@ argument_specs: description: > If the route should be attached to cookies to reflect the node that owns a particular session. If false, route is not attached to cookies and we rely on the session affinity capabilities from reverse proxy + keycloak_quarkus_ks_vault_enabled: + default: false + type: "bool" + description: "Whether to enable vault SPI" + keycloak_quarkus_ks_vault_file: + default: "{{ keycloak_quarkus_config_dir }}/keystore.p12" + type: "str" + description: "The keystore path for the vault SPI" + keycloak_quarkus_ks_vault_type: + default: "PKCS12" + type: "str" + description: "Type of the keystore used for the vault SPI" + keycloak_quarkus_ks_vault_pass: + required: false + type: "str" + description: "The password for accessing the keystore vault SPI" downstream: options: rhbk_version: From ff198bcd3e95646ee98b9fd755af0c5aa1785ace Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 18 Apr 2024 11:06:14 +0200 Subject: [PATCH 082/205] workaround debug logfile too long for slurp --- molecule/quarkus/verify.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/molecule/quarkus/verify.yml b/molecule/quarkus/verify.yml index 0216f1c..1efe9dd 100644 --- a/molecule/quarkus/verify.yml +++ b/molecule/quarkus/verify.yml @@ -76,13 +76,10 @@ that: - not keycloak_default_log_folder.stat.exists - - name: Read content of logs - ansible.builtin.slurp: - src: /tmp/keycloak/keycloak.log + - name: Verify vault SPI in logfile + ansible.builtin.shell: | + set -o pipefail + zgrep 'Configured KeystoreVaultProviderFactory with the keystore file' /opt/keycloak/keycloak-*/data/log/keycloak.log*zip + changed_when: false + failed_when: slurped_log.rc != 0 register: slurped_log - - - name: Verify keystore vault loaded - ansible.builtin.assert: - that: - - "'Configured KeystoreVaultProviderFactory with the keystore file' in slurped_log.content | b64decode" - fail_msg: "Service failed to use keystore vault correctly" From b8cba487acc71c0cfa7858b61aac3c5c82a94699 Mon Sep 17 00:00:00 2001 From: Deven Phillips Date: Thu, 18 Apr 2024 13:15:46 -0400 Subject: [PATCH 083/205] Add better error trapping for booleans --- roles/keycloak_quarkus/templates/keycloak.conf.j2 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index 3b064b1..86d6628 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -10,10 +10,10 @@ db-password={{ keycloak_quarkus_db_pass }} {% endif %} {% endif %} -{% if keycloak_quarkus_hostname_strict_https and keycloak_quarkus_hostname_strict_https is sameas true -%} +{% if keycloak_quarkus_hostname_strict_https is defined and keycloak_quarkus_hostname_strict_https is sameas true -%} hostname-strict-https=true {% endif -%} -{% if keycloak_quarkus_hostname_strict_https and keycloak_quarkus_hostname_strict_https is sameas false -%} +{% if keycloak_quarkus_hostname_strict_https is defined and keycloak_quarkus_hostname_strict_https is sameas false -%} hostname-strict-https=false {% endif -%} From 289b4767e0ca428a0e1e3526cc652a4609fa6d57 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Fri, 19 Apr 2024 08:14:58 +0200 Subject: [PATCH 084/205] #190: remove `keycloak_quarkus_admin_user[_pass]` once keycloak is bootstrapped --- roles/keycloak_quarkus/README.md | 8 +++++++ roles/keycloak_quarkus/handlers/main.yml | 4 +++- roles/keycloak_quarkus/tasks/bootstrapped.yml | 16 +++++++++++++ roles/keycloak_quarkus/tasks/install.yml | 7 ++++++ roles/keycloak_quarkus/tasks/main.yml | 23 +++++++++++++++---- .../templates/keycloak-sysconfig.j2 | 4 ++++ .../templates/keycloak.fact.j2 | 2 ++ roles/keycloak_quarkus/vars/main.yml | 1 + 8 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 roles/keycloak_quarkus/tasks/bootstrapped.yml create mode 100644 roles/keycloak_quarkus/templates/keycloak.fact.j2 diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 52304e6..fb41533 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -152,6 +152,14 @@ Role Variables |`keycloak_quarkus_admin_url`| Base URL for accessing the administration console, including scheme, host, port and path | `no` | |`keycloak_quarkus_ks_vault_pass`| The password for accessing the keystore vault SPI | `no` | +Role custom facts +----------------- + +The role uses the following [custom facts](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_vars_facts.html#adding-custom-facts) found in `/etc/ansible/facts.d/keycloak.fact` (and thus identified by the `ansible_local.keycloak.` prefix): + +| Variable | Description | +|:---------|:------------| +|`general.bootstrapped` | A custom fact indicating whether this role has been used for bootstrapping keycloak on the respective host before; set to `false` (e.g., when starting off with a new, empty database) ensures that the initial admin user as defined by `keycloak_quarkus_admin_user[_pass]` gets created | License ------- diff --git a/roles/keycloak_quarkus/handlers/main.yml b/roles/keycloak_quarkus/handlers/main.yml index 965ea8f..d6b2220 100644 --- a/roles/keycloak_quarkus/handlers/main.yml +++ b/roles/keycloak_quarkus/handlers/main.yml @@ -3,7 +3,9 @@ - name: "Rebuild {{ keycloak.service_name }} config" ansible.builtin.include_tasks: rebuild_config.yml listen: "rebuild keycloak config" - +- name: "Bootstrapped" + ansible.builtin.include_tasks: bootstrapped.yml + listen: bootstrapped - name: "Restart {{ keycloak.service_name }}" ansible.builtin.include_tasks: restart.yml listen: "restart keycloak" diff --git a/roles/keycloak_quarkus/tasks/bootstrapped.yml b/roles/keycloak_quarkus/tasks/bootstrapped.yml new file mode 100644 index 0000000..46278ab --- /dev/null +++ b/roles/keycloak_quarkus/tasks/bootstrapped.yml @@ -0,0 +1,16 @@ +--- +- name: Write ansible custom facts + become: true + ansible.builtin.template: + src: keycloak.fact.j2 + dest: /etc/ansible/facts.d/keycloak.fact + mode: '0644' + vars: + bootstrapped: true + +- name: Re-read custom facts + ansible.builtin.setup: + filter: ansible_local + +- name: Ensure that `KEYCLOAK_ADMIN[_PASSWORD]` get purged + ansible.builtin.include_tasks: systemd.yml diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index 818487f..085f3d7 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -33,6 +33,13 @@ group: "{{ keycloak.service_group }}" mode: '0750' +- name: Create directory for ansible custom facts + become: true + ansible.builtin.file: + state: directory + recurse: true + path: /etc/ansible/facts.d + ## check remote archive - name: Set download archive path ansible.builtin.set_fact: diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index 8ca24cc..4c0db72 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -96,11 +96,6 @@ - name: "Start and wait for keycloak service" ansible.builtin.include_tasks: start.yml -- name: Check service status - ansible.builtin.command: "systemctl status keycloak" - register: keycloak_service_status - changed_when: false - - name: Link default logs directory ansible.builtin.file: state: link @@ -108,3 +103,21 @@ dest: "{{ keycloak_quarkus_log_target }}" force: true become: true + +- name: Check service status + ansible.builtin.systemd_service: + name: "{{ keycloak.service_name }}" + register: keycloak_service_status + changed_when: false + +- name: "Trigger bootstrapped notification: remove `keycloak_quarkus_admin_user[_pass]` env vars" + when: + - not ansible_local.keycloak.general.bootstrapped | default(false) | bool # it was not bootstrapped prior to the current role's execution + - keycloak_service_status.status.ActiveState == "active" # but it is now + ansible.builtin.assert: { that: true, quiet: true } + changed_when: true + notify: + - bootstrapped + +- name: Flush pending handlers + ansible.builtin.meta: flush_handlers diff --git a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 index 4667596..ef27d27 100644 --- a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 +++ b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 @@ -1,6 +1,10 @@ {{ ansible_managed | comment }} +{% if not ansible_local.keycloak.general.bootstrapped | default(false) | bool %} KEYCLOAK_ADMIN={{ keycloak_quarkus_admin_user }} KEYCLOAK_ADMIN_PASSWORD='{{ keycloak_quarkus_admin_pass }}' +{% else %} +{{ keycloak.bootstrap_mnemonic }} +{% endif %} PATH={{ keycloak_quarkus_java_home | default(keycloak_sys_pkg_java_home, true) }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin JAVA_HOME={{ keycloak_quarkus_java_home | default(keycloak_sys_pkg_java_home, true) }} JAVA_OPTS={{ keycloak_quarkus_java_opts }} diff --git a/roles/keycloak_quarkus/templates/keycloak.fact.j2 b/roles/keycloak_quarkus/templates/keycloak.fact.j2 new file mode 100644 index 0000000..e035110 --- /dev/null +++ b/roles/keycloak_quarkus/templates/keycloak.fact.j2 @@ -0,0 +1,2 @@ +[general] +bootstrapped={{ bootstrapped | lower }} diff --git a/roles/keycloak_quarkus/vars/main.yml b/roles/keycloak_quarkus/vars/main.yml index 84fbeaa..fcf82f0 100644 --- a/roles/keycloak_quarkus/vars/main.yml +++ b/roles/keycloak_quarkus/vars/main.yml @@ -15,3 +15,4 @@ keycloak: # noqa var-naming this is an internal dict of interpolated values file: "{{ keycloak_quarkus_home }}/{{ keycloak_quarkus_log_file }}" level: "{{ keycloak_quarkus_log_level }}" format: "{{ keycloak_quarkus_log_format }}" + bootstrap_mnemonic: "# ansible-middleware/keycloak: bootstrapped" From 04bb465992924576186787f5fdc75d147e33c23e Mon Sep 17 00:00:00 2001 From: Deven Phillips Date: Fri, 19 Apr 2024 09:55:08 -0400 Subject: [PATCH 085/205] Added argument specs --- roles/keycloak_quarkus/meta/argument_specs.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 7a74e64..a07b1a9 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -338,6 +338,12 @@ argument_specs: description: > If the route should be attached to cookies to reflect the node that owns a particular session. If false, route is not attached to cookies and we rely on the session affinity capabilities from reverse proxy + keycloak_quarkus_hostname_strict_https: + type: "bool" + description: > + By default, Keycloak requires running using TLS/HTTPS. If the service MUST run without TLS/HTTPS, then set + this option to "true" + downstream: options: rhbk_version: From 2925ea8cf1fd897b987bdb74f70c8f8e0d73cf9e Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 23 Apr 2024 16:38:04 +0200 Subject: [PATCH 086/205] Add wait_for systemd logic --- molecule/quarkus/converge.yml | 4 ++ molecule/quarkus/prepare.yml | 2 + roles/keycloak_quarkus/README.md | 40 ++++++++++--------- roles/keycloak_quarkus/defaults/main.yml | 7 +++- roles/keycloak_quarkus/handlers/main.yml | 2 +- .../keycloak_quarkus/meta/argument_specs.yml | 20 ++++++++-- roles/keycloak_quarkus/tasks/restart.yml | 1 + .../templates/keycloak.service.j2 | 11 +++-- 8 files changed, 59 insertions(+), 28 deletions(-) diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index ea04de2..0d59050 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -15,6 +15,10 @@ keycloak_quarkus_ks_vault_enabled: true keycloak_quarkus_ks_vault_file: "/opt/keycloak/certs/keystore.p12" keycloak_quarkus_ks_vault_pass: keystorepassword + keycloak_quarkus_systemd_wait_for_port: true + keycloak_quarkus_systemd_wait_for_timeout: 20 + keycloak_quarkus_systemd_wait_for_delay: 2 + keycloak_quarkus_systemd_wait_for_log: true roles: - role: keycloak_quarkus - role: keycloak_realm diff --git a/molecule/quarkus/prepare.yml b/molecule/quarkus/prepare.yml index b4f2431..0095226 100644 --- a/molecule/quarkus/prepare.yml +++ b/molecule/quarkus/prepare.yml @@ -24,7 +24,9 @@ - name: Create vault keystore ansible.builtin.command: keytool -importpass -alias TestRealm_testalias -keystore keystore.p12 -storepass keystorepassword delegate_to: localhost + register: keytool_cmd changed_when: False + failed_when: not 'already exists' in keytool_cmd.stdout and keytool_cmd.rc != 0 - name: Copy certificates and vault become: yes diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index fb41533..5d0641c 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -12,15 +12,16 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| |`keycloak_quarkus_version`| keycloak.org package version | `24.0.3` | +|`keycloak_quarkus_offline_install` | Perform an offline install | `False`| +|`keycloak_quarkus_version`| keycloak.org package version | `23.0.7` | +|`keycloak_quarkus_dest`| Installation root path | `/opt/keycloak` | +|`keycloak_quarkus_download_url` | Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}` | #### Service configuration | Variable | Description | Default | |:---------|:------------|:--------| -|`keycloak_quarkus_ha_enabled`| Enable auto configuration for database backend, clustering and remote caches on infinispan | `False` | -|`keycloak_quarkus_ha_discovery`| Discovery protocol for HA cluster members | `TCPPING` | -|`keycloak_quarkus_db_enabled`| Enable auto configuration for database backend | `True` if `keycloak_quarkus_ha_enabled` is True, else `False` | |`keycloak_quarkus_admin_user`| Administration console user account | `admin` | |`keycloak_quarkus_bind_address`| Address for binding service ports | `0.0.0.0` | |`keycloak_quarkus_host`| Hostname for the Keycloak server | `localhost` | @@ -29,13 +30,11 @@ Role Defaults |`keycloak_quarkus_http_port`| HTTP listening port | `8080` | |`keycloak_quarkus_https_port`| TLS HTTP listening port | `8443` | |`keycloak_quarkus_ajp_port`| AJP port | `8009` | -|`keycloak_quarkus_jgroups_port`| jgroups cluster tcp port | `7800` | |`keycloak_quarkus_service_user`| Posix account username | `keycloak` | |`keycloak_quarkus_service_group`| Posix account group | `keycloak` | |`keycloak_quarkus_service_restart_always`| systemd restart always behavior activation | `False` | |`keycloak_quarkus_service_restart_on_failure`| systemd restart on-failure behavior activation | `False` | |`keycloak_quarkus_service_restartsec`| systemd RestartSec | `10s` | -|`keycloak_quarkus_service_pidfile`| Pid file path for service | `/run/keycloak.pid` | |`keycloak_quarkus_jvm_package`| RHEL java package runtime | `java-17-openjdk-headless` | |`keycloak_quarkus_java_home`| JAVA_HOME of installed JRE, leave empty for using specified keycloak_quarkus_jvm_package RPM path | `None` | |`keycloak_quarkus_java_heap_opts`| Heap memory JVM setting | `-Xms1024m -Xmx2048m` | @@ -57,8 +56,24 @@ Role Defaults |`keycloak_quarkus_https_trust_store_file`| The file path to the trust store | `{{ keycloak.home }}/conf/trust_store.p12` | |`keycloak_quarkus_https_trust_store_password`| Password for the trust store | `""` | |`keycloak_quarkus_proxy_headers`| Parse reverse proxy headers (`forwarded` or `xforwarded`) | `""` | -|`keycloak_quarkus_config_key_store_file`| Path to the configuration key store; only used if `keycloak_quarkus_keystore_password` is not empty | `{{ keycloak.home }}/conf/conf_store.p12` if `keycloak_quarkus_keystore_password`!='', else '' | -|`keycloak_quarkus_config_key_store_password`| Password of the configuration key store; if non-empty, `keycloak_quarkus_db_pass` will be saved to the key store at `keycloak_quarkus_config_key_store_file` (instead of being written to the configuration file in clear text | `""` | +|`keycloak_quarkus_config_key_store_file`| Path to the configuration key store; only used if `keycloak_quarkus_keystore_password` is not empty | `{{ keycloak.home }}/conf/conf_store.p12` if `keycloak_quarkus_keystore_password != ''`, else `''` | +|`keycloak_quarkus_config_key_store_password`| Password of the configuration keystore; if non-empty, `keycloak_quarkus_db_pass` will be saved to the keystore at `keycloak_quarkus_config_key_store_file` instead of being written to the configuration file in clear text | `""` | +|`keycloak_quarkus_configure_firewalld` | Ensure firewalld is running and configure keycloak ports | `False` | +|`keycloak_quarkus_configure_iptables` | Ensure iptables is configured for keycloak ports | `False` | + + +#### High-availability + +| Variable | Description | Default | +|:---------|:------------|:--------| +|`keycloak_quarkus_ha_enabled`| Enable auto configuration for database backend, clustering and remote caches on infinispan | `False` | +|`keycloak_quarkus_ha_discovery`| Discovery protocol for HA cluster members | `TCPPING` | +|`keycloak_quarkus_db_enabled`| Enable auto configuration for database backend | `True` if `keycloak_quarkus_ha_enabled` is True, else `False` | +|`keycloak_quarkus_jgroups_port`| jgroups cluster tcp port | `7800` | +|`keycloak_quarkus_systemd_wait_for_port` | Whether systemd unit should wait for keycloak port before returning | `{{ keycloak_quarkus_ha_enabled }}` | +|`keycloak_quarkus_systemd_wait_for_log` | Whether systemd unit should wait for service to be up in logs | `false` | +|`keycloak_quarkus_systemd_wait_for_timeout`| How long to wait for service to be alive (seconds) | `60` | +|`keycloak_quarkus_systemd_wait_for_delay`| Activation delay for service systemd unit (seconds) | `10` | #### Hostname configuration @@ -94,17 +109,6 @@ Role Defaults |`keycloak_quarkus_ispn_trust_store_password` | Password for infinispan certificate keystore | `changeit` | -#### Install options - -| Variable | Description | Default | -|:---------|:------------|:---------| -|`keycloak_quarkus_offline_install` | Perform an offline install | `False`| -|`keycloak_quarkus_version`| keycloak.org package version | `23.0.7` | -|`keycloak_quarkus_dest`| Installation root path | `/opt/keycloak` | -|`keycloak_quarkus_download_url` | Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}` | -|`keycloak_quarkus_configure_firewalld` | Ensure firewalld is running and configure keycloak ports | `False` | - - #### Miscellaneous configuration | Variable | Description | Default | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index e3e2504..1999dd8 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -16,7 +16,6 @@ keycloak_quarkus_config_dir: "{{ keycloak_quarkus_home }}/conf" keycloak_quarkus_start_dev: false keycloak_quarkus_service_user: keycloak keycloak_quarkus_service_group: keycloak -keycloak_quarkus_service_pidfile: "/run/keycloak/keycloak.pid" keycloak_quarkus_service_restart_always: false keycloak_quarkus_service_restart_on_failure: false keycloak_quarkus_service_restartsec: "10s" @@ -66,7 +65,11 @@ keycloak_quarkus_config_key_store_password: '' keycloak_quarkus_ha_enabled: false keycloak_quarkus_ha_discovery: "TCPPING" ### Enable database configuration, must be enabled when HA is configured -keycloak_quarkus_db_enabled: "{{ True if keycloak_quarkus_ha_enabled else False }}" +keycloak_quarkus_db_enabled: "{{ keycloak_quarkus_ha_enabled }}" +keycloak_quarkus_systemd_wait_for_port: "{{ keycloak_quarkus_ha_enabled }}" +keycloak_quarkus_systemd_wait_for_log: false +keycloak_quarkus_systemd_wait_for_timeout: 60 +keycloak_quarkus_systemd_wait_for_delay: 10 ### keycloak frontend url keycloak_quarkus_frontend_url: diff --git a/roles/keycloak_quarkus/handlers/main.yml b/roles/keycloak_quarkus/handlers/main.yml index d6b2220..f60e747 100644 --- a/roles/keycloak_quarkus/handlers/main.yml +++ b/roles/keycloak_quarkus/handlers/main.yml @@ -9,9 +9,9 @@ - name: "Restart {{ keycloak.service_name }}" ansible.builtin.include_tasks: restart.yml listen: "restart keycloak" - - name: "Print deprecation warning" ansible.builtin.fail: msg: "Deprecation warning: you are using the deprecated variable '{{ deprecated_variable | d('NotSet') }}', check docs on how to upgrade." ignore_errors: true + failed_when: false listen: "print deprecation warning" diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 5d0519b..460c9a7 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -48,10 +48,6 @@ argument_specs: default: "keycloak" description: "Posix account group" type: "str" - keycloak_quarkus_service_pidfile: - default: "/run/keycloak/keycloak.pid" - description: "Pid file path for service" - type: "str" keycloak_quarkus_configure_firewalld: default: false description: "Ensure firewalld is running and configure keycloak ports" @@ -360,6 +356,22 @@ argument_specs: required: false type: "str" description: "The password for accessing the keystore vault SPI" + keycloak_quarkus_systemd_wait_for_port: + description: 'Whether systemd unit should wait for keycloak port before returning' + default: "{{ keycloak_quarkus_ha_enabled }}" + type: "bool" + keycloak_quarkus_systemd_wait_for_log: + description: 'Whether systemd unit should wait for service to be up in logs' + default: false + type: "bool" + keycloak_quarkus_systemd_wait_for_timeout: + description: "How long to wait for service to be alive (seconds)" + default: 60 + type: 'int' + keycloak_quarkus_systemd_wait_for_delay: + description: "Activation delay for service systemd unit (seconds)" + default: 10 + type: 'int' downstream: options: rhbk_version: diff --git a/roles/keycloak_quarkus/tasks/restart.yml b/roles/keycloak_quarkus/tasks/restart.yml index f709f75..77e1099 100644 --- a/roles/keycloak_quarkus/tasks/restart.yml +++ b/roles/keycloak_quarkus/tasks/restart.yml @@ -1,5 +1,6 @@ --- - name: "Restart and enable {{ keycloak.service_name }} service" + throttle: 1 ansible.builtin.systemd: name: keycloak enabled: true diff --git a/roles/keycloak_quarkus/templates/keycloak.service.j2 b/roles/keycloak_quarkus/templates/keycloak.service.j2 index 3cdfacf..9cabb69 100644 --- a/roles/keycloak_quarkus/templates/keycloak.service.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.service.j2 @@ -4,9 +4,7 @@ Description=Keycloak Server After=network.target [Service] -Type=simple EnvironmentFile=-{{ keycloak_quarkus_sysconf_file }} -PIDFile={{ keycloak_quarkus_service_pidfile }} {% if keycloak_quarkus_start_dev %} ExecStart={{ keycloak.home }}/bin/kc.sh start-dev {% else %} @@ -14,15 +12,22 @@ ExecStart={{ keycloak.home }}/bin/kc.sh start --optimized {% endif %} User={{ keycloak.service_user }} Group={{ keycloak.service_group }} +SuccessExitStatus=0 143 {% if keycloak_quarkus_service_restart_always %} Restart=always {% elif keycloak_quarkus_service_restart_on_failure %} Restart=on-failure {% endif %} RestartSec={{ keycloak_quarkus_service_restartsec }} -{% if keycloak_quarkus_http_port|int < 1024 or keycloak_quarkus_https_port|int < 1024 %} +{% if keycloak_quarkus_http_port | int < 1024 or keycloak_quarkus_https_port | int < 1024 %} AmbientCapabilities=CAP_NET_BIND_SERVICE {% endif %} +{% if keycloak_quarkus_systemd_wait_for_port %} +ExecStartPost=/usr/bin/timeout {{ keycloak_quarkus_systemd_wait_for_timeout }} sh -c 'while ! ss -H -t -l -n sport = :{{ keycloak_quarkus_https_port }} | grep -q "^LISTEN.*:{{ keycloak_quarkus_https_port }}"; do sleep 1; done && /bin/sleep {{ keycloak_quarkus_systemd_wait_for_delay }}' +{% endif %} +{% if keycloak_quarkus_systemd_wait_for_log %} +ExecStartPost=/usr/bin/timeout {{ keycloak_quarkus_systemd_wait_for_timeout }} sh -c 'cat {{ keycloak.log.file }} | sed "/Profile.*activated/ q" && /bin/sleep {{ keycloak_quarkus_systemd_wait_for_delay }}' +{% endif %} [Install] WantedBy=multi-user.target From 213a9a07665aa3a0e48c801343e6f2b4e3866fe8 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 24 Apr 2024 17:56:15 +0200 Subject: [PATCH 087/205] ci: downstream molecule fixes --- molecule/quarkus/prepare.yml | 5 +++++ roles/keycloak_quarkus/README.md | 1 - roles/keycloak_quarkus/tasks/prereqs.yml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/molecule/quarkus/prepare.yml b/molecule/quarkus/prepare.yml index 0095226..e3306e5 100644 --- a/molecule/quarkus/prepare.yml +++ b/molecule/quarkus/prepare.yml @@ -21,6 +21,11 @@ path: "/opt/keycloak/certs/" mode: 0755 + - name: Make sure a jre is available (for keytool to prepare keystore) + ansible.builtin.package: + name: java-17-openjdk-headless + state: present + - name: Create vault keystore ansible.builtin.command: keytool -importpass -alias TestRealm_testalias -keystore keystore.p12 -storepass keystorepassword delegate_to: localhost diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 5d0641c..f1d17fb 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -13,7 +13,6 @@ Role Defaults |:---------|:------------|:--------| |`keycloak_quarkus_version`| keycloak.org package version | `24.0.3` | |`keycloak_quarkus_offline_install` | Perform an offline install | `False`| -|`keycloak_quarkus_version`| keycloak.org package version | `23.0.7` | |`keycloak_quarkus_dest`| Installation root path | `/opt/keycloak` | |`keycloak_quarkus_download_url` | Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}` | diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index d96c09e..4f9eec9 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -44,7 +44,7 @@ packages_list: "{{ keycloak_quarkus_prereq_package_list }}" - name: "Validate keytool" - when: keycloak.config_key_store_enabled + when: keycloak_quarkus_config_key_store_password | length > 0 block: - name: "Attempt to run keytool" changed_when: false From 4c056d886eb647a901af5d0e55680c74833bb356 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 24 Apr 2024 21:20:16 +0200 Subject: [PATCH 088/205] ci: downstream molecule fixes --- molecule/quarkus/prepare.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/molecule/quarkus/prepare.yml b/molecule/quarkus/prepare.yml index e3306e5..1601a79 100644 --- a/molecule/quarkus/prepare.yml +++ b/molecule/quarkus/prepare.yml @@ -15,7 +15,7 @@ changed_when: False - name: Create conf directory # risky-file-permissions in test user account does not exist yet - become: yes + become: true ansible.builtin.file: state: directory path: "/opt/keycloak/certs/" @@ -25,6 +25,7 @@ ansible.builtin.package: name: java-17-openjdk-headless state: present + become: true - name: Create vault keystore ansible.builtin.command: keytool -importpass -alias TestRealm_testalias -keystore keystore.p12 -storepass keystorepassword @@ -34,7 +35,7 @@ failed_when: not 'already exists' in keytool_cmd.stdout and keytool_cmd.rc != 0 - name: Copy certificates and vault - become: yes + become: true ansible.builtin.copy: src: "{{ item }}" dest: "/opt/keycloak/certs/{{ item }}" From ac23e04d6ad053e0fcef7b9bf8b6d22ba0bfc69b Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 25 Apr 2024 08:16:56 +0200 Subject: [PATCH 089/205] ci: downstream molecule fixes --- roles/keycloak_quarkus/tasks/main.yml | 33 ++++++--------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index 4c0db72..2dadf61 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -32,29 +32,6 @@ tags: - install -- name: "Configure config for keycloak service" - ansible.builtin.template: - src: keycloak.conf.j2 - dest: "{{ keycloak.home }}/conf/keycloak.conf" - owner: "{{ keycloak.service_user }}" - group: "{{ keycloak.service_group }}" - mode: '0640' - become: true - notify: - - rebuild keycloak config - - restart keycloak - -- name: "Configure quarkus config for keycloak service" - ansible.builtin.template: - src: quarkus.properties.j2 - dest: "{{ keycloak.home }}/conf/quarkus.properties" - owner: "{{ keycloak.service_user }}" - group: "{{ keycloak.service_group }}" - mode: '0640' - become: true - notify: - - restart keycloak - - name: Create tcpping cluster node list ansible.builtin.set_fact: keycloak_quarkus_cluster_nodes: > @@ -69,14 +46,18 @@ loop: "{{ ansible_play_batch }}" when: keycloak_quarkus_ha_enabled and keycloak_quarkus_ha_discovery == 'TCPPING' -- name: "Configure infinispan config for keycloak service" +- name: "Configure config files for keycloak service" ansible.builtin.template: - src: cache-ispn.xml.j2 - dest: "{{ keycloak.home }}/conf/cache-ispn.xml" + src: "{{ item }}.j2" + dest: "{{ keycloak.home }}/conf/{{ item }}" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" mode: '0640' become: true + loop: + - keycloak.conf + - quarkus.properties + - cache-ispn.xml notify: - rebuild keycloak config - restart keycloak From 6967385c7fa8c2bede1db4e4f846369aee384a78 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 25 Apr 2024 13:03:03 +0200 Subject: [PATCH 090/205] ci: downstream molecule fixes --- molecule/quarkus/prepare.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/molecule/quarkus/prepare.yml b/molecule/quarkus/prepare.yml index 1601a79..28b42c6 100644 --- a/molecule/quarkus/prepare.yml +++ b/molecule/quarkus/prepare.yml @@ -22,10 +22,14 @@ mode: 0755 - name: Make sure a jre is available (for keytool to prepare keystore) + delegate_to: localhost ansible.builtin.package: - name: java-17-openjdk-headless + name: + - java-17-openjdk-headless + - openjdk-17-jdk-headless state: present become: true + failed_when: false - name: Create vault keystore ansible.builtin.command: keytool -importpass -alias TestRealm_testalias -keystore keystore.p12 -storepass keystorepassword From 278a70d62768e245e3df4a4feafdb9a3ce326e88 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 25 Apr 2024 13:57:31 +0200 Subject: [PATCH 091/205] ci: downstream molecule fixes --- molecule/quarkus/prepare.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/molecule/quarkus/prepare.yml b/molecule/quarkus/prepare.yml index 28b42c6..1efdb15 100644 --- a/molecule/quarkus/prepare.yml +++ b/molecule/quarkus/prepare.yml @@ -24,9 +24,7 @@ - name: Make sure a jre is available (for keytool to prepare keystore) delegate_to: localhost ansible.builtin.package: - name: - - java-17-openjdk-headless - - openjdk-17-jdk-headless + name: "{{ 'java-17-openjdk-headless' if hera_home | length > 0 else 'openjdk-17-jdk-headless' }}" state: present become: true failed_when: false From a33393a477844ecb8b27303c9b175990f914f431 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 25 Apr 2024 14:11:05 +0200 Subject: [PATCH 092/205] ci: downstream molecule fixes --- molecule/quarkus/verify.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/molecule/quarkus/verify.yml b/molecule/quarkus/verify.yml index 1efe9dd..dd8490f 100644 --- a/molecule/quarkus/verify.yml +++ b/molecule/quarkus/verify.yml @@ -53,7 +53,7 @@ fail_msg: "Service log symlink not correctly created" - name: Check log file - become: yes + become: true ansible.builtin.stat: path: /tmp/keycloak/keycloak.log register: keycloak_log_file @@ -77,6 +77,7 @@ - not keycloak_default_log_folder.stat.exists - name: Verify vault SPI in logfile + become: true ansible.builtin.shell: | set -o pipefail zgrep 'Configured KeystoreVaultProviderFactory with the keystore file' /opt/keycloak/keycloak-*/data/log/keycloak.log*zip From 43b9ffcb6486cd881394b00f4d7f333840093b48 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 30 Apr 2024 10:45:20 +0200 Subject: [PATCH 093/205] Providers config and custom providers --- molecule/quarkus/converge.yml | 10 +++++++ roles/keycloak_quarkus/README.md | 27 +++++++++++++++++++ roles/keycloak_quarkus/defaults/main.yml | 2 ++ .../keycloak_quarkus/meta/argument_specs.yml | 4 +++ roles/keycloak_quarkus/tasks/install.yml | 12 +++++++++ roles/keycloak_quarkus/tasks/prereqs.yml | 9 +++++++ .../templates/keycloak.conf.j2 | 11 ++++++++ 7 files changed, 75 insertions(+) diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index 0d59050..0480f9a 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -19,6 +19,16 @@ keycloak_quarkus_systemd_wait_for_timeout: 20 keycloak_quarkus_systemd_wait_for_delay: 2 keycloak_quarkus_systemd_wait_for_log: true + keycloak_quarkus_providers: + - id: http-client + spi: connections + default: true + restart: true + properties: + - key: default-connection-pool-size + value: 10 + - id: spid-saml + url: https://github.com/italia/spid-keycloak-provider/releases/download/24.0.2/spid-provider.jar roles: - role: keycloak_quarkus - role: keycloak_realm diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index f1d17fb..ed44e21 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -145,6 +145,33 @@ Role Defaults |`keycloak_quarkus_ks_vault_type`| Type of the keystore used for the vault SPI | `PKCS12` | +#### Configuring providers + +| Variable | Description | Default | +|:---------|:------------|:--------| +|`keycloak_quarkus_providers`| List of provider definitions; see below | `[]` | + +Provider definition: + +```yaml +keycloak_quarkus_providers: + - id: http-client # required + spi: connections # required if url is not specified + default: true # optional, whether to set default for spi, default false + restart: true # optional, whether to restart, default true + url: https://.../.../custom_spi.jar # optional, url for download + properties: # optional, list of key-values + - key: default-connection-pool-size + value: 10 +``` + +the definition above will generate the following build command: + +``` +bin/kc.sh build --spi-connections-provider=http-client --spi-connections-http-client-default-connection-pool-size=10 +``` + + Role Variables -------------- diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 1999dd8..771dc85 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -144,3 +144,5 @@ keycloak_quarkus_ks_vault_enabled: false keycloak_quarkus_ks_vault_file: "{{ keycloak_quarkus_config_dir }}/keystore.p12" keycloak_quarkus_ks_vault_type: PKCS12 keycloak_quarkus_ks_vault_pass: + +keycloak_quarkus_providers: [] diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 460c9a7..7d97e29 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -372,6 +372,10 @@ argument_specs: description: "Activation delay for service systemd unit (seconds)" default: 10 type: 'int' + keycloak_quarkus_providers: + description: "List of provider definition dicts: { 'id': str, 'spi': str, 'url': str, 'default': bool, 'properties': list of key/value }" + default: [] + type: "list" downstream: options: rhbk_version: diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index 085f3d7..d95887f 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -164,3 +164,15 @@ when: - rhbk_enable is defined and rhbk_enable - keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url is defined + +- name: "Download custom providers" + ansible.builtin.get_url: + url: "{{ item.url }}" + dest: "{{ keycloak.home }}/providers/{{ item.id }}.jar" + owner: "{{ keycloak.service_user }}" + group: "{{ keycloak.service_group }}" + mode: '0640' + become: true + loop: "{{ keycloak_quarkus_providers }}" + when: item.url is defined and item.url | length > 0 + notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or not item.restart else [] }}" diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index 4f9eec9..e0a76d5 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -56,3 +56,12 @@ when: keytool_check.rc != 0 ansible.builtin.fail: msg: "keytool NOT found in the PATH, but is required for setting up the configuration key store" + +- name: "Validate providers" + ansible.builtin.assert: + that: + - item.id is defined and item.id | length > 0 + - (item.spi is defined and item.spi | length > 0) or (item.url is defined and item.url | length > 0) + quiet: true + fail_msg: "Providers definition is incorrect; `id` and one of `spi` or `url` are mandatory. `key` and `value` are mandatory for each property" + loop: "{{ keycloak_quarkus_providers }}" diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index 065eea7..f55ee80 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -97,3 +97,14 @@ vault-file={{ keycloak_quarkus_ks_vault_file }} vault-type={{ keycloak_quarkus_ks_vault_type }} vault-pass={{ keycloak_quarkus_ks_vault_pass }} {% endif %} + + +# Providers +{% for provider in keycloak_quarkus_providers %} +{% if provider.default is defined and provider.default %} +spi-{{ provider.spi }}-provider={{ provider.id }} +{% endif %} +{% if provider.properties is defined %}{% for property in provider.properties %} +spi-{{ provider.spi }}-{{ provider.id }}-{{ property.key }}={{ property.value }} +{% endfor %}{% endif %} +{% endfor %} From eafc4586d67ff356c8f42bd63b3ad90656831d98 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 30 Apr 2024 13:09:27 +0200 Subject: [PATCH 094/205] ci: turn historicized docs off --- .github/workflows/docs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c1a95bf..540fe4f 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -15,3 +15,4 @@ jobs: with: fqcn: 'middleware_automation/keycloak' collection_fqcn: 'middleware_automation.keycloak' + historical_docs: 'false' From a7b9f0ef97132f0e9e5c1dfa77bb6267cdd80d47 Mon Sep 17 00:00:00 2001 From: Deven Phillips Date: Tue, 30 Apr 2024 14:27:42 -0400 Subject: [PATCH 095/205] Add option to override JDBC download parameters --- roles/keycloak_quarkus/meta/argument_specs.yml | 9 +++++++++ roles/keycloak_quarkus/tasks/jdbc_driver.yml | 13 +++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 460c9a7..c1ebe8f 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -372,6 +372,15 @@ argument_specs: description: "Activation delay for service systemd unit (seconds)" default: 10 type: 'int' + keycloak_quarkus_jdbc_download_url: + description: "Override the default Maven Central download URL for the JDBC driver" + type: "str" + keycloak_quarkus_jdbc_download_user: + description: "Set a username with which to authenticate when downloading JDBC drivers from an alternative location" + type: "str" + keycloak_quarkus_jdbc_download_pass: + description: "Set a password with which to authenticate when downloading JDBC drivers from an alternative location (requires keycloak_quarkus_jdbc_download_user)" + type: "str" downstream: options: rhbk_version: diff --git a/roles/keycloak_quarkus/tasks/jdbc_driver.yml b/roles/keycloak_quarkus/tasks/jdbc_driver.yml index 310509a..bcb7069 100644 --- a/roles/keycloak_quarkus/tasks/jdbc_driver.yml +++ b/roles/keycloak_quarkus/tasks/jdbc_driver.yml @@ -1,10 +1,19 @@ --- -- name: "Retrieve JDBC Driver from {{ keycloak_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url }}" +- name: Verify valid parameters for download credentials when specified + fail: + msg: >- + When JDBC driver download credentials are set, both the username and the password MUST be set + when: + - keycloak_jdbc_download_user is undefined and keycloak_jdbc_download_pass is not undefined + - keycloak_jdbc_download_pass is undefined and keycloak_jdbc_download_user is not undefined +- name: "Retrieve JDBC Driver from {{ keycloak_jdbc_download_user | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" ansible.builtin.get_url: - url: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url }}" + url: "{{ keycloak_jdbc_download_url | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" dest: "{{ keycloak.home }}/providers" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" + url_username: "{{ keycloak_jdbc_download_user | default(omit) }}" + url_password: "{{ keycloak_jdbc_download_pass | default(omit) }}" mode: '0640' become: true notify: From c2904bf20d24c9d17b974e5061c39369a3f5e604 Mon Sep 17 00:00:00 2001 From: Deven Phillips Date: Tue, 30 Apr 2024 14:48:10 -0400 Subject: [PATCH 096/205] Use FQCN for fail module --- roles/keycloak_quarkus/tasks/jdbc_driver.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/keycloak_quarkus/tasks/jdbc_driver.yml b/roles/keycloak_quarkus/tasks/jdbc_driver.yml index bcb7069..11fa385 100644 --- a/roles/keycloak_quarkus/tasks/jdbc_driver.yml +++ b/roles/keycloak_quarkus/tasks/jdbc_driver.yml @@ -1,6 +1,6 @@ --- -- name: Verify valid parameters for download credentials when specified - fail: +- name: "Verify valid parameters for download credentials when specified" + ansible.builtin.fail: msg: >- When JDBC driver download credentials are set, both the username and the password MUST be set when: From 55f6881b2f1e909a5b5b42431cd1f1fbd6588258 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Wed, 1 May 2024 14:44:01 +0000 Subject: [PATCH 097/205] Update changelog for release 2.2.0 Signed-off-by: ansible-middleware-core --- CHANGELOG.rst | 21 +++++++++++++++++++-- changelogs/changelog.yaml | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 89d0992..4366622 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,25 @@ middleware\_automation.keycloak Release Notes This changelog describes changes after version 0.2.6. +v2.2.0 +====== + +Major Changes +------------- + +- Support java keystore for configuration of sensitive options `#189 `_ + +Minor Changes +------------- + +- Add ``wait_for_port`` and ``wait_for_log`` systemd unit logic `#199 `_ +- Customize jdbc driver downloads, optional authentication `#202 `_ +- Keystore-based vault SPI configuration `#196 `_ +- New ``keycloak_quarkus_hostname_strict_https`` parameter `#195 `_ +- Providers config and custom providers `#201 `_ +- Remove administrator credentials from files once keycloak is bootstrapped `#197 `_ +- Update keycloak to 24.0 `#194 `_ + v2.1.2 ====== @@ -14,7 +33,6 @@ Release Summary Internal release, documentation or test changes only. - v2.1.1 ====== @@ -286,7 +304,6 @@ Release Summary Internal release, documentation or test changes only. - v1.0.3 ====== diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 3fd8b1b..a58a5d6 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -464,3 +464,42 @@ releases: ' release_date: '2024-04-17' + 2.2.0: + changes: + major_changes: + - 'Support java keystore for configuration of sensitive options `#189 `_ + + ' + minor_changes: + - 'Add ``wait_for_port`` and ``wait_for_log`` systemd unit logic `#199 `_ + + ' + - 'Customize jdbc driver downloads, optional authentication `#202 `_ + + ' + - 'Keystore-based vault SPI configuration `#196 `_ + + ' + - 'New ``keycloak_quarkus_hostname_strict_https`` parameter `#195 `_ + + ' + - 'Providers config and custom providers `#201 `_ + + ' + - 'Remove administrator credentials from files once keycloak is bootstrapped + `#197 `_ + + ' + - 'Update keycloak to 24.0 `#194 `_ + + ' + fragments: + - 189.yaml + - 194.yaml + - 195.yaml + - 196.yaml + - 197.yaml + - 199.yaml + - 201.yaml + - 202.yaml + release_date: '2024-05-01' From 9e6a6f607612bf4585eccf022ff9f3f7559caa8d Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Wed, 1 May 2024 14:44:15 +0000 Subject: [PATCH 098/205] Bump version to 2.2.1 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index 02838e3..d121f3c 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.2.0" +version: "2.2.1" readme: README.md authors: - Romain Pelisse From 1a73c39a9140c7e0132e0211e3726191b61075d9 Mon Sep 17 00:00:00 2001 From: Deven Phillips Date: Thu, 2 May 2024 12:09:36 -0400 Subject: [PATCH 099/205] Fix logic in when clause --- roles/keycloak_quarkus/tasks/jdbc_driver.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/roles/keycloak_quarkus/tasks/jdbc_driver.yml b/roles/keycloak_quarkus/tasks/jdbc_driver.yml index 11fa385..10731cf 100644 --- a/roles/keycloak_quarkus/tasks/jdbc_driver.yml +++ b/roles/keycloak_quarkus/tasks/jdbc_driver.yml @@ -4,8 +4,7 @@ msg: >- When JDBC driver download credentials are set, both the username and the password MUST be set when: - - keycloak_jdbc_download_user is undefined and keycloak_jdbc_download_pass is not undefined - - keycloak_jdbc_download_pass is undefined and keycloak_jdbc_download_user is not undefined + - (keycloak_jdbc_download_user is undefined and keycloak_jdbc_download_pass is not undefined) or (keycloak_jdbc_download_pass is undefined and keycloak_jdbc_download_user is not undefined) - name: "Retrieve JDBC Driver from {{ keycloak_jdbc_download_user | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" ansible.builtin.get_url: url: "{{ keycloak_jdbc_download_url | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" From 978494524fd850f396245c4302a2f5eb5eb24f67 Mon Sep 17 00:00:00 2001 From: Deven Phillips Date: Thu, 2 May 2024 12:31:16 -0400 Subject: [PATCH 100/205] Fix errors introduced --- roles/keycloak_quarkus/tasks/jdbc_driver.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/keycloak_quarkus/tasks/jdbc_driver.yml b/roles/keycloak_quarkus/tasks/jdbc_driver.yml index 10731cf..dc84880 100644 --- a/roles/keycloak_quarkus/tasks/jdbc_driver.yml +++ b/roles/keycloak_quarkus/tasks/jdbc_driver.yml @@ -3,8 +3,8 @@ ansible.builtin.fail: msg: >- When JDBC driver download credentials are set, both the username and the password MUST be set - when: - - (keycloak_jdbc_download_user is undefined and keycloak_jdbc_download_pass is not undefined) or (keycloak_jdbc_download_pass is undefined and keycloak_jdbc_download_user is not undefined) + when: + - (keycloak_jdbc_download_user is undefined and keycloak_jdbc_download_pass is not undefined) or (keycloak_jdbc_download_pass is undefined and keycloak_jdbc_download_user is not undefined) - name: "Retrieve JDBC Driver from {{ keycloak_jdbc_download_user | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" ansible.builtin.get_url: url: "{{ keycloak_jdbc_download_url | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" From 1ab3ebc2a4dfdf54cc4fc19f091a58d31af1fd89 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Thu, 2 May 2024 16:59:47 +0000 Subject: [PATCH 101/205] Update changelog for release 2.2.1 Signed-off-by: ansible-middleware-core --- CHANGELOG.rst | 13 +++++++++++++ changelogs/changelog.yaml | 11 +++++++++++ 2 files changed, 24 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4366622..145a090 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,19 @@ middleware\_automation.keycloak Release Notes This changelog describes changes after version 0.2.6. +v2.2.1 +====== + +Release Summary +--------------- + +Internal release, documentation or test changes only. + +Bugfixes +-------- + +- JDBC provider: fix clause in argument validation `#204 `_ + v2.2.0 ====== diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index a58a5d6..400d633 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -503,3 +503,14 @@ releases: - 201.yaml - 202.yaml release_date: '2024-05-01' + 2.2.1: + changes: + bugfixes: + - 'JDBC provider: fix clause in argument validation `#204 `_ + + ' + release_summary: Internal release, documentation or test changes only. + fragments: + - 204.yaml + - v2.2.1-devel_summary.yaml + release_date: '2024-05-02' From 1d6a6eb7ee2449f41528d30d2ff4eed0c7ae98d2 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Thu, 2 May 2024 17:00:01 +0000 Subject: [PATCH 102/205] Bump version to 2.2.2 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index d121f3c..ae08f9b 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.2.1" +version: "2.2.2" readme: README.md authors: - Romain Pelisse From b14d75dfab246ed38f97158c98aeb014f691a6e3 Mon Sep 17 00:00:00 2001 From: Deven Phillips Date: Thu, 2 May 2024 14:33:36 -0400 Subject: [PATCH 103/205] jdbc_download and validate_certs params update - Added jdbc_download customization to both keycloak releases - Added option to allow invalid certificates to download JDBC drivers --- github.json | 0 roles/keycloak/meta/argument_specs.yml | 13 +++++++++++++ roles/keycloak/tasks/jdbc_driver.yml | 9 +++++++++ roles/keycloak_quarkus/meta/argument_specs.yml | 4 ++++ roles/keycloak_quarkus/tasks/jdbc_driver.yml | 9 +++++---- 5 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 github.json diff --git a/github.json b/github.json new file mode 100644 index 0000000..e69de29 diff --git a/roles/keycloak/meta/argument_specs.yml b/roles/keycloak/meta/argument_specs.yml index 7ba6509..eab89cf 100644 --- a/roles/keycloak/meta/argument_specs.yml +++ b/roles/keycloak/meta/argument_specs.yml @@ -316,6 +316,19 @@ argument_specs: default: '/var/log/keycloak' type: "str" description: "Set the destination of the keycloak log folder link" + keycloak_jdbc_download_url: + description: "Override the default Maven Central download URL for the JDBC driver" + type: "str" + keycloak_jdbc_download_user: + description: "Set a username with which to authenticate when downloading JDBC drivers from an alternative location" + type: "str" + keycloak_jdbc_download_pass: + description: "Set a password with which to authenticate when downloading JDBC drivers from an alternative location (requires keycloak_jdbc_download_user)" + type: "str" + keycloak_jdbc_download_validate_certs: + default: true + description: "Allow the option to ignore invalid certificates when downloading JDBC drivers from a custom URL" + type: "bool" downstream: options: sso_version: diff --git a/roles/keycloak/tasks/jdbc_driver.yml b/roles/keycloak/tasks/jdbc_driver.yml index 1b0a1ec..a7cd8ab 100644 --- a/roles/keycloak/tasks/jdbc_driver.yml +++ b/roles/keycloak/tasks/jdbc_driver.yml @@ -16,6 +16,12 @@ become: true when: - not dest_path.stat.exists +- name: "Verify valid parameters for download credentials when specified" + ansible.builtin.fail: + msg: >- + When JDBC driver download credentials are set, both the username and the password MUST be set + when: + - (keycloak_jdbc_download_user is undefined and keycloak_jdbc_download_pass is not undefined) or (keycloak_jdbc_download_pass is undefined and keycloak_jdbc_download_user is not undefined) - name: "Retrieve JDBC Driver from {{ keycloak_jdbc[keycloak_jdbc_engine].driver_jar_url }}" ansible.builtin.get_url: @@ -23,6 +29,9 @@ dest: "{{ keycloak_jdbc[keycloak_jdbc_engine].driver_module_dir }}/{{ keycloak_jdbc[keycloak_jdbc_engine].driver_jar_filename }}" group: "{{ keycloak_service_group }}" owner: "{{ keycloak_service_user }}" + url_username: "{{ keycloak_jdbc_download_user | default(omit) }}" + url_password: "{{ keycloak_jdbc_download_pass | default(omit) }}" + validate_certs: "{{ keycloak_jdbc_download_validate_certs | default(omit) }}" mode: 0640 become: true diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 0669dc5..538e0ab 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -385,6 +385,10 @@ argument_specs: keycloak_quarkus_jdbc_download_pass: description: "Set a password with which to authenticate when downloading JDBC drivers from an alternative location (requires keycloak_quarkus_jdbc_download_user)" type: "str" + keycloak_quarkus_jdbc_download_validate_certs: + default: true + description: "Allow the option to ignore invalid certificates when downloading JDBC drivers from a custom URL" + type: "bool" downstream: options: rhbk_version: diff --git a/roles/keycloak_quarkus/tasks/jdbc_driver.yml b/roles/keycloak_quarkus/tasks/jdbc_driver.yml index dc84880..52298aa 100644 --- a/roles/keycloak_quarkus/tasks/jdbc_driver.yml +++ b/roles/keycloak_quarkus/tasks/jdbc_driver.yml @@ -4,15 +4,16 @@ msg: >- When JDBC driver download credentials are set, both the username and the password MUST be set when: - - (keycloak_jdbc_download_user is undefined and keycloak_jdbc_download_pass is not undefined) or (keycloak_jdbc_download_pass is undefined and keycloak_jdbc_download_user is not undefined) + - (keycloak_quarkus_jdbc_download_user is undefined and keycloak_quarkus_jdbc_download_pass is not undefined) or (keycloak_quarkus_jdbc_download_pass is undefined and keycloak_quarkus_jdbc_download_user is not undefined) - name: "Retrieve JDBC Driver from {{ keycloak_jdbc_download_user | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" ansible.builtin.get_url: - url: "{{ keycloak_jdbc_download_url | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" + url: "{{ keycloak_quarkus_jdbc_download_url | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" dest: "{{ keycloak.home }}/providers" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" - url_username: "{{ keycloak_jdbc_download_user | default(omit) }}" - url_password: "{{ keycloak_jdbc_download_pass | default(omit) }}" + url_username: "{{ keycloak_quarkus_jdbc_download_user | default(omit) }}" + url_password: "{{ keycloak_quarkus_jdbc_download_pass | default(omit) }}" + validate_certs: "{{ keycloak_quarkus_jdbc_download_validate_certs | default(omit) }}" mode: '0640' become: true notify: From feec4d9f8b866150f759ae7eb9c9ace87df2ab4a Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Fri, 3 May 2024 13:03:18 +0200 Subject: [PATCH 104/205] controller priv escalation --- roles/keycloak_quarkus/tasks/install.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index d95887f..7155c3a 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -57,6 +57,7 @@ path: "{{ lookup('env', 'PWD') }}" register: local_path delegate_to: localhost + run_once: true become: false - name: Download keycloak archive @@ -108,15 +109,20 @@ client_secret: "{{ rhn_password }}" product_id: "{{ (rhn_filtered_products | first).id }}" dest: "{{ local_path.stat.path }}/{{ keycloak.bundle }}" + mode: '0640' + owner: "{{ lookup('env', 'USER') | default(omit) }}" no_log: "{{ omit_rhn_output | default(true) }}" delegate_to: localhost run_once: true + become: false - name: Check downloaded archive ansible.builtin.stat: path: "{{ local_path.stat.path }}/{{ keycloak.bundle }}" register: local_archive_path delegate_to: localhost + become: false + run_once: true ## copy and unpack - name: Copy archive to target nodes From 9bc1ae69e9a8af0c720b910197a818f365c2e84f Mon Sep 17 00:00:00 2001 From: Footur <3769085+Footur@users.noreply.github.com> Date: Fri, 3 May 2024 14:34:57 +0000 Subject: [PATCH 105/205] Enable copying of key material This commit updates the configuration to use the standard Red Hat Enterprise Linux (RHEL) default path for TLS certificates, which is /etc/pki/tls. Also, it copies the private key and certificate to the target host. --- roles/keycloak_quarkus/README.md | 8 ++++-- roles/keycloak_quarkus/defaults/main.yml | 8 ++++-- .../keycloak_quarkus/meta/argument_specs.yml | 20 ++++++++++++-- roles/keycloak_quarkus/tasks/install.yml | 26 +++++++++++++++++++ 4 files changed, 56 insertions(+), 6 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index ed44e21..17f2bc8 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -44,8 +44,12 @@ Role Defaults |`keycloak_quarkus_http_relative_path` | Set the path relative to / for serving resources. The path must start with a / | `/` | |`keycloak_quarkus_http_enabled`| Enable listener on HTTP port | `True` | |`keycloak_quarkus_https_key_file_enabled`| Enable listener on HTTPS port | `False` | -|`keycloak_quarkus_key_file`| The file path to a private key in PEM format | `{{ keycloak.home }}/conf/server.key.pem` | -|`keycloak_quarkus_cert_file`| The file path to a server certificate or certificate chain in PEM format | `{{ keycloak.home }}/conf/server.crt.pem` | +|`keycloak_quarkus_key_file_copy_enabled`| Enable copy of key file to target host | `False` | +|`keycloak_quarkus_key_file_src`| Set the source file path | `""` | +|`keycloak_quarkus_key_file`| The file path to a private key in PEM format | `/etc/pki/tls/private/server.key.pem` | +|`keycloak_quarkus_cert_file_copy_enabled`| Enable copy of cert file to target host | `False`| +|`keycloak_quarkus_cert_file_src`| Set the source file path | `""` | +|`keycloak_quarkus_cert_file`| The file path to a server certificate or certificate chain in PEM format | `/etc/pki/tls/certs/server.crt.pem` | |`keycloak_quarkus_https_key_store_enabled`| Enable configuration of HTTPS via a key store | `False` | |`keycloak_quarkus_key_store_file`| Deprecated, use `keycloak_quarkus_https_key_store_file` instead. || |`keycloak_quarkus_key_store_password`| Deprecated, use `keycloak_quarkus_https_key_store_password` instead.|| diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 771dc85..fcd02a5 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -47,8 +47,12 @@ keycloak_quarkus_java_opts: "{{ keycloak_quarkus_java_heap_opts + ' ' + keycloak ### TLS/HTTPS configuration keycloak_quarkus_https_key_file_enabled: false -keycloak_quarkus_key_file: "{{ keycloak.home }}/conf/server.key.pem" -keycloak_quarkus_cert_file: "{{ keycloak.home }}/conf/server.crt.pem" +keycloak_quarkus_key_file_copy_enabled: false +keycloak_quarkus_key_file_src: "" +keycloak_quarkus_key_file: "/etc/pki/tls/private/server.key.pem" +keycloak_quarkus_cert_file_copy_enabled: false +keycloak_quarkus_cert_file_src: "" +keycloak_quarkus_cert_file: "/etc/pki/tls/certs/server.crt.pem" #### key store configuration keycloak_quarkus_https_key_store_enabled: false keycloak_quarkus_https_key_store_file: "{{ keycloak.home }}/conf/key_store.p12" diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 538e0ab..768b3e9 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -108,12 +108,28 @@ argument_specs: default: false description: "Enable configuration of HTTPS via files in PEM format" type: "bool" + keycloak_quarkus_key_file_copy_enabled: + default: false + description: "Enable copy of key file to target host" + type: "bool" + keycloak_quarkus_key_file_src: + default: "" + description: "Set the source file path" + type: "str" keycloak_quarkus_key_file: - default: "{{ keycloak.home }}/conf/server.key.pem" + default: "/etc/pki/tls/private/server.key.pem" description: "The file path to a private key in PEM format" type: "str" + keycloak_quarkus_cert_file_copy_enabled: + default: false + description: "Enable copy of cert file to target host" + type: "bool" + keycloak_quarkus_cert_file_src: + default: "" + description: "Set the source file path" + type: "str" keycloak_quarkus_cert_file: - default: "{{ keycloak.home }}/conf/server.crt.pem" + default: "/etc/pki/tls/certs/server.crt.pem" description: "The file path to a server certificate or certificate chain in PEM format" type: "str" keycloak_quarkus_https_key_store_enabled: diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index d95887f..b4b566a 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -159,6 +159,32 @@ when: - (not new_version_downloaded.changed) and path_to_workdir.stat.exists +- name: "Copy private key to target" + ansible.builtin.copy: + src: "{{ keycloak_quarkus_key_file_src }}" + dest: "{{ keycloak_quarkus_key_file }}" + owner: "{{ keycloak.service_user }}" + group: "{{ keycloak.service_group }}" + mode: 0640 + become: true + when: + - keycloak_quarkus_https_key_file_enabled is defined and keycloak_quarkus_https_key_file_enabled + - keycloak_quarkus_key_file_copy_enabled is defined and keycloak_quarkus_key_file_copy_enabled + - keycloak_quarkus_key_file_src | length > 0 + +- name: "Copy certificate to target" + ansible.builtin.copy: + src: "{{ keycloak_quarkus_cert_file_src }}" + dest: "{{ keycloak_quarkus_cert_file }}" + owner: "{{ keycloak.service_user }}" + group: "{{ keycloak.service_group }}" + mode: 0644 + become: true + when: + - keycloak_quarkus_https_key_file_enabled is defined and keycloak_quarkus_https_key_file_enabled + - keycloak_quarkus_cert_file_copy_enabled is defined and keycloak_quarkus_cert_file_copy_enabled + - keycloak_quarkus_cert_file_src | length > 0 + - name: "Install {{ keycloak_quarkus_jdbc_engine }} JDBC driver" ansible.builtin.include_tasks: jdbc_driver.yml when: From 7141e1c9b2d53469ddfebb5cf24ef6a740bca64c Mon Sep 17 00:00:00 2001 From: Footur <3769085+Footur@users.noreply.github.com> Date: Sun, 5 May 2024 12:08:14 +0200 Subject: [PATCH 106/205] Test: Installation of key material via Ansible role --- molecule/quarkus/converge.yml | 8 +++++--- molecule/quarkus/prepare.yml | 12 ++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index 0480f9a..5971a93 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -9,11 +9,13 @@ keycloak_quarkus_log: file keycloak_quarkus_log_level: debug keycloak_quarkus_https_key_file_enabled: true - keycloak_quarkus_key_file: "/opt/keycloak/certs/key.pem" - keycloak_quarkus_cert_file: "/opt/keycloak/certs/cert.pem" + keycloak_quarkus_key_file_copy_enabled: true + keycloak_quarkus_key_file_src: key.pem + keycloak_quarkus_cert_file_copy_enabled: true + keycloak_quarkus_cert_file_src: cert.pem keycloak_quarkus_log_target: /tmp/keycloak keycloak_quarkus_ks_vault_enabled: true - keycloak_quarkus_ks_vault_file: "/opt/keycloak/certs/keystore.p12" + keycloak_quarkus_ks_vault_file: "/opt/keycloak/vault/keystore.p12" keycloak_quarkus_ks_vault_pass: keystorepassword keycloak_quarkus_systemd_wait_for_port: true keycloak_quarkus_systemd_wait_for_timeout: 20 diff --git a/molecule/quarkus/prepare.yml b/molecule/quarkus/prepare.yml index 1efdb15..459bafa 100644 --- a/molecule/quarkus/prepare.yml +++ b/molecule/quarkus/prepare.yml @@ -14,11 +14,11 @@ delegate_to: localhost changed_when: False - - name: Create conf directory # risky-file-permissions in test user account does not exist yet + - name: Create vault directory become: true ansible.builtin.file: state: directory - path: "/opt/keycloak/certs/" + path: "/opt/keycloak/vault" mode: 0755 - name: Make sure a jre is available (for keytool to prepare keystore) @@ -39,10 +39,6 @@ - name: Copy certificates and vault become: true ansible.builtin.copy: - src: "{{ item }}" - dest: "/opt/keycloak/certs/{{ item }}" + src: keystore.p12 + dest: /opt/keycloak/vault/keystore.p12 mode: 0444 - loop: - - cert.pem - - key.pem - - keystore.p12 From 320a5f0d9a171aeb9dbe4bf6914dcedd42596d07 Mon Sep 17 00:00:00 2001 From: Footur <3769085+Footur@users.noreply.github.com> Date: Sun, 5 May 2024 11:58:19 +0000 Subject: [PATCH 107/205] Copy the TLS private key from memory This change should avoid storing plain private keys on disk due to security risks. It also makes it easier to encrypt the data with SOPS. --- molecule/quarkus/converge.yml | 2 +- roles/keycloak_quarkus/README.md | 2 +- roles/keycloak_quarkus/defaults/main.yml | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 4 ++-- roles/keycloak_quarkus/tasks/install.yml | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index 5971a93..9e74aa6 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -10,7 +10,7 @@ keycloak_quarkus_log_level: debug keycloak_quarkus_https_key_file_enabled: true keycloak_quarkus_key_file_copy_enabled: true - keycloak_quarkus_key_file_src: key.pem + keycloak_quarkus_key_content: "{{ lookup('file', 'key.pem') }}" keycloak_quarkus_cert_file_copy_enabled: true keycloak_quarkus_cert_file_src: cert.pem keycloak_quarkus_log_target: /tmp/keycloak diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 17f2bc8..ccb9e75 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -45,7 +45,7 @@ Role Defaults |`keycloak_quarkus_http_enabled`| Enable listener on HTTP port | `True` | |`keycloak_quarkus_https_key_file_enabled`| Enable listener on HTTPS port | `False` | |`keycloak_quarkus_key_file_copy_enabled`| Enable copy of key file to target host | `False` | -|`keycloak_quarkus_key_file_src`| Set the source file path | `""` | +|`keycloak_quarkus_key_content`| Content of the TLS private key. Use `"{{ lookup('file', 'server.key.pem') }}"` to lookup a file. | `""` | |`keycloak_quarkus_key_file`| The file path to a private key in PEM format | `/etc/pki/tls/private/server.key.pem` | |`keycloak_quarkus_cert_file_copy_enabled`| Enable copy of cert file to target host | `False`| |`keycloak_quarkus_cert_file_src`| Set the source file path | `""` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index fcd02a5..a54e6c7 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -48,7 +48,7 @@ keycloak_quarkus_java_opts: "{{ keycloak_quarkus_java_heap_opts + ' ' + keycloak ### TLS/HTTPS configuration keycloak_quarkus_https_key_file_enabled: false keycloak_quarkus_key_file_copy_enabled: false -keycloak_quarkus_key_file_src: "" +keycloak_quarkus_key_content: "" keycloak_quarkus_key_file: "/etc/pki/tls/private/server.key.pem" keycloak_quarkus_cert_file_copy_enabled: false keycloak_quarkus_cert_file_src: "" diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 768b3e9..094a46b 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -112,9 +112,9 @@ argument_specs: default: false description: "Enable copy of key file to target host" type: "bool" - keycloak_quarkus_key_file_src: + keycloak_quarkus_key_content: default: "" - description: "Set the source file path" + description: "Content of the TLS private key" type: "str" keycloak_quarkus_key_file: default: "/etc/pki/tls/private/server.key.pem" diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index b4b566a..5a385e2 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -161,7 +161,7 @@ - name: "Copy private key to target" ansible.builtin.copy: - src: "{{ keycloak_quarkus_key_file_src }}" + content: "{{ keycloak_quarkus_key_content }}" dest: "{{ keycloak_quarkus_key_file }}" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" @@ -170,7 +170,7 @@ when: - keycloak_quarkus_https_key_file_enabled is defined and keycloak_quarkus_https_key_file_enabled - keycloak_quarkus_key_file_copy_enabled is defined and keycloak_quarkus_key_file_copy_enabled - - keycloak_quarkus_key_file_src | length > 0 + - keycloak_quarkus_key_content | length > 0 - name: "Copy certificate to target" ansible.builtin.copy: From b427cb8a24624bf83d95c1a417bb20691f7df7c9 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Mon, 6 May 2024 08:11:11 +0000 Subject: [PATCH 108/205] Update changelog for release 2.2.2 Signed-off-by: ansible-middleware-core --- CHANGELOG.rst | 14 ++++++++++++++ changelogs/changelog.yaml | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 145a090..3d0f005 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,20 @@ middleware\_automation.keycloak Release Notes This changelog describes changes after version 0.2.6. +v2.2.2 +====== + +Minor Changes +------------- + +- Copying of key material for TLS configuration `#210 `_ +- Validate certs parameter for JDBC driver downloads `#207 `_ + +Bugfixes +-------- + +- Turn off controller privilege escalation `#209 `_ + v2.2.1 ====== diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 400d633..fe5c499 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -514,3 +514,21 @@ releases: - 204.yaml - v2.2.1-devel_summary.yaml release_date: '2024-05-02' + 2.2.2: + changes: + bugfixes: + - 'Turn off controller privilege escalation `#209 `_ + + ' + minor_changes: + - 'Copying of key material for TLS configuration `#210 `_ + + ' + - 'Validate certs parameter for JDBC driver downloads `#207 `_ + + ' + fragments: + - 207.yaml + - 209.yaml + - 210.yaml + release_date: '2024-05-06' From 4da0e83ae92ff21c95c5094158c469f9d23b3f2f Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Mon, 6 May 2024 08:11:28 +0000 Subject: [PATCH 109/205] Bump version to 2.2.3 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index ae08f9b..1e6fd20 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.2.2" +version: "2.2.3" readme: README.md authors: - Romain Pelisse From 2a7395c444df8fcd6af8aa1edf851de5e18f50b1 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 6 May 2024 11:20:00 +0200 Subject: [PATCH 110/205] downstream: update default to rhbk 24.0.3 --- galaxy.yml | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy.yml b/galaxy.yml index 1e6fd20..ae08f9b 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.2.3" +version: "2.2.2" readme: README.md authors: - Romain Pelisse diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 094a46b..5fccedc 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -408,7 +408,7 @@ argument_specs: downstream: options: rhbk_version: - default: "22.0.10" + default: "24.0.3" description: "Red Hat Build of Keycloak version" type: "str" rhbk_archive: From 70834ccf133e4c73375daf1ed6c39cf1fbf116d0 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 6 May 2024 12:03:44 +0200 Subject: [PATCH 111/205] downstream: remove problematic owner of downloaded zipfile --- roles/keycloak_quarkus/tasks/install.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index bbface7..732e5b1 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -110,7 +110,6 @@ product_id: "{{ (rhn_filtered_products | first).id }}" dest: "{{ local_path.stat.path }}/{{ keycloak.bundle }}" mode: '0640' - owner: "{{ lookup('env', 'USER') | default(omit) }}" no_log: "{{ omit_rhn_output | default(true) }}" delegate_to: localhost run_once: true From a45b18dc85ecf57802d450de9b4be83dfdc84319 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 6 May 2024 13:02:51 +0200 Subject: [PATCH 112/205] kc.sh build uses configured jdk --- roles/keycloak_quarkus/tasks/rebuild_config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/roles/keycloak_quarkus/tasks/rebuild_config.yml b/roles/keycloak_quarkus/tasks/rebuild_config.yml index 5a715c6..5d2247d 100644 --- a/roles/keycloak_quarkus/tasks/rebuild_config.yml +++ b/roles/keycloak_quarkus/tasks/rebuild_config.yml @@ -3,5 +3,8 @@ - name: "Rebuild {{ keycloak.service_name }} config" ansible.builtin.shell: | {{ keycloak.home }}/bin/kc.sh build + environment: + PATH: "{{ keycloak_quarkus_java_home | default(keycloak_quarkus_pkg_java_home, true) }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + JAVA_HOME: "{{ keycloak_quarkus_java_home | default(keycloak_quarkus_pkg_java_home, true) }}" become: true changed_when: true From b497e946cce42b49311d33fa458def1c63642e1f Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 7 May 2024 09:47:12 +0200 Subject: [PATCH 113/205] Bump tp 2.2.3 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index ae08f9b..1e6fd20 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.2.2" +version: "2.2.3" readme: README.md authors: - Romain Pelisse From 1115ee409a706e2453d5c9b321630ba08208e8e7 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 7 May 2024 10:18:43 +0200 Subject: [PATCH 114/205] Linter warnings fix pass --- .ansible-lint | 2 +- changelogs/config.yaml | 32 +++++++++---------- roles/keycloak/meta/argument_specs.yml | 10 ++++-- roles/keycloak/tasks/fastpackages.yml | 7 ++-- roles/keycloak/tasks/install.yml | 24 +++++++------- roles/keycloak/tasks/jdbc_driver.yml | 11 ++++--- roles/keycloak/tasks/prereqs.yml | 9 ++++-- roles/keycloak/tasks/restart_keycloak.yml | 2 +- roles/keycloak/tasks/rhsso_cli.yml | 2 +- roles/keycloak/tasks/rhsso_patch.yml | 12 +++---- roles/keycloak/tasks/systemd.yml | 6 ++-- roles/keycloak/vars/debian.yml | 5 +-- roles/keycloak/vars/main.yml | 14 +++++--- roles/keycloak_quarkus/handlers/main.yml | 2 +- .../keycloak_quarkus/meta/argument_specs.yml | 8 +++-- roles/keycloak_quarkus/tasks/install.yml | 4 +-- roles/keycloak_quarkus/tasks/jdbc_driver.yml | 8 +++-- 17 files changed, 90 insertions(+), 68 deletions(-) diff --git a/.ansible-lint b/.ansible-lint index 92e5eaf..9c2702e 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -28,7 +28,6 @@ warn_list: - name[casing] - fqcn[action] - schema[meta] - - var-naming[no-role-prefix] - key-order[task] - blocked_modules @@ -36,6 +35,7 @@ skip_list: - vars_should_not_be_used - file_is_small_enough - name[template] + - var-naming[no-role-prefix] use_default_rules: true parseable: true diff --git a/changelogs/config.yaml b/changelogs/config.yaml index 374ae65..3c7fb7e 100644 --- a/changelogs/config.yaml +++ b/changelogs/config.yaml @@ -11,22 +11,22 @@ notesdir: fragments prelude_section_name: release_summary prelude_section_title: Release Summary sections: -- - major_changes - - Major Changes -- - minor_changes - - Minor Changes -- - breaking_changes - - Breaking Changes / Porting Guide -- - deprecated_features - - Deprecated Features -- - removed_features - - Removed Features -- - security_fixes - - Security Fixes -- - bugfixes - - Bugfixes -- - known_issues - - Known Issues + - - major_changes + - Major Changes + - - minor_changes + - Minor Changes + - - breaking_changes + - Breaking Changes / Porting Guide + - - deprecated_features + - Deprecated Features + - - removed_features + - Removed Features + - - security_fixes + - Security Fixes + - - bugfixes + - Bugfixes + - - known_issues + - Known Issues title: middleware_automation.keycloak trivial_section_name: trivial use_fqcn: true diff --git a/roles/keycloak/meta/argument_specs.yml b/roles/keycloak/meta/argument_specs.yml index eab89cf..5f6052d 100644 --- a/roles/keycloak/meta/argument_specs.yml +++ b/roles/keycloak/meta/argument_specs.yml @@ -86,7 +86,9 @@ argument_specs: type: "str" keycloak_features: default: "[]" - description: "List of `name`/`status` pairs of features (also known as profiles on RH-SSO) to `enable` or `disable`, example: `[ { name: 'docker', status: 'enabled' } ]`" + description: > + List of `name`/`status` pairs of features (also known as profiles on RH-SSO) to `enable` or `disable`, + example: `[ { name: 'docker', status: 'enabled' } ]` type: "list" keycloak_bind_address: default: "0.0.0.0" @@ -310,7 +312,8 @@ argument_specs: type: "str" keycloak_jgroups_subnet: required: false - description: "Override the subnet match for jgroups cluster formation; if not defined, it will be inferred from local machine route configuration" + description: > + Override the subnet match for jgroups cluster formation; if not defined, it will be inferred from local machine route configuration type: "str" keycloak_log_target: default: '/var/log/keycloak' @@ -323,7 +326,8 @@ argument_specs: description: "Set a username with which to authenticate when downloading JDBC drivers from an alternative location" type: "str" keycloak_jdbc_download_pass: - description: "Set a password with which to authenticate when downloading JDBC drivers from an alternative location (requires keycloak_jdbc_download_user)" + description: > + Set a password with which to authenticate when downloading JDBC drivers from an alternative location (requires keycloak_jdbc_download_user) type: "str" keycloak_jdbc_download_validate_certs: default: true diff --git a/roles/keycloak/tasks/fastpackages.yml b/roles/keycloak/tasks/fastpackages.yml index 3b557ef..be34c72 100644 --- a/roles/keycloak/tasks/fastpackages.yml +++ b/roles/keycloak/tasks/fastpackages.yml @@ -8,7 +8,8 @@ - name: "Add missing packages to the yum install list" ansible.builtin.set_fact: - packages_to_install: "{{ packages_to_install | default([]) + rpm_info.stdout_lines | map('regex_findall', 'package (.+) is not installed$') | default([]) | flatten }}" + packages_to_install: "{{ packages_to_install | default([]) + rpm_info.stdout_lines | \ + map('regex_findall', 'package (.+) is not installed$') | default([]) | flatten }}" when: ansible_facts.os_family == "RedHat" - name: "Install packages: {{ packages_to_install }}" @@ -17,8 +18,8 @@ name: "{{ packages_to_install }}" state: present when: - - packages_to_install | default([]) | length > 0 - - ansible_facts.os_family == "RedHat" + - packages_to_install | default([]) | length > 0 + - ansible_facts.os_family == "RedHat" - name: "Install packages: {{ packages_list }}" become: true diff --git a/roles/keycloak/tasks/install.yml b/roles/keycloak/tasks/install.yml index 67b98cd..b620b03 100644 --- a/roles/keycloak/tasks/install.yml +++ b/roles/keycloak/tasks/install.yml @@ -41,8 +41,8 @@ ansible.builtin.user: name: "{{ keycloak_service_user }}" home: /opt/keycloak - system: yes - create_home: no + system: true + create_home: false - name: "Create install location for {{ keycloak.service_name }}" become: true @@ -51,7 +51,7 @@ state: directory owner: "{{ keycloak_service_user }}" group: "{{ keycloak_service_group }}" - mode: 0750 + mode: '0750' - name: Create pidfile folder become: true @@ -60,7 +60,7 @@ state: directory owner: "{{ keycloak_service_user if keycloak_service_runas else omit }}" group: "{{ keycloak_service_group if keycloak_service_runas else omit }}" - mode: 0750 + mode: '0750' ## check remote archive - name: Set download archive path @@ -84,7 +84,7 @@ ansible.builtin.get_url: # noqa risky-file-permissions delegated, uses controller host user url: "{{ keycloak_download_url }}" dest: "{{ local_path.stat.path }}/{{ keycloak.bundle }}" - mode: 0644 + mode: '0644' delegate_to: localhost run_once: true when: @@ -136,7 +136,7 @@ ansible.builtin.get_url: # noqa risky-file-permissions delegated, uses controller host user url: "{{ keycloak_rhsso_download_url }}" dest: "{{ local_path.stat.path }}/{{ keycloak.bundle }}" - mode: 0644 + mode: '0644' delegate_to: localhost run_once: true when: @@ -160,7 +160,7 @@ dest: "{{ archive }}" owner: "{{ keycloak_service_user }}" group: "{{ keycloak_service_group }}" - mode: 0640 + mode: '0640' register: new_version_downloaded when: - not archive_path.stat.exists @@ -221,7 +221,7 @@ dest: "{{ keycloak_config_path_to_standalone_xml }}" owner: "{{ keycloak_service_user }}" group: "{{ keycloak_service_group }}" - mode: 0640 + mode: '0640' notify: - restart keycloak when: keycloak_config_override_template | length > 0 @@ -233,7 +233,7 @@ dest: "{{ keycloak_config_path_to_standalone_xml }}" owner: "{{ keycloak_service_user }}" group: "{{ keycloak_service_group }}" - mode: 0640 + mode: '0640' notify: - restart keycloak when: @@ -261,7 +261,7 @@ dest: "{{ keycloak_config_path_to_standalone_xml }}" owner: "{{ keycloak_service_user }}" group: "{{ keycloak_service_group }}" - mode: 0640 + mode: '0640' notify: - restart keycloak when: @@ -276,7 +276,7 @@ dest: "{{ keycloak_config_path_to_standalone_xml }}" owner: "{{ keycloak_service_user }}" group: "{{ keycloak_service_group }}" - mode: 0640 + mode: '0640' notify: - restart keycloak when: @@ -291,7 +291,7 @@ dest: "{{ keycloak_config_path_to_properties }}" owner: "{{ keycloak_service_user }}" group: "{{ keycloak_service_group }}" - mode: 0640 + mode: '0640' notify: - restart keycloak when: keycloak_features | length > 0 diff --git a/roles/keycloak/tasks/jdbc_driver.yml b/roles/keycloak/tasks/jdbc_driver.yml index a7cd8ab..bec80e3 100644 --- a/roles/keycloak/tasks/jdbc_driver.yml +++ b/roles/keycloak/tasks/jdbc_driver.yml @@ -12,7 +12,7 @@ recurse: true owner: "{{ keycloak_service_user }}" group: "{{ keycloak_service_group }}" - mode: 0750 + mode: '0750' become: true when: - not dest_path.stat.exists @@ -20,8 +20,9 @@ ansible.builtin.fail: msg: >- When JDBC driver download credentials are set, both the username and the password MUST be set - when: - - (keycloak_jdbc_download_user is undefined and keycloak_jdbc_download_pass is not undefined) or (keycloak_jdbc_download_pass is undefined and keycloak_jdbc_download_user is not undefined) + when: > + (keycloak_jdbc_download_user is undefined and keycloak_jdbc_download_pass is not undefined) or + (keycloak_jdbc_download_pass is undefined and keycloak_jdbc_download_user is not undefined) - name: "Retrieve JDBC Driver from {{ keycloak_jdbc[keycloak_jdbc_engine].driver_jar_url }}" ansible.builtin.get_url: @@ -32,7 +33,7 @@ url_username: "{{ keycloak_jdbc_download_user | default(omit) }}" url_password: "{{ keycloak_jdbc_download_pass | default(omit) }}" validate_certs: "{{ keycloak_jdbc_download_validate_certs | default(omit) }}" - mode: 0640 + mode: '0640' become: true - name: "Deploy module.xml for JDBC Driver" @@ -41,5 +42,5 @@ dest: "{{ keycloak_jdbc[keycloak_jdbc_engine].driver_module_dir }}/module.xml" group: "{{ keycloak_service_group }}" owner: "{{ keycloak_service_user }}" - mode: 0640 + mode: '0640' become: true diff --git a/roles/keycloak/tasks/prereqs.yml b/roles/keycloak/tasks/prereqs.yml index c92bb1c..d97390c 100644 --- a/roles/keycloak/tasks/prereqs.yml +++ b/roles/keycloak/tasks/prereqs.yml @@ -4,13 +4,16 @@ that: - keycloak_admin_password | length > 12 quiet: true - fail_msg: "The console administrator password is empty or invalid. Please set the keycloak_admin_password variable to a 12+ char long string" + fail_msg: > + The console administrator password is empty or invalid. Please set the keycloak_admin_password variable to a 12+ char long string success_msg: "{{ 'Console administrator password OK' }}" - name: Validate configuration ansible.builtin.assert: - that: - - (keycloak_ha_enabled and keycloak_db_enabled) or (not keycloak_ha_enabled and keycloak_db_enabled) or (not keycloak_ha_enabled and not keycloak_db_enabled) + that: > + (keycloak_ha_enabled and keycloak_db_enabled) or + (not keycloak_ha_enabled and keycloak_db_enabled) or + (not keycloak_ha_enabled and not keycloak_db_enabled) quiet: true fail_msg: "Cannot install HA setup without a backend database service. Check keycloak_ha_enabled and keycloak_db_enabled" success_msg: "{{ 'Configuring HA' if keycloak_ha_enabled else 'Configuring standalone' }}" diff --git a/roles/keycloak/tasks/restart_keycloak.yml b/roles/keycloak/tasks/restart_keycloak.yml index bae91cd..7284bd0 100644 --- a/roles/keycloak/tasks/restart_keycloak.yml +++ b/roles/keycloak/tasks/restart_keycloak.yml @@ -22,7 +22,7 @@ - name: "Restart and enable {{ keycloak.service_name }} service" ansible.builtin.systemd: name: keycloak - enabled: yes + enabled: true state: restarted become: true when: inventory_hostname != ansible_play_hosts | first diff --git a/roles/keycloak/tasks/rhsso_cli.yml b/roles/keycloak/tasks/rhsso_cli.yml index c51cdc7..fd41dd6 100644 --- a/roles/keycloak/tasks/rhsso_cli.yml +++ b/roles/keycloak/tasks/rhsso_cli.yml @@ -10,4 +10,4 @@ ansible.builtin.command: > {{ keycloak.cli_path }} --connect --command='{{ query }}' --controller={{ keycloak_host }}:{{ keycloak_management_http_port }} changed_when: false - register: cli_result \ No newline at end of file + register: cli_result diff --git a/roles/keycloak/tasks/rhsso_patch.yml b/roles/keycloak/tasks/rhsso_patch.yml index 191a3e0..e7ac3f0 100644 --- a/roles/keycloak/tasks/rhsso_patch.yml +++ b/roles/keycloak/tasks/rhsso_patch.yml @@ -45,7 +45,7 @@ - name: Determine latest version ansible.builtin.set_fact: - sso_latest_version: "{{ filtered_versions | middleware_automation.common.version_sort | last }}" + sso_latest_version: "{{ filtered_versions | middleware_automation.common.version_sort | last }}" when: sso_patch_version is not defined or sso_patch_version | length == 0 delegate_to: localhost run_once: true @@ -95,7 +95,7 @@ dest: "{{ patch_archive }}" owner: "{{ keycloak_service_user }}" group: "{{ keycloak_service_group }}" - mode: 0640 + mode: '0640' register: new_version_downloaded when: - not patch_archive_path.stat.exists @@ -135,8 +135,8 @@ - cli_result.rc == 0 args: apply: - become: true - become_user: "{{ keycloak_service_user }}" + become: true + become_user: "{{ keycloak_service_user }}" - name: "Wait until {{ keycloak.service_name }} becomes active {{ keycloak.health_url }}" ansible.builtin.uri: @@ -152,8 +152,8 @@ query: "patch info" args: apply: - become: true - become_user: "{{ keycloak_service_user }}" + become: true + become_user: "{{ keycloak_service_user }}" - name: "Verify installed patch version" ansible.builtin.assert: diff --git a/roles/keycloak/tasks/systemd.yml b/roles/keycloak/tasks/systemd.yml index 797eb7b..1653406 100644 --- a/roles/keycloak/tasks/systemd.yml +++ b/roles/keycloak/tasks/systemd.yml @@ -6,7 +6,7 @@ dest: "{{ keycloak_dest }}/keycloak-service.sh" owner: root group: root - mode: 0755 + mode: '0755' notify: - restart keycloak @@ -17,7 +17,7 @@ dest: "{{ keycloak_sysconf_file }}" owner: root group: root - mode: 0644 + mode: '0644' notify: - restart keycloak @@ -27,7 +27,7 @@ dest: /etc/systemd/system/keycloak.service owner: root group: root - mode: 0644 + mode: '0644' become: true register: systemdunit notify: diff --git a/roles/keycloak/vars/debian.yml b/roles/keycloak/vars/debian.yml index 60cdfa8..b005b0a 100644 --- a/roles/keycloak/vars/debian.yml +++ b/roles/keycloak/vars/debian.yml @@ -6,6 +6,7 @@ keycloak_prereq_package_list: - procps - apt - tzdata -keycloak_configure_iptables: True +keycloak_configure_iptables: true keycloak_sysconf_file: /etc/default/keycloak -keycloak_pkg_java_home: "/usr/lib/jvm/java-{{ keycloak_varjvm_package | regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" +keycloak_pkg_java_home: "/usr/lib/jvm/java-{{ keycloak_varjvm_package | \ + regex_search('(?!:openjdk-)[0-9.]+') }}-openjdk-{{ 'arm64' if ansible_architecture == 'aarch64' else 'amd64' }}" diff --git a/roles/keycloak/vars/main.yml b/roles/keycloak/vars/main.yml index b03a1a5..7f7dfd1 100644 --- a/roles/keycloak/vars/main.yml +++ b/roles/keycloak/vars/main.yml @@ -13,7 +13,8 @@ keycloak: service_name: "{{ keycloak_service_name }}" health_url: "{{ keycloak_management_url }}/health" cli_path: "{{ keycloak_jboss_home }}/bin/jboss-cli.sh" - config_template_source: "{{ keycloak_config_override_template if keycloak_config_override_template | length > 0 else 'standalone-ha.xml.j2' if keycloak_remote_cache_enabled else 'standalone.xml.j2' }}" + config_template_source: "{{ keycloak_config_override_template if keycloak_config_override_template | length > 0 \ + else 'standalone-ha.xml.j2' if keycloak_remote_cache_enabled else 'standalone.xml.j2' }}" features: "{{ keycloak_features }}" # database @@ -26,7 +27,8 @@ keycloak_jdbc: driver_module_dir: "{{ keycloak_jboss_home }}/modules/org/postgresql/main" driver_version: "{{ keycloak_jdbc_driver_version }}" driver_jar_filename: "postgresql-{{ keycloak_jdbc_driver_version }}.jar" - driver_jar_url: "https://repo.maven.apache.org/maven2/org/postgresql/postgresql/{{ keycloak_jdbc_driver_version }}/postgresql-{{ keycloak_jdbc_driver_version }}.jar" + driver_jar_url: > + {{ keycloak_maven_central }}org/postgresql/postgresql/{{ keycloak_jdbc_driver_version }}/postgresql-{{ keycloak_jdbc_driver_version }}.jar connection_url: "{{ keycloak_jdbc_url }}" db_user: "{{ keycloak_db_user }}" db_password: "{{ keycloak_db_pass }}" @@ -46,7 +48,8 @@ keycloak_jdbc: driver_module_dir: "{{ keycloak_jboss_home }}/modules/org/mariadb/main" driver_version: "{{ keycloak_jdbc_driver_version }}" driver_jar_filename: "mariadb-java-client-{{ keycloak_jdbc_driver_version }}.jar" - driver_jar_url: "https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/{{ keycloak_jdbc_driver_version }}/mariadb-java-client-{{ keycloak_jdbc_driver_version }}.jar" + driver_jar_url: > + {{ keycloak_maven_central }}org/mariadb/jdbc/mariadb-java-client/{{ keycloak_jdbc_driver_version }}/mariadb-java-client-{{ keycloak_jdbc_driver_version }}.jar connection_url: "{{ keycloak_jdbc_url }}" db_user: "{{ keycloak_db_user }}" db_password: "{{ keycloak_db_pass }}" @@ -67,7 +70,8 @@ keycloak_jdbc: driver_module_dir: "{{ keycloak_jboss_home }}/modules/com/microsoft/sqlserver/main" driver_version: "{{ keycloak_jdbc_driver_version }}" driver_jar_filename: "mssql-java-client-{{ keycloak_jdbc_driver_version }}.jar" - driver_jar_url: "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/{{ keycloak_jdbc_driver_version }}.jre11/mssql-jdbc-{{ keycloak_jdbc_driver_version }}.jre11.jar" # e.g., https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/12.2.0.jre11/mssql-jdbc-12.2.0.jre11.jar + driver_jar_url: > + {{ keycloak_maven_central }}com/microsoft/sqlserver/mssql-jdbc/{{ keycloak_jdbc_driver_version }}.jre11/mssql-jdbc-{{ keycloak_jdbc_driver_version }}.jre11.jar connection_url: "{{ keycloak_jdbc_url }}" db_user: "{{ keycloak_db_user }}" db_password: "{{ keycloak_db_pass }}" @@ -102,3 +106,5 @@ keycloak_remotecache: use_ssl: "{{ keycloak_infinispan_use_ssl }}" trust_store_path: "{{ keycloak_infinispan_trust_store_path }}" trust_store_password: "{{ keycloak_infinispan_trust_store_password }}" + +keycloak_maven_central: https://repo1.maven.org/maven2/ diff --git a/roles/keycloak_quarkus/handlers/main.yml b/roles/keycloak_quarkus/handlers/main.yml index f60e747..b95d5c3 100644 --- a/roles/keycloak_quarkus/handlers/main.yml +++ b/roles/keycloak_quarkus/handlers/main.yml @@ -12,6 +12,6 @@ - name: "Print deprecation warning" ansible.builtin.fail: msg: "Deprecation warning: you are using the deprecated variable '{{ deprecated_variable | d('NotSet') }}', check docs on how to upgrade." - ignore_errors: true failed_when: false + changed_when: true listen: "print deprecation warning" diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 5fccedc..a8b1a05 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -170,7 +170,9 @@ argument_specs: type: "str" keycloak_quarkus_config_key_store_password: default: "" - description: "Password of the configuration key store; if non-empty, `keycloak_quarkus_db_pass` will be saved to the key store at `keycloak_quarkus_config_key_store_file` (instead of being written to the configuration file in clear text" + description: > + Password of the configuration key store; if non-empty, `keycloak_quarkus_db_pass` will be saved to the key store + at `keycloak_quarkus_config_key_store_file` (instead of being written to the configuration file in clear text) type: "str" keycloak_quarkus_https_port: default: 8443 @@ -399,7 +401,9 @@ argument_specs: description: "Set a username with which to authenticate when downloading JDBC drivers from an alternative location" type: "str" keycloak_quarkus_jdbc_download_pass: - description: "Set a password with which to authenticate when downloading JDBC drivers from an alternative location (requires keycloak_quarkus_jdbc_download_user)" + description: > + Set a password with which to authenticate when downloading JDBC drivers from an alternative location + (requires `keycloak_quarkus_jdbc_download_user``) type: "str" keycloak_quarkus_jdbc_download_validate_certs: default: true diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index 732e5b1..65fd391 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -170,7 +170,7 @@ dest: "{{ keycloak_quarkus_key_file }}" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" - mode: 0640 + mode: '0640' become: true when: - keycloak_quarkus_https_key_file_enabled is defined and keycloak_quarkus_https_key_file_enabled @@ -183,7 +183,7 @@ dest: "{{ keycloak_quarkus_cert_file }}" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" - mode: 0644 + mode: '0644' become: true when: - keycloak_quarkus_https_key_file_enabled is defined and keycloak_quarkus_https_key_file_enabled diff --git a/roles/keycloak_quarkus/tasks/jdbc_driver.yml b/roles/keycloak_quarkus/tasks/jdbc_driver.yml index 52298aa..880a915 100644 --- a/roles/keycloak_quarkus/tasks/jdbc_driver.yml +++ b/roles/keycloak_quarkus/tasks/jdbc_driver.yml @@ -3,9 +3,11 @@ ansible.builtin.fail: msg: >- When JDBC driver download credentials are set, both the username and the password MUST be set - when: - - (keycloak_quarkus_jdbc_download_user is undefined and keycloak_quarkus_jdbc_download_pass is not undefined) or (keycloak_quarkus_jdbc_download_pass is undefined and keycloak_quarkus_jdbc_download_user is not undefined) -- name: "Retrieve JDBC Driver from {{ keycloak_jdbc_download_user | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" + when: > + (keycloak_quarkus_jdbc_download_user is undefined and keycloak_quarkus_jdbc_download_pass is not undefined) or + (keycloak_quarkus_jdbc_download_pass is undefined and keycloak_quarkus_jdbc_download_user is not undefined) + +- name: "Retrieve JDBC Driver from {{ keycloak_jdbc_download_url | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" ansible.builtin.get_url: url: "{{ keycloak_quarkus_jdbc_download_url | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" dest: "{{ keycloak.home }}/providers" From a0198238715563bfd0fe13e1b72c7fc6659a5424 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Wed, 8 May 2024 17:15:50 +0200 Subject: [PATCH 115/205] Close #214: RHBK 24.*: Update sqlserver JDBC version --- roles/keycloak_quarkus/defaults/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index a54e6c7..5a11f08 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -130,9 +130,9 @@ keycloak_quarkus_default_jdbc: version: 2.7.4 mssql: url: 'jdbc:sqlserver://localhost:1433;databaseName=keycloak;' - version: 12.2.0 - driver_jar_url: "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/12.2.0.jre11/mssql-jdbc-12.2.0.jre11.jar" - # cf. https://access.redhat.com/documentation/en-us/red_hat_build_of_keycloak/22.0/html/server_guide/db-#db-installing-the-microsoft-sql-server-driver + version: 12.4.2 + driver_jar_url: "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/12.4.2.jre11/mssql-jdbc-12.4.2.jre11.jar" + # cf. https://access.redhat.com/documentation/en-us/red_hat_build_of_keycloak/24.0/html/server_guide/db-#db-installing-the-microsoft-sql-server-driver ### logging configuration keycloak_quarkus_log: file keycloak_quarkus_log_level: info From 3c224176743f71af3d50377d97ca3889f7f7ddf7 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 8 May 2024 19:03:30 +0200 Subject: [PATCH 116/205] Port downstream upgrade --- molecule/quarkus_upgrade/converge.yml | 9 +++++ molecule/quarkus_upgrade/molecule.yml | 43 ++++++++++++++++++++++ molecule/quarkus_upgrade/prepare.yml | 52 +++++++++++++++++++++++++++ molecule/quarkus_upgrade/vars.yml | 14 ++++++++ molecule/quarkus_upgrade/verify.yml | 32 +++++++++++++++++ 5 files changed, 150 insertions(+) create mode 100644 molecule/quarkus_upgrade/converge.yml create mode 100644 molecule/quarkus_upgrade/molecule.yml create mode 100644 molecule/quarkus_upgrade/prepare.yml create mode 100644 molecule/quarkus_upgrade/vars.yml create mode 100644 molecule/quarkus_upgrade/verify.yml diff --git a/molecule/quarkus_upgrade/converge.yml b/molecule/quarkus_upgrade/converge.yml new file mode 100644 index 0000000..eb84589 --- /dev/null +++ b/molecule/quarkus_upgrade/converge.yml @@ -0,0 +1,9 @@ +--- +- name: Converge + hosts: all + vars_files: + - vars.yml + vars: + keycloak_quarkus_version: 24.0.3 + roles: + - role: keycloak_quarkus diff --git a/molecule/quarkus_upgrade/molecule.yml b/molecule/quarkus_upgrade/molecule.yml new file mode 100644 index 0000000..77f687f --- /dev/null +++ b/molecule/quarkus_upgrade/molecule.yml @@ -0,0 +1,43 @@ +--- +dependency: + name: galaxy + options: + requirements-file: molecule/requirements.yml +driver: + name: docker +platforms: + - name: instance + image: registry.access.redhat.com/ubi9/ubi-init:latest + command: "/usr/sbin/init" + pre_build_image: true + privileged: true + port_bindings: + - 8080:8080 + published_ports: + - 0.0.0.0:8080:8080/TCP +provisioner: + name: ansible + playbooks: + prepare: prepare.yml + converge: converge.yml + verify: verify.yml + inventory: + host_vars: + localhost: + ansible_python_interpreter: "{{ ansible_playbook_python }}" +verifier: + name: ansible +scenario: + test_sequence: + - dependency + - cleanup + - destroy + - syntax + - create + - prepare + - converge + - idempotence + - side_effect + - verify + - cleanup + - destroy diff --git a/molecule/quarkus_upgrade/prepare.yml b/molecule/quarkus_upgrade/prepare.yml new file mode 100644 index 0000000..1a0e708 --- /dev/null +++ b/molecule/quarkus_upgrade/prepare.yml @@ -0,0 +1,52 @@ +--- +- name: Prepare + hosts: all + vars_files: + - vars.yml + vars: + sudo_pkg_name: sudo + keycloak_quarkus_version: 22.0.10 + pre_tasks: + - name: Install sudo + ansible.builtin.apt: + name: + - sudo + - openjdk-17-jdk-headless + state: present + when: + - ansible_facts.os_family == 'Debian' + + - name: "Ensure common prepare phase are set." + ansible.builtin.include_tasks: ../prepare.yml + + - name: Display Ansible version + ansible.builtin.debug: + msg: "Ansible version is {{ ansible_version.full }}" + + - name: "Ensure {{ sudo_pkg_name }} is installed (if user is root)." + ansible.builtin.dnf: + name: "{{ sudo_pkg_name }}" + when: + - ansible_user_id == 'root' + + - name: Gather the package facts + ansible.builtin.package_facts: + manager: auto + + - name: "Check if {{ sudo_pkg_name }} is installed." + ansible.builtin.assert: + that: + - sudo_pkg_name in ansible_facts.packages + + - name: Create certificate request + ansible.builtin.command: openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes -subj '/CN=instance' + delegate_to: localhost + changed_when: false + roles: + - role: keycloak_quarkus + post_tasks: + - name: "Delete custom fact" + ansible.builtin.file: + path: /etc/ansible/facts.d/keycloak.fact + state: absent + become: true diff --git a/molecule/quarkus_upgrade/vars.yml b/molecule/quarkus_upgrade/vars.yml new file mode 100644 index 0000000..81d56b5 --- /dev/null +++ b/molecule/quarkus_upgrade/vars.yml @@ -0,0 +1,14 @@ +--- +keycloak_quarkus_offline_install: false +keycloak_quarkus_admin_password: "remembertochangeme" +keycloak_quarkus_admin_pass: "remembertochangeme" +keycloak_quarkus_realm: TestRealm +keycloak_quarkus_host: instance +keycloak_quarkus_log: file +keycloak_quarkus_https_key_file_enabled: true +keycloak_quarkus_log_target: /tmp/keycloak +keycloak_quarkus_hostname_strict: false +keycloak_quarkus_cert_file_copy_enabled: true +keycloak_quarkus_key_file_copy_enabled: true +keycloak_quarkus_key_content: "{{ lookup('file', 'key.pem') }}" +keycloak_quarkus_cert_file_src: cert.pem diff --git a/molecule/quarkus_upgrade/verify.yml b/molecule/quarkus_upgrade/verify.yml new file mode 100644 index 0000000..def2d5d --- /dev/null +++ b/molecule/quarkus_upgrade/verify.yml @@ -0,0 +1,32 @@ +--- +- name: Verify + hosts: instance + vars: + keycloak_quarkus_admin_password: "remembertochangeme" + keycloak_quarkus_port: http://localhost:8080 + tasks: + - name: Populate service facts + ansible.builtin.service_facts: + + - name: Check if keycloak service started + ansible.builtin.assert: + that: + - ansible_facts.services["rhbk.service"]["state"] == "running" + - ansible_facts.services["rhbk.service"]["status"] == "enabled" + + - name: Verify we are running on requested jvm + ansible.builtin.shell: | + set -eo pipefail + ps -ef | grep 'etc/alternatives/.*17' | grep -v grep + changed_when: false + + - name: Verify token api call + ansible.builtin.uri: + url: "{{ keycloak_quarkus_port }}/realms/master/protocol/openid-connect/token" + method: POST + body: "client_id=admin-cli&username=admin&password={{ keycloak_quarkus_admin_password }}&grant_type=password" + validate_certs: no + register: keycloak_auth_response + until: keycloak_auth_response.status == 200 + retries: 2 + delay: 2 From 22f5ad902f1372b701ab81c43cccf6a48eb6080c Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 8 May 2024 19:05:24 +0200 Subject: [PATCH 117/205] add test to github actions --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 509bebb..d5cac41 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,4 +15,4 @@ jobs: with: fqcn: 'middleware_automation/keycloak' molecule_tests: >- - [ "default", "overridexml", "https_revproxy", "quarkus", "quarkus-devmode", "debian" ] + [ "default", "overridexml", "https_revproxy", "quarkus", "quarkus-devmode", "quarkus_upgrade", "debian" ] From 4c96cbe7f6d1aca3279f54179dd0c11b2b450e4c Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 8 May 2024 19:09:59 +0200 Subject: [PATCH 118/205] use sane version to be upgraded --- molecule/quarkus_upgrade/prepare.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/molecule/quarkus_upgrade/prepare.yml b/molecule/quarkus_upgrade/prepare.yml index 1a0e708..bebfc68 100644 --- a/molecule/quarkus_upgrade/prepare.yml +++ b/molecule/quarkus_upgrade/prepare.yml @@ -5,7 +5,7 @@ - vars.yml vars: sudo_pkg_name: sudo - keycloak_quarkus_version: 22.0.10 + keycloak_quarkus_version: 23.0.7 pre_tasks: - name: Install sudo ansible.builtin.apt: From 4bbc8e02566732f4550ff8718d753d8152ffd644 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 8 May 2024 19:14:04 +0200 Subject: [PATCH 119/205] update systemd service name in verify --- molecule/quarkus_upgrade/verify.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/molecule/quarkus_upgrade/verify.yml b/molecule/quarkus_upgrade/verify.yml index def2d5d..f5edfd0 100644 --- a/molecule/quarkus_upgrade/verify.yml +++ b/molecule/quarkus_upgrade/verify.yml @@ -11,8 +11,8 @@ - name: Check if keycloak service started ansible.builtin.assert: that: - - ansible_facts.services["rhbk.service"]["state"] == "running" - - ansible_facts.services["rhbk.service"]["status"] == "enabled" + - ansible_facts.services["keycloak.service"]["state"] == "running" + - ansible_facts.services["keycloak.service"]["status"] == "enabled" - name: Verify we are running on requested jvm ansible.builtin.shell: | From fcf629d05e22eedffb279f645382347ae3ef3a06 Mon Sep 17 00:00:00 2001 From: Footur <3769085+Footur@users.noreply.github.com> Date: Thu, 9 May 2024 07:24:47 +0000 Subject: [PATCH 120/205] Update Keycloak to version 24.0.4 --- roles/keycloak_quarkus/README.md | 2 +- roles/keycloak_quarkus/defaults/main.yml | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index ccb9e75..a70deae 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -11,7 +11,7 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| -|`keycloak_quarkus_version`| keycloak.org package version | `24.0.3` | +|`keycloak_quarkus_version`| keycloak.org package version | `24.0.4` | |`keycloak_quarkus_offline_install` | Perform an offline install | `False`| |`keycloak_quarkus_dest`| Installation root path | `/opt/keycloak` | |`keycloak_quarkus_download_url` | Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 5a11f08..242482d 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -1,6 +1,6 @@ --- ### Configuration specific to keycloak -keycloak_quarkus_version: 24.0.3 +keycloak_quarkus_version: 24.0.4 keycloak_quarkus_archive: "keycloak-{{ keycloak_quarkus_version }}.zip" keycloak_quarkus_download_url: "https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}" keycloak_quarkus_installdir: "{{ keycloak_quarkus_dest }}/keycloak-{{ keycloak_quarkus_version }}" diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index a8b1a05..56a99ce 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -2,7 +2,7 @@ argument_specs: main: options: keycloak_quarkus_version: - default: "24.0.3" + default: "24.0.4" description: "keycloak.org package version" type: "str" keycloak_quarkus_archive: @@ -412,7 +412,7 @@ argument_specs: downstream: options: rhbk_version: - default: "24.0.3" + default: "24.0.4" description: "Red Hat Build of Keycloak version" type: "str" rhbk_archive: From 8f14be37d7ad512ea393a81ecca6db819eb79d20 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Fri, 10 May 2024 10:17:37 +0200 Subject: [PATCH 121/205] add functionality --- roles/keycloak_quarkus/README.md | 10 ++++++++++ roles/keycloak_quarkus/tasks/install.yml | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index a70deae..f7f1be3 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -185,6 +185,16 @@ Role Variables |`keycloak_quarkus_frontend_url`| Base URL for frontend URLs, including scheme, host, port and path | `no` | |`keycloak_quarkus_admin_url`| Base URL for accessing the administration console, including scheme, host, port and path | `no` | |`keycloak_quarkus_ks_vault_pass`| The password for accessing the keystore vault SPI | `no` | +|`keycloak_quarkus_alternate_download_url`| Alternate location with optional authentication for downloading RHBK | `no` | +|`keycloak_quarkus_download_user`| Optional username for http authentication | `no*` | +|`keycloak_quarkus_download_pass`| Optional password for http authentication | `no*` | +|`keycloak_quarkus_download_validate_certs`| Whether to validate certs for URL `keycloak_quarkus_alternate_download_url` | `no` | +|`keycloak_quarkus_jdbc_download_user`| Optional username for http authentication | `no*` | +|`keycloak_quarkus_jdbc_download_pass`| Optional password for http authentication | `no*` | +|`keycloak_quarkus_jdbc_download_validate_certs`| Whether to validate certs for URL `keycloak_quarkus_download_validate_certs` | `no` | + +`*` username/password authentication credentials must be both declared or both undefined + Role custom facts ----------------- diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index 65fd391..480ccbc 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -115,6 +115,25 @@ run_once: true become: false +- name: Perform download of RHBK from alternate download location + delegate_to: localhost + run_once: true + become: false + when: + - archive_path is defined + - archive_path.stat is defined + - not archive_path.stat.exists + - rhbk_enable is defined and rhbk_enable + - not keycloak.offline_install + - keycloak_quarkus_alternate_download_url is defined + ansible.builtin.get_url: # noqa risky-file-permissions delegated, uses controller host user + url: "{{ keycloak_quarkus_alternate_download_url }}" + dest: "{{ local_path.stat.path }}/{{ keycloak.bundle }}" + mode: '0640' + url_username: "{{ keycloak_quarkus_download_user | default(omit) }}" + url_password: "{{ keycloak_quarkus_download_pass | default(omit) }}" + validate_certs: "{{ keycloak_quarkus_download_validate_certs | default(omit) }}" + - name: Check downloaded archive ansible.builtin.stat: path: "{{ local_path.stat.path }}/{{ keycloak.bundle }}" From 9f4623b05a776ec555e3a1581798a530fddf4cbd Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 14 May 2024 08:36:55 +0200 Subject: [PATCH 122/205] #224: keycloak_quarkus: Add support for policy files --- molecule/quarkus/converge.yml | 6 ++++++ roles/keycloak_quarkus/README.md | 16 ++++++++++++++++ roles/keycloak_quarkus/defaults/main.yml | 2 ++ roles/keycloak_quarkus/tasks/install.yml | 22 ++++++++++++++++++++++ roles/keycloak_quarkus/tasks/prereqs.yml | 10 ++++++++++ 5 files changed, 56 insertions(+) diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index 9e74aa6..2982250 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -31,6 +31,12 @@ value: 10 - id: spid-saml url: https://github.com/italia/spid-keycloak-provider/releases/download/24.0.2/spid-provider.jar + keycloak_quarkus_policies: + - name: "xato-net-10-million-passwords.txt" + url: "https://github.com/danielmiessler/SecLists/raw/master/Passwords/xato-net-10-million-passwords.txt" + - name: "xato-net-10-million-passwords-10.txt" + url: "https://github.com/danielmiessler/SecLists/raw/master/Passwords/xato-net-10-million-passwords-10.txt" + type: password-blacklists roles: - role: keycloak_quarkus - role: keycloak_realm diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index f7f1be3..47d5a21 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -176,6 +176,22 @@ bin/kc.sh build --spi-connections-provider=http-client --spi-connections-http-cl ``` +#### Configuring policies + +| Variable | Description | Default | +|:---------|:------------|:--------| +|`keycloak_quarkus_policies`| List of policy definitions; see below | `[]` | + +Provider definition: + +```yaml +keycloak_quarkus_policies: + - name: xato-net-10-million-passwords.txt # required, resulting file name + url: https://github.com/danielmiessler/SecLists/raw/master/Passwords/xato-net-10-million-passwords.txt # required, url for download + type: password-blacklists # optional, defaults to `password-blacklists`; supported values: [`password-blacklists`] +``` + + Role Variables -------------- diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 242482d..8a4f9f1 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -150,3 +150,5 @@ keycloak_quarkus_ks_vault_type: PKCS12 keycloak_quarkus_ks_vault_pass: keycloak_quarkus_providers: [] +keycloak_quarkus_policies: [] +keycloak_quarkus_supported_policy_types: ['password-blacklists'] diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index 480ccbc..ab7c396 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -226,3 +226,25 @@ loop: "{{ keycloak_quarkus_providers }}" when: item.url is defined and item.url | length > 0 notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or not item.restart else [] }}" + +- name: Ensure required folder structure for policies exits + ansible.builtin.file: + path: "{{ keycloak.home }}/data/{{ item | lower }}" + state: directory + owner: "{{ keycloak.service_user }}" + group: "{{ keycloak.service_group }}" + mode: '0750' + become: true + loop: "{{ keycloak_quarkus_supported_policy_types }}" + +- name: "Install custom policies" + ansible.builtin.get_url: + url: "{{ item.url }}" + dest: "{{ keycloak.home }}/data/{{ item.type|default(keycloak_quarkus_supported_policy_types | first) | lower }}/{{ item.name }}" + owner: "{{ keycloak.service_user }}" + group: "{{ keycloak.service_group }}" + mode: '0640' + become: true + loop: "{{ keycloak_quarkus_policies }}" + when: item.url is defined and item.url | length > 0 + notify: "restart keycloak" diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index e0a76d5..1e422a7 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -65,3 +65,13 @@ quiet: true fail_msg: "Providers definition is incorrect; `id` and one of `spi` or `url` are mandatory. `key` and `value` are mandatory for each property" loop: "{{ keycloak_quarkus_providers }}" + +- name: "Validate policies" + ansible.builtin.assert: + that: + - item.name is defined and item.name | length > 0 + - item.url is defined and item.url | length > 0 + - item.type is not defined or item.type | lower in keycloak_quarkus_supported_policy_types + quiet: true + fail_msg: "Policy definition is incorrect: `name` and one of `url` are mandatory, `type` needs to be left empty or one of {{ keycloak_quarkus_supported_policy_types }}." + loop: "{{ keycloak_quarkus_policies }}" From 6682853a2d105aa701ac9f30a33b47ebf1e0f028 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 14 May 2024 08:58:57 +0200 Subject: [PATCH 123/205] #224: Add missing argument specs --- roles/keycloak_quarkus/meta/argument_specs.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 56a99ce..c5f5138 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -394,6 +394,14 @@ argument_specs: description: "List of provider definition dicts: { 'id': str, 'spi': str, 'url': str, 'default': bool, 'properties': list of key/value }" default: [] type: "list" + keycloak_quarkus_supported_policy_types: + description: "List of str of supported policy types" + default: ['password-blacklists'] + type: "list" + keycloak_quarkus_policies: + description: "List of policy definition dicts: { 'name': str, 'url': str, 'type': str }" + default: [] + type: "list" keycloak_quarkus_jdbc_download_url: description: "Override the default Maven Central download URL for the JDBC driver" type: "str" From 4b902adc8d4598dc1ce3ca98f3f0ae3670aaa435 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 13 May 2024 17:20:21 +0200 Subject: [PATCH 124/205] #222: Add support for maven providers --- requirements.txt | 5 ++-- requirements.yml | 1 + roles/keycloak_quarkus/README.md | 34 ++++++++++++++++++++++-- roles/keycloak_quarkus/tasks/install.yml | 33 +++++++++++++++++++++-- roles/keycloak_quarkus/tasks/prereqs.yml | 4 +-- 5 files changed, 69 insertions(+), 8 deletions(-) diff --git a/requirements.txt b/requirements.txt index b2366a5..a91d12a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,7 @@ ################################################# -# python dependencies required to be installed +# python dependencies required to be installed # on the controller host with: # pip install -r requirements.txt # -netaddr \ No newline at end of file +netaddr +lxml # for community.general.maven_artifact \ No newline at end of file diff --git a/requirements.yml b/requirements.yml index 3f6feef..10150ad 100644 --- a/requirements.yml +++ b/requirements.yml @@ -2,3 +2,4 @@ collections: - name: middleware_automation.common - name: ansible.posix + - name: community.general # for `maven_artifact` diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 47d5a21..028097c 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -4,6 +4,29 @@ keycloak_quarkus Install [keycloak](https://keycloak.org/) >= 20.0.0 (quarkus) server configurations. +Requirements +------------ + +This role requires the `python3-netaddr` and `lxml` library installed on the controller node. + +* to install via yum/dnf: `dnf install python3-netaddr python3-lxml` +* to install via apt: `apt install python3-netaddr python3-lxml` +* or via the collection: `pip install -r requirements.txt` + + +Dependencies +------------ + +The roles depends on: + +* [middleware_automation.common](https://github.com/ansible-middleware/common) +* [ansible-posix](https://docs.ansible.com/ansible/latest/collections/ansible/posix/index.html) +* [community.general](https://docs.ansible.com/ansible/latest/collections/community/general/index.html) + +To install all the dependencies via galaxy: + + ansible-galaxy collection install -r requirements.yml + Role Defaults ------------- @@ -160,10 +183,17 @@ Provider definition: ```yaml keycloak_quarkus_providers: - id: http-client # required - spi: connections # required if url is not specified + spi: connections # required if neither url nor maven are specified default: true # optional, whether to set default for spi, default false restart: true # optional, whether to restart, default true - url: https://.../.../custom_spi.jar # optional, url for download + url: https://.../.../custom_spi.jar # optional, url for download via http + maven: # optional, for download using maven + repository_url: https://maven.pkg.github.com/OWNER/REPOSITORY # optional, maven repo url + group_id: my.group # optional, maven group id + artifact_id: artifact # optional, maven artifact id + version: 24.0.4 # optional, defaults to latest + username: user # optional, cf. https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry#authenticating-to-github-packages + password: pat # optional, provide a PAT for accessing Github's Apache Maven registry properties: # optional, list of key-values - key: default-connection-pool-size value: 10 diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index ab7c396..8d604e6 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -215,7 +215,7 @@ - rhbk_enable is defined and rhbk_enable - keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url is defined -- name: "Download custom providers" +- name: "Download custom providers via http" ansible.builtin.get_url: url: "{{ item.url }}" dest: "{{ keycloak.home }}/providers/{{ item.id }}.jar" @@ -227,7 +227,36 @@ when: item.url is defined and item.url | length > 0 notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or not item.restart else [] }}" -- name: Ensure required folder structure for policies exits +# this requires the `lxml` package to be installed; we redirect this step to localhost such that we do need to install it on the remote hosts +- name: "Download custom providers to localhost using maven" + community.general.maven_artifact: + repository_url: "{{ item.maven.repository_url }}" + group_id: "{{ item.maven.group_id }}" + artifact_id: "{{ item.maven.artifact_id }}" + version: "{{ item.maven.version | default(omit) }}" + username: "{{ item.maven.username | default(omit) }}" + password: "{{ item.maven.password | default(omit) }}" + dest: "{{ local_path.stat.path }}/{{ item.id }}.jar" + delegate_to: "localhost" + run_once: true + loop: "{{ keycloak_quarkus_providers }}" + when: item.maven is defined + no_log: "{{ item.maven.password is defined and item.maven.password | length > 0 | default(false) }}" + notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or not item.restart else [] }}" + +- name: "Upload local maven SPIs" + ansible.builtin.copy: + src: "{{ local_path.stat.path }}/{{ item.id }}.jar" + dest: "{{ keycloak.home }}/providers/{{ item.id }}.jar" + owner: "{{ keycloak.service_user }}" + group: "{{ keycloak.service_group }}" + mode: '0640' + become: true + loop: "{{ keycloak_quarkus_providers }}" + when: item.maven is defined + no_log: "{{ item.maven.password is defined and item.maven.password | length > 0 | default(false) }}" + +- name: Ensure required folder structure for policies exists ansible.builtin.file: path: "{{ keycloak.home }}/data/{{ item | lower }}" state: directory diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index 1e422a7..064cc10 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -61,9 +61,9 @@ ansible.builtin.assert: that: - item.id is defined and item.id | length > 0 - - (item.spi is defined and item.spi | length > 0) or (item.url is defined and item.url | length > 0) + - (item.spi is defined and item.spi | length > 0) or (item.url is defined and item.url | length > 0) or (item.maven is defined and item.maven.repository_url is defined and item.maven.repository_url | length > 0 and item.maven.group_id is defined and item.maven.group_id | length > 0 and item.maven.artifact_id is defined and item.maven.artifact_id | length > 0) quiet: true - fail_msg: "Providers definition is incorrect; `id` and one of `spi` or `url` are mandatory. `key` and `value` are mandatory for each property" + fail_msg: "Providers definition is incorrect; `id` and one of `spi`, `url`, or `maven` are mandatory. `key` and `value` are mandatory for each property" loop: "{{ keycloak_quarkus_providers }}" - name: "Validate policies" From d8e9620a8a26381eb272c3125c9b5adb0183fcc0 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 13 May 2024 17:20:32 +0200 Subject: [PATCH 125/205] #222: Molecule tests --- molecule/quarkus/converge.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index 2982250..6186af4 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -31,6 +31,14 @@ value: 10 - id: spid-saml url: https://github.com/italia/spid-keycloak-provider/releases/download/24.0.2/spid-provider.jar + - id: keycloak-kerberos-federation + maven: + repository_url: https://repo1.maven.org/maven2/ # https://mvnrepository.com/artifact/org.keycloak/keycloak-kerberos-federation/24.0.4 + group_id: org.keycloak + artifact_id: keycloak-kerberos-federation + version: 24.0.4 # optional + # username: myUser # optional + # password: myPAT # optional keycloak_quarkus_policies: - name: "xato-net-10-million-passwords.txt" url: "https://github.com/danielmiessler/SecLists/raw/master/Passwords/xato-net-10-million-passwords.txt" From d87c8ca8acba5695253f91dbd39794632cc75a0c Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 14 May 2024 10:12:58 +0200 Subject: [PATCH 126/205] wip --- roles/keycloak_quarkus/meta/argument_specs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index c5f5138..b630d6a 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -391,7 +391,7 @@ argument_specs: default: 10 type: 'int' keycloak_quarkus_providers: - description: "List of provider definition dicts: { 'id': str, 'spi': str, 'url': str, 'default': bool, 'properties': list of key/value }" + description: "List of provider definition dicts: { 'id': str, 'spi': str, 'url': str, 'default': bool, 'properties': list of key/value TODO:add maven}" default: [] type: "list" keycloak_quarkus_supported_policy_types: From 6d01ffbb7796da35d91713913e44f6f6dd411e22 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 14 May 2024 11:10:38 +0200 Subject: [PATCH 127/205] Close #228: add support for custom env vars in sysconfig file --- roles/keycloak_quarkus/README.md | 3 ++- roles/keycloak_quarkus/defaults/main.yml | 1 + roles/keycloak_quarkus/meta/argument_specs.yml | 4 ++++ roles/keycloak_quarkus/tasks/prereqs.yml | 10 ++++++++++ roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 | 5 +++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 47d5a21..f8f9899 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -38,7 +38,8 @@ Role Defaults |`keycloak_quarkus_java_home`| JAVA_HOME of installed JRE, leave empty for using specified keycloak_quarkus_jvm_package RPM path | `None` | |`keycloak_quarkus_java_heap_opts`| Heap memory JVM setting | `-Xms1024m -Xmx2048m` | |`keycloak_quarkus_java_jvm_opts`| Other JVM settings | same as keycloak | -|`keycloak_quarkus_java_opts`| JVM arguments; if overriden, it takes precedence over `keycloak_quarkus_java_*` | `{{ keycloak_quarkus_java_heap_opts + ' ' + keycloak_quarkus_java_jvm_opts }}` | +|`keycloak_quarkus_java_opts`| JVM arguments; if overridden, it takes precedence over `keycloak_quarkus_java_*` | `{{ keycloak_quarkus_java_heap_opts + ' ' + keycloak_quarkus_java_jvm_opts }}` | +|`keycloak_quarkus_additional_env_vars` | List of additional env variables of { key: str, value: str} to be put in sysconfig file | `[]` | |`keycloak_quarkus_frontend_url`| Set the base URL for frontend URLs, including scheme, host, port and path | | |`keycloak_quarkus_admin_url`| Set the base URL for accessing the administration console, including scheme, host, port and path | | |`keycloak_quarkus_http_relative_path` | Set the path relative to / for serving resources. The path must start with a / | `/` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 8a4f9f1..d61cfff 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -44,6 +44,7 @@ keycloak_quarkus_java_jvm_opts: "-XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.security.egd=file:/dev/urandom -XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:FlightRecorderOptions=stackdepth=512" keycloak_quarkus_java_opts: "{{ keycloak_quarkus_java_heap_opts + ' ' + keycloak_quarkus_java_jvm_opts }}" +keycloak_quarkus_additional_env_vars: [] ### TLS/HTTPS configuration keycloak_quarkus_https_key_file_enabled: false diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index c5f5138..c8cece8 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -201,6 +201,10 @@ argument_specs: default: "{{ keycloak_quarkus_java_heap_opts + ' ' + keycloak_quarkus_java_jvm_opts }}" description: "JVM arguments, by default heap_opts + jvm_opts, if overriden it takes precedence over them" type: "str" + keycloak_quarkus_additional_env_vars: + default: "[]" + description: "List of additional env variables of { key: str, value: str} to be put in sysconfig file" + type: "list" keycloak_quarkus_ha_enabled: default: false description: "Enable auto configuration for database backend, clustering and remote caches on infinispan" diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index 1e422a7..0229036 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -75,3 +75,13 @@ quiet: true fail_msg: "Policy definition is incorrect: `name` and one of `url` are mandatory, `type` needs to be left empty or one of {{ keycloak_quarkus_supported_policy_types }}." loop: "{{ keycloak_quarkus_policies }}" + +- name: "Validate additional env variables" + ansible.builtin.assert: + that: + - item.key is defined and item.key | length > 0 + - item.value is defined and item.value | length > 0 + quiet: true + fail_msg: "Additional env variable definition is incorrect: `key` and `value` are mandatory." + no_log: true + loop: "{{ keycloak_quarkus_additional_env_vars }}" diff --git a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 index ef27d27..2c260a3 100644 --- a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 +++ b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 @@ -8,3 +8,8 @@ KEYCLOAK_ADMIN_PASSWORD='{{ keycloak_quarkus_admin_pass }}' PATH={{ keycloak_quarkus_java_home | default(keycloak_sys_pkg_java_home, true) }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin JAVA_HOME={{ keycloak_quarkus_java_home | default(keycloak_sys_pkg_java_home, true) }} JAVA_OPTS={{ keycloak_quarkus_java_opts }} + +# Custom ENV variables +{% for env in keycloak_quarkus_additional_env_vars %} +{{ env.key }}={{ env.value }} +{% endfor %} From 26316ddc506872b794b48f1c3edf882a94490b1d Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 14 May 2024 11:54:45 +0200 Subject: [PATCH 128/205] #222: add support for local providers to be uploaded --- molecule/quarkus/converge.yml | 2 ++ roles/keycloak_quarkus/README.md | 11 +++++++++-- roles/keycloak_quarkus/meta/argument_specs.yml | 2 +- roles/keycloak_quarkus/tasks/install.yml | 11 +++++++++++ roles/keycloak_quarkus/tasks/prereqs.yml | 4 ++-- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index 6186af4..2fa1ceb 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -39,6 +39,8 @@ version: 24.0.4 # optional # username: myUser # optional # password: myPAT # optional + # - id: my-static-theme + # local_path: /tmp/my-static-theme.jar keycloak_quarkus_policies: - name: "xato-net-10-million-passwords.txt" url: "https://github.com/danielmiessler/SecLists/raw/master/Passwords/xato-net-10-million-passwords.txt" diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 028097c..28f81aa 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -178,15 +178,22 @@ Role Defaults |:---------|:------------|:--------| |`keycloak_quarkus_providers`| List of provider definitions; see below | `[]` | +Providers support different sources: + +* `url`: http download for SPIs not requiring authentication +* `maven`: maven download for SPIs hosted publicly on Apache Maven Central or private Maven repositories like Github Maven requiring authentication +* `local_path`: static SPIs to be uploaded + Provider definition: ```yaml keycloak_quarkus_providers: - - id: http-client # required - spi: connections # required if neither url nor maven are specified + - id: http-client # required; "{{ id }}.jar" identifies the file name on RHBK + spi: connections # required if neither url, local_path nor maven are specified; required for setting properties default: true # optional, whether to set default for spi, default false restart: true # optional, whether to restart, default true url: https://.../.../custom_spi.jar # optional, url for download via http + local_path: my_theme_spi.jar # optional, path on local controller for SPI to be uploaded maven: # optional, for download using maven repository_url: https://maven.pkg.github.com/OWNER/REPOSITORY # optional, maven repo url group_id: my.group # optional, maven group id diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index b630d6a..f4c9f51 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -391,7 +391,7 @@ argument_specs: default: 10 type: 'int' keycloak_quarkus_providers: - description: "List of provider definition dicts: { 'id': str, 'spi': str, 'url': str, 'default': bool, 'properties': list of key/value TODO:add maven}" + description: "List of provider definition dicts: { 'id': str, 'spi': str, 'url': str, 'local_path': str, 'maven': { 'repository_url': str, 'group_id': str, 'artifact_id': str, 'version': str, 'username': str, optional, 'password': str, optional }, 'default': bool, 'properties': list of key/value }" default: [] type: "list" keycloak_quarkus_supported_policy_types: diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index 8d604e6..6c8b31d 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -256,6 +256,17 @@ when: item.maven is defined no_log: "{{ item.maven.password is defined and item.maven.password | length > 0 | default(false) }}" +- name: "Upload local SPIs" + ansible.builtin.copy: + src: "{{ item.local_path}}" + dest: "{{ keycloak.home }}/providers/{{ item.id }}.jar" + owner: "{{ keycloak.service_user }}" + group: "{{ keycloak.service_group }}" + mode: '0640' + become: true + loop: "{{ keycloak_quarkus_providers }}" + when: item.local_path is defined + - name: Ensure required folder structure for policies exists ansible.builtin.file: path: "{{ keycloak.home }}/data/{{ item | lower }}" diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index 064cc10..12f9b23 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -61,9 +61,9 @@ ansible.builtin.assert: that: - item.id is defined and item.id | length > 0 - - (item.spi is defined and item.spi | length > 0) or (item.url is defined and item.url | length > 0) or (item.maven is defined and item.maven.repository_url is defined and item.maven.repository_url | length > 0 and item.maven.group_id is defined and item.maven.group_id | length > 0 and item.maven.artifact_id is defined and item.maven.artifact_id | length > 0) + - (item.spi is defined and item.spi | length > 0) or (item.url is defined and item.url | length > 0) or (item.maven is defined and item.maven.repository_url is defined and item.maven.repository_url | length > 0 and item.maven.group_id is defined and item.maven.group_id | length > 0 and item.maven.artifact_id is defined and item.maven.artifact_id | length > 0) or (item.local_path is defined and item.local_path | length > 0) quiet: true - fail_msg: "Providers definition is incorrect; `id` and one of `spi`, `url`, or `maven` are mandatory. `key` and `value` are mandatory for each property" + fail_msg: "Providers definition is incorrect; `id` and one of `spi`, `url`, `local_path`, or `maven` are mandatory. `key` and `value` are mandatory for each property" loop: "{{ keycloak_quarkus_providers }}" - name: "Validate policies" From d2ece93c12237459901928e163a0127f82b94235 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 14 May 2024 20:28:14 +0200 Subject: [PATCH 129/205] #222 Migrate to middleware_automation.common.maven_artifact --- requirements.txt | 2 +- requirements.yml | 2 +- roles/keycloak_quarkus/README.md | 7 +++---- roles/keycloak_quarkus/tasks/install.yml | 6 +++--- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/requirements.txt b/requirements.txt index a91d12a..5de7845 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,4 @@ # pip install -r requirements.txt # netaddr -lxml # for community.general.maven_artifact \ No newline at end of file +lxml # for middleware_automation.common.maven_artifact \ No newline at end of file diff --git a/requirements.yml b/requirements.yml index 10150ad..06e5714 100644 --- a/requirements.yml +++ b/requirements.yml @@ -1,5 +1,5 @@ --- collections: - name: middleware_automation.common + version: ">=1.2.1" - name: ansible.posix - - name: community.general # for `maven_artifact` diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 28f81aa..3e4ce6d 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -21,7 +21,6 @@ The roles depends on: * [middleware_automation.common](https://github.com/ansible-middleware/common) * [ansible-posix](https://docs.ansible.com/ansible/latest/collections/ansible/posix/index.html) -* [community.general](https://docs.ansible.com/ansible/latest/collections/community/general/index.html) To install all the dependencies via galaxy: @@ -180,9 +179,9 @@ Role Defaults Providers support different sources: -* `url`: http download for SPIs not requiring authentication -* `maven`: maven download for SPIs hosted publicly on Apache Maven Central or private Maven repositories like Github Maven requiring authentication -* `local_path`: static SPIs to be uploaded +* `url`: http download for providers not requiring authentication +* `maven`: maven download for providers hosted publicly on Apache Maven Central or private Maven repositories like Github Maven requiring authentication +* `local_path`: static providers to be uploaded Provider definition: diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index 6c8b31d..ced4191 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -229,7 +229,7 @@ # this requires the `lxml` package to be installed; we redirect this step to localhost such that we do need to install it on the remote hosts - name: "Download custom providers to localhost using maven" - community.general.maven_artifact: + middleware_automation.common.maven_artifact: repository_url: "{{ item.maven.repository_url }}" group_id: "{{ item.maven.group_id }}" artifact_id: "{{ item.maven.artifact_id }}" @@ -244,7 +244,7 @@ no_log: "{{ item.maven.password is defined and item.maven.password | length > 0 | default(false) }}" notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or not item.restart else [] }}" -- name: "Upload local maven SPIs" +- name: "Upload local maven providers" ansible.builtin.copy: src: "{{ local_path.stat.path }}/{{ item.id }}.jar" dest: "{{ keycloak.home }}/providers/{{ item.id }}.jar" @@ -256,7 +256,7 @@ when: item.maven is defined no_log: "{{ item.maven.password is defined and item.maven.password | length > 0 | default(false) }}" -- name: "Upload local SPIs" +- name: "Upload local providers" ansible.builtin.copy: src: "{{ item.local_path}}" dest: "{{ keycloak.home }}/providers/{{ item.id }}.jar" From 5adb28dcd83c217e059f5775fa80ac9a9cc12a9d Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 15 May 2024 09:22:45 +0200 Subject: [PATCH 130/205] Bump to 2.3.0 --- galaxy.yml | 4 ++-- github.json | 0 2 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 github.json diff --git a/galaxy.yml b/galaxy.yml index 1e6fd20..da8794c 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.2.3" +version: "2.3.0" readme: README.md authors: - Romain Pelisse @@ -26,7 +26,7 @@ tags: - middleware - a4mw dependencies: - "middleware_automation.common": ">=1.1.0" + "middleware_automation.common": ">=1.2.1" "ansible.posix": ">=1.4.0" repository: https://github.com/ansible-middleware/keycloak documentation: https://ansible-middleware.github.io/keycloak diff --git a/github.json b/github.json deleted file mode 100644 index e69de29..0000000 From d57be1f188bec5bdf886605dad8581dfc158db94 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 14 May 2024 13:59:51 +0200 Subject: [PATCH 131/205] Close #182, #221: improve restart handler logic --- roles/keycloak_quarkus/tasks/restart.yml | 43 ++++++++++++++++++++---- roles/keycloak_quarkus/vars/main.yml | 2 +- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/roles/keycloak_quarkus/tasks/restart.yml b/roles/keycloak_quarkus/tasks/restart.yml index 77e1099..4b43ac8 100644 --- a/roles/keycloak_quarkus/tasks/restart.yml +++ b/roles/keycloak_quarkus/tasks/restart.yml @@ -1,9 +1,38 @@ --- -- name: "Restart and enable {{ keycloak.service_name }} service" +- name: Ensure only one service at a time gets rebooted, to ensure replication of distributed ispn caches throttle: 1 - ansible.builtin.systemd: - name: keycloak - enabled: true - state: restarted - daemon_reload: true - become: true + block: + - name: "Restart and enable {{ keycloak.service_name }} service on first host" + ansible.builtin.systemd: + name: "{{ keycloak.service_name }}" + enabled: true + state: restarted + daemon_reload: true + become: true + delegate_to: "{{ ansible_play_hosts | first }}" + run_once: true + + - name: "Wait until {{ keycloak.service_name }} service becomes active {{ keycloak.health_url }}" + ansible.builtin.uri: + url: "{{ keycloak.health_url }}" + register: keycloak_status + until: keycloak_status.status == 200 + retries: 25 + delay: 10 + delegate_to: "{{ ansible_play_hosts | first }}" + run_once: true + + - name: Pause to give distributed ispn caches time to (re-)replicate back onto first host + ansible.builtin.pause: + seconds: 15 + when: + - rhbk_ha_enabled + + - name: "Restart and enable {{ keycloak.service_name }} service on all other hosts" + ansible.builtin.systemd: + name: "{{ keycloak.service_name }}" + enabled: true + state: restarted + daemon_reload: true + become: true + when: inventory_hostname != ansible_play_hosts | first diff --git a/roles/keycloak_quarkus/vars/main.yml b/roles/keycloak_quarkus/vars/main.yml index fcf82f0..a5c4aaa 100644 --- a/roles/keycloak_quarkus/vars/main.yml +++ b/roles/keycloak_quarkus/vars/main.yml @@ -4,7 +4,7 @@ keycloak: # noqa var-naming this is an internal dict of interpolated values config_dir: "{{ keycloak_quarkus_config_dir }}" bundle: "{{ keycloak_quarkus_archive }}" service_name: "keycloak" - health_url: "http://{{ keycloak_quarkus_host }}:{{ keycloak_quarkus_http_port }}{{ keycloak_quarkus_http_relative_path }}{{ '/' \ + health_url: "{{ 'https' if keycloak_quarkus_http_enabled == False else 'http' }}://{{ keycloak_quarkus_host }}:{{ keycloak_quarkus_https_port if keycloak_quarkus_http_enabled == False else keycloak_quarkus_http_port }}{{ keycloak_quarkus_http_relative_path }}{{ '/' \ if keycloak_quarkus_http_relative_path | length > 1 else '' }}realms/master/.well-known/openid-configuration" cli_path: "{{ keycloak_quarkus_home }}/bin/kcadm.sh" service_user: "{{ keycloak_quarkus_service_user }}" From db831fa339c6d2c8e31aba7a2c2146f080aa9234 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Wed, 15 May 2024 10:17:32 +0200 Subject: [PATCH 132/205] #182 - CR changes --- roles/keycloak_quarkus/tasks/restart.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/keycloak_quarkus/tasks/restart.yml b/roles/keycloak_quarkus/tasks/restart.yml index 4b43ac8..4d55189 100644 --- a/roles/keycloak_quarkus/tasks/restart.yml +++ b/roles/keycloak_quarkus/tasks/restart.yml @@ -26,7 +26,7 @@ ansible.builtin.pause: seconds: 15 when: - - rhbk_ha_enabled + - keycloak_quarkus_ha_enabled - name: "Restart and enable {{ keycloak.service_name }} service on all other hosts" ansible.builtin.systemd: From 1e9a669deab77ef65e749f9926211fe35eaea40c Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Wed, 15 May 2024 10:28:46 +0200 Subject: [PATCH 133/205] #221 - add keycloak_quarkus_health_check_url_path config option --- roles/keycloak_quarkus/README.md | 1 + roles/keycloak_quarkus/meta/argument_specs.yml | 4 ++++ roles/keycloak_quarkus/vars/main.yml | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index a011f29..2ba3c99 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -66,6 +66,7 @@ Role Defaults |`keycloak_quarkus_admin_url`| Set the base URL for accessing the administration console, including scheme, host, port and path | | |`keycloak_quarkus_http_relative_path` | Set the path relative to / for serving resources. The path must start with a / | `/` | |`keycloak_quarkus_http_enabled`| Enable listener on HTTP port | `True` | +|`keycloak_quarkus_health_check_url_path`| Path to the health check endpoint; scheme, host and keycloak_quarkus_http_relative_path will be prepended automatically | `realms/master/.well-known/openid-configuration` | |`keycloak_quarkus_https_key_file_enabled`| Enable listener on HTTPS port | `False` | |`keycloak_quarkus_key_file_copy_enabled`| Enable copy of key file to target host | `False` | |`keycloak_quarkus_key_content`| Content of the TLS private key. Use `"{{ lookup('file', 'server.key.pem') }}"` to lookup a file. | `""` | diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 11d928f..6936fa2 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -104,6 +104,10 @@ argument_specs: default: 8080 description: "HTTP port" type: "int" + keycloak_quarkus_health_check_url_path: + default: "realms/master/.well-known/openid-configuration" + description: "Path to the health check endpoint; scheme, host and keycloak_quarkus_http_relative_path will be prepended automatically" + type: "str" keycloak_quarkus_https_key_file_enabled: default: false description: "Enable configuration of HTTPS via files in PEM format" diff --git a/roles/keycloak_quarkus/vars/main.yml b/roles/keycloak_quarkus/vars/main.yml index a5c4aaa..e59af55 100644 --- a/roles/keycloak_quarkus/vars/main.yml +++ b/roles/keycloak_quarkus/vars/main.yml @@ -5,7 +5,7 @@ keycloak: # noqa var-naming this is an internal dict of interpolated values bundle: "{{ keycloak_quarkus_archive }}" service_name: "keycloak" health_url: "{{ 'https' if keycloak_quarkus_http_enabled == False else 'http' }}://{{ keycloak_quarkus_host }}:{{ keycloak_quarkus_https_port if keycloak_quarkus_http_enabled == False else keycloak_quarkus_http_port }}{{ keycloak_quarkus_http_relative_path }}{{ '/' \ - if keycloak_quarkus_http_relative_path | length > 1 else '' }}realms/master/.well-known/openid-configuration" + if keycloak_quarkus_http_relative_path | length > 1 else '' }}{{ keycloak_quarkus_health_check_url_path | default('realms/master/.well-known/openid-configuration') }}" cli_path: "{{ keycloak_quarkus_home }}/bin/kcadm.sh" service_user: "{{ keycloak_quarkus_service_user }}" service_group: "{{ keycloak_quarkus_service_group }}" From 2d573c2b626e348130b921ad827ed3a222daee75 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 15 May 2024 13:34:29 +0200 Subject: [PATCH 134/205] Add restart strategies, and allow custom task include Co-authored-by: Helmut Wolf Co-authored-by: Guido Grazioli --- roles/keycloak_quarkus/defaults/main.yml | 5 ++ roles/keycloak_quarkus/handlers/main.yml | 3 +- .../keycloak_quarkus/meta/argument_specs.yml | 22 +++++++- roles/keycloak_quarkus/tasks/install.yml | 4 +- roles/keycloak_quarkus/tasks/prereqs.yml | 18 +++++-- roles/keycloak_quarkus/tasks/restart.yml | 51 ++++++------------- roles/keycloak_quarkus/tasks/restart/none.yml | 4 ++ .../keycloak_quarkus/tasks/restart/serial.yml | 8 +++ .../tasks/restart/verify_first.yml | 34 +++++++++++++ 9 files changed, 104 insertions(+), 45 deletions(-) create mode 100644 roles/keycloak_quarkus/tasks/restart/none.yml create mode 100644 roles/keycloak_quarkus/tasks/restart/serial.yml create mode 100644 roles/keycloak_quarkus/tasks/restart/verify_first.yml diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index d61cfff..0dde230 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -153,3 +153,8 @@ keycloak_quarkus_ks_vault_pass: keycloak_quarkus_providers: [] keycloak_quarkus_policies: [] keycloak_quarkus_supported_policy_types: ['password-blacklists'] + +# files in restart directory (one of [ 'serial', 'none', 'verify_first' ]), or path to file when providing custom strategy +keycloak_quarkus_restart_strategy: restart/serial.yml +keycloak_quarkus_restart_health_check: "{{ keycloak_quarkus_ha_enabled }}" +keycloak_quarkus_restart_pause: 15 diff --git a/roles/keycloak_quarkus/handlers/main.yml b/roles/keycloak_quarkus/handlers/main.yml index b95d5c3..5851a71 100644 --- a/roles/keycloak_quarkus/handlers/main.yml +++ b/roles/keycloak_quarkus/handlers/main.yml @@ -7,7 +7,8 @@ ansible.builtin.include_tasks: bootstrapped.yml listen: bootstrapped - name: "Restart {{ keycloak.service_name }}" - ansible.builtin.include_tasks: restart.yml + ansible.builtin.include_tasks: + file: "{{ keycloak_quarkus_restart_strategy if keycloak_quarkus_ha_enabled else 'restart.yml' }}" listen: "restart keycloak" - name: "Print deprecation warning" ansible.builtin.fail: diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 6936fa2..01dbfb9 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -399,7 +399,13 @@ argument_specs: default: 10 type: 'int' keycloak_quarkus_providers: - description: "List of provider definition dicts: { 'id': str, 'spi': str, 'url': str, 'local_path': str, 'maven': { 'repository_url': str, 'group_id': str, 'artifact_id': str, 'version': str, 'username': str, optional, 'password': str, optional }, 'default': bool, 'properties': list of key/value }" + description: > + List of provider definition dicts: { 'id': str, 'spi': str, 'url': str, 'local_path': str, + 'maven': { + 'repository_url': str, 'group_id': str, 'artifact_id': str, 'version': str, 'username': str, optional, 'password': str, optional + }, + 'default': bool, + 'properties': list of key/value } default: [] type: "list" keycloak_quarkus_supported_policy_types: @@ -425,6 +431,20 @@ argument_specs: default: true description: "Allow the option to ignore invalid certificates when downloading JDBC drivers from a custom URL" type: "bool" + keycloak_quarkus_restart_health_check: + default: "{{ keycloak_quarkus_ha_enabled }}" + description: "Whether to wait on successful health check after restart" + type: "bool" + keycloak_quarkus_restart_strategy: + description: > + Strategy task file for restarting in HA, one of [ 'serial', 'none', 'verify_first' ] below, or path to + file when providing custom strategy + default: "restart/serial.yml" + type: "str" + keycloak_quarkus_restart_pause: + description: "Seconds to wait between restarts in HA strategy" + default: 15 + type: int downstream: options: rhbk_version: diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index ced4191..7745031 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -258,7 +258,7 @@ - name: "Upload local providers" ansible.builtin.copy: - src: "{{ item.local_path}}" + src: "{{ item.local_path }}" dest: "{{ keycloak.home }}/providers/{{ item.id }}.jar" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" @@ -280,7 +280,7 @@ - name: "Install custom policies" ansible.builtin.get_url: url: "{{ item.url }}" - dest: "{{ keycloak.home }}/data/{{ item.type|default(keycloak_quarkus_supported_policy_types | first) | lower }}/{{ item.name }}" + dest: "{{ keycloak.home }}/data/{{ item.type | default(keycloak_quarkus_supported_policy_types | first) | lower }}/{{ item.name }}" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" mode: '0640' diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index d901c71..220f65b 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -59,11 +59,18 @@ - name: "Validate providers" ansible.builtin.assert: - that: - - item.id is defined and item.id | length > 0 - - (item.spi is defined and item.spi | length > 0) or (item.url is defined and item.url | length > 0) or (item.maven is defined and item.maven.repository_url is defined and item.maven.repository_url | length > 0 and item.maven.group_id is defined and item.maven.group_id | length > 0 and item.maven.artifact_id is defined and item.maven.artifact_id | length > 0) or (item.local_path is defined and item.local_path | length > 0) + that: > + item.id is defined and item.id | length > 0 and + ( (item.spi is defined and item.spi | length > 0) or + (item.url is defined and item.url | length > 0) or + ( item.maven is defined and item.maven.repository_url is defined and item.maven.repository_url | length > 0 and + item.maven.group_id is defined and item.maven.group_id | length > 0 and + item.maven.artifact_id is defined and item.maven.artifact_id | length > 0) or + (item.local_path is defined and item.local_path | length > 0) + ) quiet: true - fail_msg: "Providers definition is incorrect; `id` and one of `spi`, `url`, `local_path`, or `maven` are mandatory. `key` and `value` are mandatory for each property" + fail_msg: > + Providers definition incorrect; `id` and one of `spi`, `url`, `local_path`, or `maven` are mandatory. `key` and `value` are mandatory for each property loop: "{{ keycloak_quarkus_providers }}" - name: "Validate policies" @@ -73,7 +80,8 @@ - item.url is defined and item.url | length > 0 - item.type is not defined or item.type | lower in keycloak_quarkus_supported_policy_types quiet: true - fail_msg: "Policy definition is incorrect: `name` and one of `url` are mandatory, `type` needs to be left empty or one of {{ keycloak_quarkus_supported_policy_types }}." + fail_msg: > + Policy definition is incorrect: `name` and one of `url` are mandatory, `type` needs to be left empty or one of {{ keycloak_quarkus_supported_policy_types }}. loop: "{{ keycloak_quarkus_policies }}" - name: "Validate additional env variables" diff --git a/roles/keycloak_quarkus/tasks/restart.yml b/roles/keycloak_quarkus/tasks/restart.yml index 4d55189..9255114 100644 --- a/roles/keycloak_quarkus/tasks/restart.yml +++ b/roles/keycloak_quarkus/tasks/restart.yml @@ -1,38 +1,17 @@ --- -- name: Ensure only one service at a time gets rebooted, to ensure replication of distributed ispn caches - throttle: 1 - block: - - name: "Restart and enable {{ keycloak.service_name }} service on first host" - ansible.builtin.systemd: - name: "{{ keycloak.service_name }}" - enabled: true - state: restarted - daemon_reload: true - become: true - delegate_to: "{{ ansible_play_hosts | first }}" - run_once: true +- name: "Restart and enable {{ keycloak.service_name }} service" + ansible.builtin.systemd: + name: "{{ keycloak.service_name }}" + enabled: true + state: restarted + daemon_reload: true + become: true - - name: "Wait until {{ keycloak.service_name }} service becomes active {{ keycloak.health_url }}" - ansible.builtin.uri: - url: "{{ keycloak.health_url }}" - register: keycloak_status - until: keycloak_status.status == 200 - retries: 25 - delay: 10 - delegate_to: "{{ ansible_play_hosts | first }}" - run_once: true - - - name: Pause to give distributed ispn caches time to (re-)replicate back onto first host - ansible.builtin.pause: - seconds: 15 - when: - - keycloak_quarkus_ha_enabled - - - name: "Restart and enable {{ keycloak.service_name }} service on all other hosts" - ansible.builtin.systemd: - name: "{{ keycloak.service_name }}" - enabled: true - state: restarted - daemon_reload: true - become: true - when: inventory_hostname != ansible_play_hosts | first +- name: "Wait until {{ keycloak.service_name }} service becomes active {{ keycloak.health_url }}" + ansible.builtin.uri: + url: "{{ keycloak.health_url }}" + register: keycloak_status + until: keycloak_status.status == 200 + retries: 25 + delay: 10 + when: keycloak_quarkus_restart_health_check diff --git a/roles/keycloak_quarkus/tasks/restart/none.yml b/roles/keycloak_quarkus/tasks/restart/none.yml new file mode 100644 index 0000000..d048959 --- /dev/null +++ b/roles/keycloak_quarkus/tasks/restart/none.yml @@ -0,0 +1,4 @@ +--- +- name: "Display message" + ansible.builtin.debug: + msg: "keycloak_quarkus_restart_strategy is none, skipping restart" diff --git a/roles/keycloak_quarkus/tasks/restart/serial.yml b/roles/keycloak_quarkus/tasks/restart/serial.yml new file mode 100644 index 0000000..74e8e3b --- /dev/null +++ b/roles/keycloak_quarkus/tasks/restart/serial.yml @@ -0,0 +1,8 @@ +--- +- name: "Restart services in serial, with optional healtch check (keycloak_quarkus_restart_health_check)" + throttle: 1 + loop: "{{ ansible_play_hosts }}" + block: + - name: "Restart and enable {{ keycloak.service_name }} service on first host" + ansible.builtin.include_tasks: ../restart.yml + delegate_to: "{{ item }}" diff --git a/roles/keycloak_quarkus/tasks/restart/verify_first.yml b/roles/keycloak_quarkus/tasks/restart/verify_first.yml new file mode 100644 index 0000000..64e2f53 --- /dev/null +++ b/roles/keycloak_quarkus/tasks/restart/verify_first.yml @@ -0,0 +1,34 @@ +--- +- name: Verify first restarted service with health URL, then rest in parallel + block: + - name: "Restart and enable {{ keycloak.service_name }} service on first host" + ansible.builtin.systemd: + name: "{{ keycloak.service_name }}" + enabled: true + state: restarted + daemon_reload: true + become: true + delegate_to: "{{ ansible_play_hosts | first }}" + run_once: true + + - name: "Wait until {{ keycloak.service_name }} service becomes active {{ keycloak.health_url }}" + ansible.builtin.uri: + url: "{{ keycloak.health_url }}" + register: keycloak_status + until: keycloak_status.status == 200 + retries: 25 + delay: 10 + delegate_to: "{{ ansible_play_hosts | first }}" + run_once: true + + - name: Pause to give distributed ispn caches time to (re-)replicate back onto first host + ansible.builtin.pause: + seconds: "{{ keycloak_quarkus_restart_pause }}" + when: + - keycloak_quarkus_ha_enabled + + - name: "Restart and enable {{ keycloak.service_name }} service on other hosts" + ansible.builtin.include_tasks: ../restart.yml + delegate_to: "{{ item }}" + loop: "{{ ansible_play_hosts }}" + when: inventory_hostname != ansible_play_hosts | first From c22389c86fabce46d98bab90f8761586b97e000a Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 15 May 2024 15:58:21 +0200 Subject: [PATCH 135/205] address review reqs --- roles/keycloak_quarkus/README.md | 3 +++ roles/keycloak_quarkus/defaults/main.yml | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 6 +++--- roles/keycloak_quarkus/tasks/restart.yml | 6 ++++++ roles/keycloak_quarkus/tasks/restart/serial.yml | 9 ++++++--- .../{verify_first.yml => serial_then_parallel.yml} | 11 +++++++---- 6 files changed, 26 insertions(+), 11 deletions(-) rename roles/keycloak_quarkus/tasks/restart/{verify_first.yml => serial_then_parallel.yml} (85%) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 2ba3c99..a9dbea0 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -101,6 +101,9 @@ Role Defaults |`keycloak_quarkus_systemd_wait_for_log` | Whether systemd unit should wait for service to be up in logs | `false` | |`keycloak_quarkus_systemd_wait_for_timeout`| How long to wait for service to be alive (seconds) | `60` | |`keycloak_quarkus_systemd_wait_for_delay`| Activation delay for service systemd unit (seconds) | `10` | +|`keycloak_quarkus_restart_strategy`| Strategy task file for restarting in HA (one of provided restart/['serial.yml','none.yml','serial_then_parallel.yml']) or path to file when providing custom strategy | `restart/serial.yml` | +|`keycloak_quarkus_restart_health_check`| Whether to wait for successful health check after restart | `{{ keycloak_quarkus_ha_enabled }}` | +|`keycloak_quarkus_restart_pause`| Seconds to wait between restarts in HA strategy | `15` | #### Hostname configuration diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 0dde230..c152a20 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -154,7 +154,7 @@ keycloak_quarkus_providers: [] keycloak_quarkus_policies: [] keycloak_quarkus_supported_policy_types: ['password-blacklists'] -# files in restart directory (one of [ 'serial', 'none', 'verify_first' ]), or path to file when providing custom strategy +# files in restart directory (one of [ 'serial', 'none', 'serial_then_parallel' ]), or path to file when providing custom strategy keycloak_quarkus_restart_strategy: restart/serial.yml keycloak_quarkus_restart_health_check: "{{ keycloak_quarkus_ha_enabled }}" keycloak_quarkus_restart_pause: 15 diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 01dbfb9..3e06525 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -433,12 +433,12 @@ argument_specs: type: "bool" keycloak_quarkus_restart_health_check: default: "{{ keycloak_quarkus_ha_enabled }}" - description: "Whether to wait on successful health check after restart" + description: "Whether to wait for successful health check after restart" type: "bool" keycloak_quarkus_restart_strategy: description: > - Strategy task file for restarting in HA, one of [ 'serial', 'none', 'verify_first' ] below, or path to - file when providing custom strategy + Strategy task file for restarting in HA, one of restart/[ 'serial', 'none', 'serial_then_parallel' ].yml, or path to + file when providing custom strategy; when keycloak_quarkus_ha_enabled and keycloak_quarkus_restart_health_check == true default: "restart/serial.yml" type: "str" keycloak_quarkus_restart_pause: diff --git a/roles/keycloak_quarkus/tasks/restart.yml b/roles/keycloak_quarkus/tasks/restart.yml index 9255114..bcb8c1d 100644 --- a/roles/keycloak_quarkus/tasks/restart.yml +++ b/roles/keycloak_quarkus/tasks/restart.yml @@ -15,3 +15,9 @@ retries: 25 delay: 10 when: keycloak_quarkus_restart_health_check + +- name: Pause to give distributed ispn caches time to (re-)replicate back onto first host + ansible.builtin.pause: + seconds: "{{ keycloak_quarkus_restart_pause }}" + when: + - keycloak_quarkus_ha_enabled diff --git a/roles/keycloak_quarkus/tasks/restart/serial.yml b/roles/keycloak_quarkus/tasks/restart/serial.yml index 74e8e3b..d98dbf9 100644 --- a/roles/keycloak_quarkus/tasks/restart/serial.yml +++ b/roles/keycloak_quarkus/tasks/restart/serial.yml @@ -3,6 +3,9 @@ throttle: 1 loop: "{{ ansible_play_hosts }}" block: - - name: "Restart and enable {{ keycloak.service_name }} service on first host" - ansible.builtin.include_tasks: ../restart.yml - delegate_to: "{{ item }}" + - name: "Restart and enable {{ keycloak.service_name }} service on {{ item }}" + ansible.builtin.include_tasks: + file: ../restart.yml + apply: + delegate_to: "{{ item }}" + run_once: true diff --git a/roles/keycloak_quarkus/tasks/restart/verify_first.yml b/roles/keycloak_quarkus/tasks/restart/serial_then_parallel.yml similarity index 85% rename from roles/keycloak_quarkus/tasks/restart/verify_first.yml rename to roles/keycloak_quarkus/tasks/restart/serial_then_parallel.yml index 64e2f53..372a302 100644 --- a/roles/keycloak_quarkus/tasks/restart/verify_first.yml +++ b/roles/keycloak_quarkus/tasks/restart/serial_then_parallel.yml @@ -1,5 +1,5 @@ --- -- name: Verify first restarted service with health URL, then rest in parallel +- name: Verify first restarted service with health URL, then rest restart in parallel block: - name: "Restart and enable {{ keycloak.service_name }} service on first host" ansible.builtin.systemd: @@ -28,7 +28,10 @@ - keycloak_quarkus_ha_enabled - name: "Restart and enable {{ keycloak.service_name }} service on other hosts" - ansible.builtin.include_tasks: ../restart.yml - delegate_to: "{{ item }}" - loop: "{{ ansible_play_hosts }}" + ansible.builtin.systemd: + name: "{{ keycloak.service_name }}" + enabled: true + state: restarted + daemon_reload: true + become: true when: inventory_hostname != ansible_play_hosts | first From fdcf1b2ed2d45f696f20263a267cc637a21a5bf8 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 15 May 2024 19:53:33 +0200 Subject: [PATCH 136/205] Add molecule scenario for HA restart --- .github/workflows/ci.yml | 2 +- .gitignore | 1 + molecule/quarkus/converge.yml | 2 +- molecule/quarkus_ha/converge.yml | 29 + molecule/quarkus_ha/molecule.yml | 79 ++ .../quarkus_ha/postgresql/postgresql.conf | 750 ++++++++++++++++++ molecule/quarkus_ha/prepare.yml | 44 + molecule/quarkus_ha/roles | 1 + molecule/quarkus_ha/verify.yml | 86 ++ .../keycloak_quarkus/tasks/restart/serial.yml | 4 +- .../templates/quarkus.properties.j2 | 2 +- 11 files changed, 995 insertions(+), 5 deletions(-) create mode 100644 molecule/quarkus_ha/converge.yml create mode 100644 molecule/quarkus_ha/molecule.yml create mode 100644 molecule/quarkus_ha/postgresql/postgresql.conf create mode 100644 molecule/quarkus_ha/prepare.yml create mode 120000 molecule/quarkus_ha/roles create mode 100644 molecule/quarkus_ha/verify.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d5cac41..0927320 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,4 +15,4 @@ jobs: with: fqcn: 'middleware_automation/keycloak' molecule_tests: >- - [ "default", "overridexml", "https_revproxy", "quarkus", "quarkus-devmode", "quarkus_upgrade", "debian" ] + [ "default", "overridexml", "https_revproxy", "quarkus", "quarkus-devmode", "quarkus_upgrade", "debian", "quarkus_ha" ] diff --git a/.gitignore b/.gitignore index e1daa92..f2ffea4 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ docs/_build/ *.retry changelogs/.plugin-cache.yaml *.pem +*.key diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index 2fa1ceb..da0f3dc 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -7,7 +7,7 @@ keycloak_realm: TestRealm keycloak_quarkus_host: instance keycloak_quarkus_log: file - keycloak_quarkus_log_level: debug + keycloak_quarkus_log_level: info keycloak_quarkus_https_key_file_enabled: true keycloak_quarkus_key_file_copy_enabled: true keycloak_quarkus_key_content: "{{ lookup('file', 'key.pem') }}" diff --git a/molecule/quarkus_ha/converge.yml b/molecule/quarkus_ha/converge.yml new file mode 100644 index 0000000..2434e65 --- /dev/null +++ b/molecule/quarkus_ha/converge.yml @@ -0,0 +1,29 @@ +--- +- name: Converge + hosts: keycloak + vars: + keycloak_quarkus_admin_pass: "remembertochangeme" + keycloak_admin_password: "remembertochangeme" + keycloak_realm: TestRealm + keycloak_quarkus_host: "{{ inventory_hostname }}" + keycloak_quarkus_log: file + keycloak_quarkus_log_level: info + keycloak_quarkus_https_key_file_enabled: true + keycloak_quarkus_key_file_copy_enabled: true + keycloak_quarkus_key_content: "{{ lookup('file', inventory_hostname + '.key') }}" + keycloak_quarkus_cert_file_copy_enabled: true + keycloak_quarkus_cert_file_src: "{{ inventory_hostname }}.pem" + keycloak_quarkus_ks_vault_enabled: true + keycloak_quarkus_ks_vault_file: "/opt/keycloak/vault/keystore.p12" + keycloak_quarkus_ks_vault_pass: keystorepassword + keycloak_quarkus_systemd_wait_for_port: true + keycloak_quarkus_systemd_wait_for_timeout: 20 + keycloak_quarkus_systemd_wait_for_delay: 2 + keycloak_quarkus_systemd_wait_for_log: true + keycloak_quarkus_ha_enabled: true + keycloak_quarkus_restart_strategy: restart/serial.yml + keycloak_quarkus_db_user: keycloak + keycloak_quarkus_db_pass: mysecretpass + keycloak_quarkus_jdbc_url: jdbc:postgresql://postgres:5432/keycloak + roles: + - role: keycloak_quarkus diff --git a/molecule/quarkus_ha/molecule.yml b/molecule/quarkus_ha/molecule.yml new file mode 100644 index 0000000..8e07e0f --- /dev/null +++ b/molecule/quarkus_ha/molecule.yml @@ -0,0 +1,79 @@ +--- +driver: + name: docker +platforms: + - name: instance1 + image: registry.access.redhat.com/ubi9/ubi-init:latest + pre_build_image: true + privileged: true + command: "/usr/sbin/init" + groups: + - keycloak + networks: + - name: rhbk + port_bindings: + - "8080/tcp" + - "8443/tcp" + - name: instance2 + image: registry.access.redhat.com/ubi9/ubi-init:latest + pre_build_image: true + privileged: true + command: "/usr/sbin/init" + groups: + - keycloak + networks: + - name: rhbk + port_bindings: + - "8080/tcp" + - "8443/tcp" + - name: postgres + image: ubuntu/postgres:14-22.04_beta + pre_build_image: true + privileged: true + command: postgres + groups: + - database + networks: + - name: rhbk + port_bindings: + - "5432/tcp" + mounts: + - type: bind + target: /etc/postgresql/postgresql.conf + source: ${PWD}/molecule/quarkus_ha/postgresql/postgresql.conf + env: + POSTGRES_USER: keycloak + POSTGRES_PASSWORD: mysecretpass + POSTGRES_DB: keycloak + POSTGRES_HOST_AUTH_METHOD: trust +provisioner: + name: ansible + config_options: + defaults: + interpreter_python: auto_silent + ssh_connection: + pipelining: false + playbooks: + prepare: prepare.yml + converge: converge.yml + verify: verify.yml + inventory: + host_vars: + localhost: + ansible_python_interpreter: "{{ ansible_playbook_python }}" + env: + ANSIBLE_FORCE_COLOR: "true" +verifier: + name: ansible +scenario: + test_sequence: + - cleanup + - destroy + - create + - prepare + - converge + - idempotence + - side_effect + - verify + - cleanup + - destroy diff --git a/molecule/quarkus_ha/postgresql/postgresql.conf b/molecule/quarkus_ha/postgresql/postgresql.conf new file mode 100644 index 0000000..d702576 --- /dev/null +++ b/molecule/quarkus_ha/postgresql/postgresql.conf @@ -0,0 +1,750 @@ +# ----------------------------- +# PostgreSQL configuration file +# ----------------------------- +# +# This file consists of lines of the form: +# +# name = value +# +# (The "=" is optional.) Whitespace may be used. Comments are introduced with +# "#" anywhere on a line. The complete list of parameter names and allowed +# values can be found in the PostgreSQL documentation. +# +# The commented-out settings shown in this file represent the default values. +# Re-commenting a setting is NOT sufficient to revert it to the default value; +# you need to reload the server. +# +# This file is read on server startup and when the server receives a SIGHUP +# signal. If you edit the file on a running system, you have to SIGHUP the +# server for the changes to take effect, run "pg_ctl reload", or execute +# "SELECT pg_reload_conf()". Some parameters, which are marked below, +# require a server shutdown and restart to take effect. +# +# Any parameter can also be given as a command-line option to the server, e.g., +# "postgres -c log_connections=on". Some parameters can be changed at run time +# with the "SET" SQL command. +# +# Memory units: kB = kilobytes Time units: ms = milliseconds +# MB = megabytes s = seconds +# GB = gigabytes min = minutes +# TB = terabytes h = hours +# d = days + + +#------------------------------------------------------------------------------ +# FILE LOCATIONS +#------------------------------------------------------------------------------ + +# The default values of these variables are driven from the -D command-line +# option or PGDATA environment variable, represented here as ConfigDir. + +#data_directory = 'ConfigDir' # use data in another directory + # (change requires restart) +#hba_file = 'ConfigDir/pg_hba.conf' # host-based authentication file + # (change requires restart) +#ident_file = 'ConfigDir/pg_ident.conf' # ident configuration file + # (change requires restart) + +# If external_pid_file is not explicitly set, no extra PID file is written. +#external_pid_file = '' # write an extra PID file + # (change requires restart) + + +#------------------------------------------------------------------------------ +# CONNECTIONS AND AUTHENTICATION +#------------------------------------------------------------------------------ + +# - Connection Settings - + +listen_addresses = '*' # what IP address(es) to listen on; + # comma-separated list of addresses; + # defaults to 'localhost'; use '*' for all + # (change requires restart) +#port = 5432 # (change requires restart) +#max_connections = 100 # (change requires restart) +#superuser_reserved_connections = 3 # (change requires restart) +#unix_socket_directories = '/tmp' # comma-separated list of directories + # (change requires restart) +#unix_socket_group = '' # (change requires restart) +#unix_socket_permissions = 0777 # begin with 0 to use octal notation + # (change requires restart) +#bonjour = off # advertise server via Bonjour + # (change requires restart) +#bonjour_name = '' # defaults to the computer name + # (change requires restart) + +# - TCP settings - +# see "man 7 tcp" for details + +#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; + # 0 selects the system default +#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; + # 0 selects the system default +#tcp_keepalives_count = 0 # TCP_KEEPCNT; + # 0 selects the system default +#tcp_user_timeout = 0 # TCP_USER_TIMEOUT, in milliseconds; + # 0 selects the system default + +# - Authentication - + +#authentication_timeout = 1min # 1s-600s +#password_encryption = md5 # md5 or scram-sha-256 +#db_user_namespace = off + +# GSSAPI using Kerberos +#krb_server_keyfile = '' +#krb_caseins_users = off + +# - SSL - + +#ssl = off +#ssl_ca_file = '' +#ssl_cert_file = 'server.crt' +#ssl_crl_file = '' +#ssl_key_file = 'server.key' +#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers +#ssl_prefer_server_ciphers = on +#ssl_ecdh_curve = 'prime256v1' +#ssl_min_protocol_version = 'TLSv1' +#ssl_max_protocol_version = '' +#ssl_dh_params_file = '' +#ssl_passphrase_command = '' +#ssl_passphrase_command_supports_reload = off + + +#------------------------------------------------------------------------------ +# RESOURCE USAGE (except WAL) +#------------------------------------------------------------------------------ + +# - Memory - + +#shared_buffers = 32MB # min 128kB + # (change requires restart) +#huge_pages = try # on, off, or try + # (change requires restart) +#temp_buffers = 8MB # min 800kB +#max_prepared_transactions = 0 # zero disables the feature + # (change requires restart) +# Caution: it is not advisable to set max_prepared_transactions nonzero unless +# you actively intend to use prepared transactions. +#work_mem = 4MB # min 64kB +#maintenance_work_mem = 64MB # min 1MB +#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem +#max_stack_depth = 2MB # min 100kB +#shared_memory_type = mmap # the default is the first option + # supported by the operating system: + # mmap + # sysv + # windows + # (change requires restart) +#dynamic_shared_memory_type = posix # the default is the first option + # supported by the operating system: + # posix + # sysv + # windows + # mmap + # (change requires restart) + +# - Disk - + +#temp_file_limit = -1 # limits per-process temp file space + # in kB, or -1 for no limit + +# - Kernel Resources - + +#max_files_per_process = 1000 # min 25 + # (change requires restart) + +# - Cost-Based Vacuum Delay - + +#vacuum_cost_delay = 0 # 0-100 milliseconds (0 disables) +#vacuum_cost_page_hit = 1 # 0-10000 credits +#vacuum_cost_page_miss = 10 # 0-10000 credits +#vacuum_cost_page_dirty = 20 # 0-10000 credits +#vacuum_cost_limit = 200 # 1-10000 credits + +# - Background Writer - + +#bgwriter_delay = 200ms # 10-10000ms between rounds +#bgwriter_lru_maxpages = 100 # max buffers written/round, 0 disables +#bgwriter_lru_multiplier = 2.0 # 0-10.0 multiplier on buffers scanned/round +#bgwriter_flush_after = 0 # measured in pages, 0 disables + +# - Asynchronous Behavior - + +#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching +#max_worker_processes = 8 # (change requires restart) +#max_parallel_maintenance_workers = 2 # taken from max_parallel_workers +#max_parallel_workers_per_gather = 2 # taken from max_parallel_workers +#parallel_leader_participation = on +#max_parallel_workers = 8 # maximum number of max_worker_processes that + # can be used in parallel operations +#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate + # (change requires restart) +#backend_flush_after = 0 # measured in pages, 0 disables + + +#------------------------------------------------------------------------------ +# WRITE-AHEAD LOG +#------------------------------------------------------------------------------ + +# - Settings - + +#wal_level = replica # minimal, replica, or logical + # (change requires restart) +#fsync = on # flush data to disk for crash safety + # (turning this off can cause + # unrecoverable data corruption) +#synchronous_commit = on # synchronization level; + # off, local, remote_write, remote_apply, or on +#wal_sync_method = fsync # the default is the first option + # supported by the operating system: + # open_datasync + # fdatasync (default on Linux) + # fsync + # fsync_writethrough + # open_sync +#full_page_writes = on # recover from partial page writes +#wal_compression = off # enable compression of full-page writes +#wal_log_hints = off # also do full page writes of non-critical updates + # (change requires restart) +#wal_init_zero = on # zero-fill new WAL files +#wal_recycle = on # recycle WAL files +#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers + # (change requires restart) +#wal_writer_delay = 200ms # 1-10000 milliseconds +#wal_writer_flush_after = 1MB # measured in pages, 0 disables + +#commit_delay = 0 # range 0-100000, in microseconds +#commit_siblings = 5 # range 1-1000 + +# - Checkpoints - + +#checkpoint_timeout = 5min # range 30s-1d +#max_wal_size = 1GB +#min_wal_size = 80MB +#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0 +#checkpoint_flush_after = 0 # measured in pages, 0 disables +#checkpoint_warning = 30s # 0 disables + +# - Archiving - + +#archive_mode = off # enables archiving; off, on, or always + # (change requires restart) +#archive_command = '' # command to use to archive a logfile segment + # placeholders: %p = path of file to archive + # %f = file name only + # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' +#archive_timeout = 0 # force a logfile segment switch after this + # number of seconds; 0 disables + +# - Archive Recovery - + +# These are only used in recovery mode. + +#restore_command = '' # command to use to restore an archived logfile segment + # placeholders: %p = path of file to restore + # %f = file name only + # e.g. 'cp /mnt/server/archivedir/%f %p' + # (change requires restart) +#archive_cleanup_command = '' # command to execute at every restartpoint +#recovery_end_command = '' # command to execute at completion of recovery + +# - Recovery Target - + +# Set these only when performing a targeted recovery. + +#recovery_target = '' # 'immediate' to end recovery as soon as a + # consistent state is reached + # (change requires restart) +#recovery_target_name = '' # the named restore point to which recovery will proceed + # (change requires restart) +#recovery_target_time = '' # the time stamp up to which recovery will proceed + # (change requires restart) +#recovery_target_xid = '' # the transaction ID up to which recovery will proceed + # (change requires restart) +#recovery_target_lsn = '' # the WAL LSN up to which recovery will proceed + # (change requires restart) +#recovery_target_inclusive = on # Specifies whether to stop: + # just after the specified recovery target (on) + # just before the recovery target (off) + # (change requires restart) +#recovery_target_timeline = 'latest' # 'current', 'latest', or timeline ID + # (change requires restart) +#recovery_target_action = 'pause' # 'pause', 'promote', 'shutdown' + # (change requires restart) + + +#------------------------------------------------------------------------------ +# REPLICATION +#------------------------------------------------------------------------------ + +# - Sending Servers - + +# Set these on the master and on any standby that will send replication data. + +#max_wal_senders = 10 # max number of walsender processes + # (change requires restart) +#wal_keep_segments = 0 # in logfile segments; 0 disables +#wal_sender_timeout = 60s # in milliseconds; 0 disables + +#max_replication_slots = 10 # max number of replication slots + # (change requires restart) +#track_commit_timestamp = off # collect timestamp of transaction commit + # (change requires restart) + +# - Master Server - + +# These settings are ignored on a standby server. + +#synchronous_standby_names = '' # standby servers that provide sync rep + # method to choose sync standbys, number of sync standbys, + # and comma-separated list of application_name + # from standby(s); '*' = all +#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed + +# - Standby Servers - + +# These settings are ignored on a master server. + +#primary_conninfo = '' # connection string to sending server + # (change requires restart) +#primary_slot_name = '' # replication slot on sending server + # (change requires restart) +#promote_trigger_file = '' # file name whose presence ends recovery +#hot_standby = on # "off" disallows queries during recovery + # (change requires restart) +#max_standby_archive_delay = 30s # max delay before canceling queries + # when reading WAL from archive; + # -1 allows indefinite delay +#max_standby_streaming_delay = 30s # max delay before canceling queries + # when reading streaming WAL; + # -1 allows indefinite delay +#wal_receiver_status_interval = 10s # send replies at least this often + # 0 disables +#hot_standby_feedback = off # send info from standby to prevent + # query conflicts +#wal_receiver_timeout = 60s # time that receiver waits for + # communication from master + # in milliseconds; 0 disables +#wal_retrieve_retry_interval = 5s # time to wait before retrying to + # retrieve WAL after a failed attempt +#recovery_min_apply_delay = 0 # minimum delay for applying changes during recovery + +# - Subscribers - + +# These settings are ignored on a publisher. + +#max_logical_replication_workers = 4 # taken from max_worker_processes + # (change requires restart) +#max_sync_workers_per_subscription = 2 # taken from max_logical_replication_workers + + +#------------------------------------------------------------------------------ +# QUERY TUNING +#------------------------------------------------------------------------------ + +# - Planner Method Configuration - + +#enable_bitmapscan = on +#enable_hashagg = on +#enable_hashjoin = on +#enable_indexscan = on +#enable_indexonlyscan = on +#enable_material = on +#enable_mergejoin = on +#enable_nestloop = on +#enable_parallel_append = on +#enable_seqscan = on +#enable_sort = on +#enable_tidscan = on +#enable_partitionwise_join = off +#enable_partitionwise_aggregate = off +#enable_parallel_hash = on +#enable_partition_pruning = on + +# - Planner Cost Constants - + +#seq_page_cost = 1.0 # measured on an arbitrary scale +#random_page_cost = 4.0 # same scale as above +#cpu_tuple_cost = 0.01 # same scale as above +#cpu_index_tuple_cost = 0.005 # same scale as above +#cpu_operator_cost = 0.0025 # same scale as above +#parallel_tuple_cost = 0.1 # same scale as above +#parallel_setup_cost = 1000.0 # same scale as above + +#jit_above_cost = 100000 # perform JIT compilation if available + # and query more expensive than this; + # -1 disables +#jit_inline_above_cost = 500000 # inline small functions if query is + # more expensive than this; -1 disables +#jit_optimize_above_cost = 500000 # use expensive JIT optimizations if + # query is more expensive than this; + # -1 disables + +#min_parallel_table_scan_size = 8MB +#min_parallel_index_scan_size = 512kB +#effective_cache_size = 4GB + +# - Genetic Query Optimizer - + +#geqo = on +#geqo_threshold = 12 +#geqo_effort = 5 # range 1-10 +#geqo_pool_size = 0 # selects default based on effort +#geqo_generations = 0 # selects default based on effort +#geqo_selection_bias = 2.0 # range 1.5-2.0 +#geqo_seed = 0.0 # range 0.0-1.0 + +# - Other Planner Options - + +#default_statistics_target = 100 # range 1-10000 +#constraint_exclusion = partition # on, off, or partition +#cursor_tuple_fraction = 0.1 # range 0.0-1.0 +#from_collapse_limit = 8 +#join_collapse_limit = 8 # 1 disables collapsing of explicit + # JOIN clauses +#force_parallel_mode = off +#jit = on # allow JIT compilation +#plan_cache_mode = auto # auto, force_generic_plan or + # force_custom_plan + + +#------------------------------------------------------------------------------ +# REPORTING AND LOGGING +#------------------------------------------------------------------------------ + +# - Where to Log - + +#log_destination = 'stderr' # Valid values are combinations of + # stderr, csvlog, syslog, and eventlog, + # depending on platform. csvlog + # requires logging_collector to be on. + +# This is used when logging to stderr: +#logging_collector = off # Enable capturing of stderr and csvlog + # into log files. Required to be on for + # csvlogs. + # (change requires restart) + +# These are only used if logging_collector is on: +#log_directory = 'log' # directory where log files are written, + # can be absolute or relative to PGDATA +#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern, + # can include strftime() escapes +#log_file_mode = 0600 # creation mode for log files, + # begin with 0 to use octal notation +#log_truncate_on_rotation = off # If on, an existing log file with the + # same name as the new log file will be + # truncated rather than appended to. + # But such truncation only occurs on + # time-driven rotation, not on restarts + # or size-driven rotation. Default is + # off, meaning append to existing files + # in all cases. +#log_rotation_age = 1d # Automatic rotation of logfiles will + # happen after that time. 0 disables. +#log_rotation_size = 10MB # Automatic rotation of logfiles will + # happen after that much log output. + # 0 disables. + +# These are relevant when logging to syslog: +#syslog_facility = 'LOCAL0' +#syslog_ident = 'postgres' +#syslog_sequence_numbers = on +#syslog_split_messages = on + +# This is only relevant when logging to eventlog (win32): +# (change requires restart) +#event_source = 'PostgreSQL' + +# - When to Log - + +#log_min_messages = warning # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic + +#log_min_error_statement = error # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # info + # notice + # warning + # error + # log + # fatal + # panic (effectively off) + +#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements + # and their durations, > 0 logs only + # statements running at least this number + # of milliseconds + +#log_transaction_sample_rate = 0.0 # Fraction of transactions whose statements + # are logged regardless of their duration. 1.0 logs all + # statements from all transactions, 0.0 never logs. + +# - What to Log - + +#debug_print_parse = off +#debug_print_rewritten = off +#debug_print_plan = off +#debug_pretty_print = on +#log_checkpoints = off +#log_connections = off +#log_disconnections = off +#log_duration = off +#log_error_verbosity = default # terse, default, or verbose messages +#log_hostname = off +#log_line_prefix = '%m [%p] ' # special values: + # %a = application name + # %u = user name + # %d = database name + # %r = remote host and port + # %h = remote host + # %p = process ID + # %t = timestamp without milliseconds + # %m = timestamp with milliseconds + # %n = timestamp with milliseconds (as a Unix epoch) + # %i = command tag + # %e = SQL state + # %c = session ID + # %l = session line number + # %s = session start timestamp + # %v = virtual transaction ID + # %x = transaction ID (0 if none) + # %q = stop here in non-session + # processes + # %% = '%' + # e.g. '<%u%%%d> ' +#log_lock_waits = off # log lock waits >= deadlock_timeout +#log_statement = 'none' # none, ddl, mod, all +#log_replication_commands = off +#log_temp_files = -1 # log temporary files equal or larger + # than the specified size in kilobytes; + # -1 disables, 0 logs all temp files +#log_timezone = 'GMT' + +#------------------------------------------------------------------------------ +# PROCESS TITLE +#------------------------------------------------------------------------------ + +#cluster_name = '' # added to process titles if nonempty + # (change requires restart) +#update_process_title = on + + +#------------------------------------------------------------------------------ +# STATISTICS +#------------------------------------------------------------------------------ + +# - Query and Index Statistics Collector - + +#track_activities = on +#track_counts = on +#track_io_timing = off +#track_functions = none # none, pl, all +#track_activity_query_size = 1024 # (change requires restart) +#stats_temp_directory = 'pg_stat_tmp' + + +# - Monitoring - + +#log_parser_stats = off +#log_planner_stats = off +#log_executor_stats = off +#log_statement_stats = off + + +#------------------------------------------------------------------------------ +# AUTOVACUUM +#------------------------------------------------------------------------------ + +#autovacuum = on # Enable autovacuum subprocess? 'on' + # requires track_counts to also be on. +#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and + # their durations, > 0 logs only + # actions running at least this number + # of milliseconds. +#autovacuum_max_workers = 3 # max number of autovacuum subprocesses + # (change requires restart) +#autovacuum_naptime = 1min # time between autovacuum runs +#autovacuum_vacuum_threshold = 50 # min number of row updates before + # vacuum +#autovacuum_analyze_threshold = 50 # min number of row updates before + # analyze +#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum +#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze +#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum + # (change requires restart) +#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age + # before forced vacuum + # (change requires restart) +#autovacuum_vacuum_cost_delay = 2ms # default vacuum cost delay for + # autovacuum, in milliseconds; + # -1 means use vacuum_cost_delay +#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for + # autovacuum, -1 means use + # vacuum_cost_limit + + +#------------------------------------------------------------------------------ +# CLIENT CONNECTION DEFAULTS +#------------------------------------------------------------------------------ + +# - Statement Behavior - + +#client_min_messages = notice # values in order of decreasing detail: + # debug5 + # debug4 + # debug3 + # debug2 + # debug1 + # log + # notice + # warning + # error +#search_path = '"$user", public' # schema names +#row_security = on +#default_tablespace = '' # a tablespace name, '' uses the default +#temp_tablespaces = '' # a list of tablespace names, '' uses + # only default tablespace +#default_table_access_method = 'heap' +#check_function_bodies = on +#default_transaction_isolation = 'read committed' +#default_transaction_read_only = off +#default_transaction_deferrable = off +#session_replication_role = 'origin' +#statement_timeout = 0 # in milliseconds, 0 is disabled +#lock_timeout = 0 # in milliseconds, 0 is disabled +#idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled +#vacuum_freeze_min_age = 50000000 +#vacuum_freeze_table_age = 150000000 +#vacuum_multixact_freeze_min_age = 5000000 +#vacuum_multixact_freeze_table_age = 150000000 +#vacuum_cleanup_index_scale_factor = 0.1 # fraction of total number of tuples + # before index cleanup, 0 always performs + # index cleanup +#bytea_output = 'hex' # hex, escape +#xmlbinary = 'base64' +#xmloption = 'content' +#gin_fuzzy_search_limit = 0 +#gin_pending_list_limit = 4MB + +# - Locale and Formatting - + +#datestyle = 'iso, mdy' +#intervalstyle = 'postgres' +#timezone = 'GMT' +#timezone_abbreviations = 'Default' # Select the set of available time zone + # abbreviations. Currently, there are + # Default + # Australia (historical usage) + # India + # You can create your own file in + # share/timezonesets/. +#extra_float_digits = 1 # min -15, max 3; any value >0 actually + # selects precise output mode +#client_encoding = sql_ascii # actually, defaults to database + # encoding + +# These settings are initialized by initdb, but they can be changed. +#lc_messages = 'C' # locale for system error message + # strings +#lc_monetary = 'C' # locale for monetary formatting +#lc_numeric = 'C' # locale for number formatting +#lc_time = 'C' # locale for time formatting + +# default configuration for text search +#default_text_search_config = 'pg_catalog.simple' + +# - Shared Library Preloading - + +#shared_preload_libraries = '' # (change requires restart) +#local_preload_libraries = '' +#session_preload_libraries = '' +#jit_provider = 'llvmjit' # JIT library to use + +# - Other Defaults - + +#dynamic_library_path = '$libdir' + + +#------------------------------------------------------------------------------ +# LOCK MANAGEMENT +#------------------------------------------------------------------------------ + +#deadlock_timeout = 1s +#max_locks_per_transaction = 64 # min 10 + # (change requires restart) +#max_pred_locks_per_transaction = 64 # min 10 + # (change requires restart) +#max_pred_locks_per_relation = -2 # negative values mean + # (max_pred_locks_per_transaction + # / -max_pred_locks_per_relation) - 1 +#max_pred_locks_per_page = 2 # min 0 + + +#------------------------------------------------------------------------------ +# VERSION AND PLATFORM COMPATIBILITY +#------------------------------------------------------------------------------ + +# - Previous PostgreSQL Versions - + +#array_nulls = on +#backslash_quote = safe_encoding # on, off, or safe_encoding +#escape_string_warning = on +#lo_compat_privileges = off +#operator_precedence_warning = off +#quote_all_identifiers = off +#standard_conforming_strings = on +#synchronize_seqscans = on + +# - Other Platforms and Clients - + +#transform_null_equals = off + + +#------------------------------------------------------------------------------ +# ERROR HANDLING +#------------------------------------------------------------------------------ + +#exit_on_error = off # terminate session on any error? +#restart_after_crash = on # reinitialize after backend crash? +#data_sync_retry = off # retry or panic on failure to fsync + # data? + # (change requires restart) + + +#------------------------------------------------------------------------------ +# CONFIG FILE INCLUDES +#------------------------------------------------------------------------------ + +# These options allow settings to be loaded from files other than the +# default postgresql.conf. Note that these are directives, not variable +# assignments, so they can usefully be given more than once. + +#include_dir = '...' # include files ending in '.conf' from + # a directory, e.g., 'conf.d' +#include_if_exists = '...' # include file only if it exists +#include = '...' # include file + + +#------------------------------------------------------------------------------ +# CUSTOMIZED OPTIONS +#------------------------------------------------------------------------------ + +# Add settings for extensions here diff --git a/molecule/quarkus_ha/prepare.yml b/molecule/quarkus_ha/prepare.yml new file mode 100644 index 0000000..dff1821 --- /dev/null +++ b/molecule/quarkus_ha/prepare.yml @@ -0,0 +1,44 @@ +--- +- name: Prepare + hosts: keycloak + tasks: + - name: "Display hera_home if defined." + ansible.builtin.set_fact: + hera_home: "{{ lookup('env', 'HERA_HOME') }}" + + - name: "Ensure common prepare phase are set." + ansible.builtin.include_tasks: ../prepare.yml + + - name: Create certificate request + ansible.builtin.command: "openssl req -x509 -newkey rsa:4096 -keyout {{ inventory_hostname }}.key -out {{ inventory_hostname }}.pem -sha256 -days 365 -nodes -subj '/CN={{ inventory_hostname }}'" + delegate_to: localhost + changed_when: False + + - name: Create vault directory + become: true + ansible.builtin.file: + state: directory + path: "/opt/keycloak/vault" + mode: 0755 + + - name: Make sure a jre is available (for keytool to prepare keystore) + delegate_to: localhost + ansible.builtin.package: + name: "{{ 'java-17-openjdk-headless' if hera_home | length > 0 else 'openjdk-17-jdk-headless' }}" + state: present + become: true + failed_when: false + + - name: Create vault keystore + ansible.builtin.command: keytool -importpass -alias TestRealm_testalias -keystore keystore.p12 -storepass keystorepassword + delegate_to: localhost + register: keytool_cmd + changed_when: False + failed_when: not 'already exists' in keytool_cmd.stdout and keytool_cmd.rc != 0 + + - name: Copy certificates and vault + become: true + ansible.builtin.copy: + src: keystore.p12 + dest: /opt/keycloak/vault/keystore.p12 + mode: 0444 diff --git a/molecule/quarkus_ha/roles b/molecule/quarkus_ha/roles new file mode 120000 index 0000000..b741aa3 --- /dev/null +++ b/molecule/quarkus_ha/roles @@ -0,0 +1 @@ +../../roles \ No newline at end of file diff --git a/molecule/quarkus_ha/verify.yml b/molecule/quarkus_ha/verify.yml new file mode 100644 index 0000000..dd8490f --- /dev/null +++ b/molecule/quarkus_ha/verify.yml @@ -0,0 +1,86 @@ +--- +- name: Verify + hosts: all + tasks: + - name: Populate service facts + ansible.builtin.service_facts: + + - name: Check if keycloak service started + ansible.builtin.assert: + that: + - ansible_facts.services["keycloak.service"]["state"] == "running" + - ansible_facts.services["keycloak.service"]["status"] == "enabled" + fail_msg: "Service not running" + + - name: Set internal envvar + ansible.builtin.set_fact: + hera_home: "{{ lookup('env', 'HERA_HOME') }}" + + - name: Verify openid config + when: + - hera_home is defined + - hera_home | length == 0 + block: + - name: Fetch openID config # noqa blocked_modules command-instead-of-module + ansible.builtin.shell: | + set -o pipefail + curl -H 'Host: instance' https://localhost:8443/realms/master/.well-known/openid-configuration -k | jq . + args: + executable: /bin/bash + delegate_to: localhost + register: openid_config + changed_when: False + - name: Verify endpoint URLs + ansible.builtin.assert: + that: + - (openid_config.stdout | from_json)["backchannel_authentication_endpoint"] == 'https://instance/realms/master/protocol/openid-connect/ext/ciba/auth' + - (openid_config.stdout | from_json)['issuer'] == 'https://instance/realms/master' + - (openid_config.stdout | from_json)['authorization_endpoint'] == 'https://instance/realms/master/protocol/openid-connect/auth' + - (openid_config.stdout | from_json)['token_endpoint'] == 'https://instance/realms/master/protocol/openid-connect/token' + delegate_to: localhost + + - name: Check log folder + ansible.builtin.stat: + path: /tmp/keycloak + register: keycloak_log_folder + + - name: Check that keycloak log folder exists and is a link + ansible.builtin.assert: + that: + - keycloak_log_folder.stat.exists + - not keycloak_log_folder.stat.isdir + - keycloak_log_folder.stat.islnk + fail_msg: "Service log symlink not correctly created" + + - name: Check log file + become: true + ansible.builtin.stat: + path: /tmp/keycloak/keycloak.log + register: keycloak_log_file + + - name: Check if keycloak file exists + ansible.builtin.assert: + that: + - keycloak_log_file.stat.exists + - not keycloak_log_file.stat.isdir + + - name: Check default log folder + become: yes + ansible.builtin.stat: + path: /var/log/keycloak + register: keycloak_default_log_folder + failed_when: false + + - name: Check that default keycloak log folder doesn't exist + ansible.builtin.assert: + that: + - not keycloak_default_log_folder.stat.exists + + - name: Verify vault SPI in logfile + become: true + ansible.builtin.shell: | + set -o pipefail + zgrep 'Configured KeystoreVaultProviderFactory with the keystore file' /opt/keycloak/keycloak-*/data/log/keycloak.log*zip + changed_when: false + failed_when: slurped_log.rc != 0 + register: slurped_log diff --git a/roles/keycloak_quarkus/tasks/restart/serial.yml b/roles/keycloak_quarkus/tasks/restart/serial.yml index d98dbf9..26397d3 100644 --- a/roles/keycloak_quarkus/tasks/restart/serial.yml +++ b/roles/keycloak_quarkus/tasks/restart/serial.yml @@ -1,11 +1,11 @@ --- - name: "Restart services in serial, with optional healtch check (keycloak_quarkus_restart_health_check)" throttle: 1 - loop: "{{ ansible_play_hosts }}" block: - name: "Restart and enable {{ keycloak.service_name }} service on {{ item }}" ansible.builtin.include_tasks: - file: ../restart.yml + file: restart.yml apply: delegate_to: "{{ item }}" run_once: true + loop: "{{ ansible_play_hosts }}" diff --git a/roles/keycloak_quarkus/templates/quarkus.properties.j2 b/roles/keycloak_quarkus/templates/quarkus.properties.j2 index 5689bfc..93152e8 100644 --- a/roles/keycloak_quarkus/templates/quarkus.properties.j2 +++ b/roles/keycloak_quarkus/templates/quarkus.properties.j2 @@ -1,6 +1,6 @@ {{ ansible_managed | comment }} {% if keycloak_quarkus_ha_enabled %} -{% if not rhbk_enable or keycloak_quarkus_version.split('.')[0]|int < 22 %} +{% if keycloak_quarkus_version.split('.')[0] | int < 22 %} quarkus.infinispan-client.server-list={{ keycloak_quarkus_ispn_hosts }} quarkus.infinispan-client.auth-username={{ keycloak_quarkus_ispn_user }} quarkus.infinispan-client.auth-password={{ keycloak_quarkus_ispn_pass }} From f63b20b9d40a22bafdad0ec996789e7e951b672d Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 15 May 2024 20:01:58 +0200 Subject: [PATCH 137/205] Update verify steps --- molecule/quarkus/converge.yml | 2 +- molecule/quarkus_ha/verify.yml | 61 ++-------------------------------- 2 files changed, 3 insertions(+), 60 deletions(-) diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index da0f3dc..b7430a1 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -7,7 +7,7 @@ keycloak_realm: TestRealm keycloak_quarkus_host: instance keycloak_quarkus_log: file - keycloak_quarkus_log_level: info + keycloak_quarkus_log_level: debug # needed for the verify step keycloak_quarkus_https_key_file_enabled: true keycloak_quarkus_key_file_copy_enabled: true keycloak_quarkus_key_content: "{{ lookup('file', 'key.pem') }}" diff --git a/molecule/quarkus_ha/verify.yml b/molecule/quarkus_ha/verify.yml index dd8490f..c1a2fb9 100644 --- a/molecule/quarkus_ha/verify.yml +++ b/molecule/quarkus_ha/verify.yml @@ -1,6 +1,6 @@ --- - name: Verify - hosts: all + hosts: keycloak tasks: - name: Populate service facts ansible.builtin.service_facts: @@ -16,46 +16,10 @@ ansible.builtin.set_fact: hera_home: "{{ lookup('env', 'HERA_HOME') }}" - - name: Verify openid config - when: - - hera_home is defined - - hera_home | length == 0 - block: - - name: Fetch openID config # noqa blocked_modules command-instead-of-module - ansible.builtin.shell: | - set -o pipefail - curl -H 'Host: instance' https://localhost:8443/realms/master/.well-known/openid-configuration -k | jq . - args: - executable: /bin/bash - delegate_to: localhost - register: openid_config - changed_when: False - - name: Verify endpoint URLs - ansible.builtin.assert: - that: - - (openid_config.stdout | from_json)["backchannel_authentication_endpoint"] == 'https://instance/realms/master/protocol/openid-connect/ext/ciba/auth' - - (openid_config.stdout | from_json)['issuer'] == 'https://instance/realms/master' - - (openid_config.stdout | from_json)['authorization_endpoint'] == 'https://instance/realms/master/protocol/openid-connect/auth' - - (openid_config.stdout | from_json)['token_endpoint'] == 'https://instance/realms/master/protocol/openid-connect/token' - delegate_to: localhost - - - name: Check log folder - ansible.builtin.stat: - path: /tmp/keycloak - register: keycloak_log_folder - - - name: Check that keycloak log folder exists and is a link - ansible.builtin.assert: - that: - - keycloak_log_folder.stat.exists - - not keycloak_log_folder.stat.isdir - - keycloak_log_folder.stat.islnk - fail_msg: "Service log symlink not correctly created" - - name: Check log file become: true ansible.builtin.stat: - path: /tmp/keycloak/keycloak.log + path: /var/log/keycloak/keycloak.log register: keycloak_log_file - name: Check if keycloak file exists @@ -63,24 +27,3 @@ that: - keycloak_log_file.stat.exists - not keycloak_log_file.stat.isdir - - - name: Check default log folder - become: yes - ansible.builtin.stat: - path: /var/log/keycloak - register: keycloak_default_log_folder - failed_when: false - - - name: Check that default keycloak log folder doesn't exist - ansible.builtin.assert: - that: - - not keycloak_default_log_folder.stat.exists - - - name: Verify vault SPI in logfile - become: true - ansible.builtin.shell: | - set -o pipefail - zgrep 'Configured KeystoreVaultProviderFactory with the keystore file' /opt/keycloak/keycloak-*/data/log/keycloak.log*zip - changed_when: false - failed_when: slurped_log.rc != 0 - register: slurped_log From 4b21569f3635526f6e5330e7203187d520b93e17 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 16 May 2024 11:16:20 +0200 Subject: [PATCH 138/205] parameterize health check; refactor serial_then_parallel --- roles/keycloak_quarkus/README.md | 2 ++ roles/keycloak_quarkus/defaults/main.yml | 2 ++ .../keycloak_quarkus/meta/argument_specs.yml | 8 +++++ roles/keycloak_quarkus/tasks/restart.yml | 6 ++-- .../tasks/restart/serial_then_parallel.yml | 33 +++++-------------- 5 files changed, 23 insertions(+), 28 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index a9dbea0..ce94392 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -103,6 +103,8 @@ Role Defaults |`keycloak_quarkus_systemd_wait_for_delay`| Activation delay for service systemd unit (seconds) | `10` | |`keycloak_quarkus_restart_strategy`| Strategy task file for restarting in HA (one of provided restart/['serial.yml','none.yml','serial_then_parallel.yml']) or path to file when providing custom strategy | `restart/serial.yml` | |`keycloak_quarkus_restart_health_check`| Whether to wait for successful health check after restart | `{{ keycloak_quarkus_ha_enabled }}` | +|`keycloak_quarkus_restart_health_check_delay`| Seconds to let pass before starting healch checks | `10` | +|`keycloak_quarkus_restart_health_check_reries`| Number of attempts for successful health check before failing | `25` | |`keycloak_quarkus_restart_pause`| Seconds to wait between restarts in HA strategy | `15` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index c152a20..46aca81 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -157,4 +157,6 @@ keycloak_quarkus_supported_policy_types: ['password-blacklists'] # files in restart directory (one of [ 'serial', 'none', 'serial_then_parallel' ]), or path to file when providing custom strategy keycloak_quarkus_restart_strategy: restart/serial.yml keycloak_quarkus_restart_health_check: "{{ keycloak_quarkus_ha_enabled }}" +keycloak_quarkus_restart_health_check_delay: 10 +keycloak_quarkus_restart_health_check_reries: 25 keycloak_quarkus_restart_pause: 15 diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 3e06525..57eea53 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -445,6 +445,14 @@ argument_specs: description: "Seconds to wait between restarts in HA strategy" default: 15 type: int + keycloak_quarkus_restart_health_check_delay: + description: "Seconds to let pass before starting healch checks" + default: 10 + type: 'int' + keycloak_quarkus_restart_health_check_reries: + description: "Number of attempts for successful health check before failing" + default: 25 + type: 'int' downstream: options: rhbk_version: diff --git a/roles/keycloak_quarkus/tasks/restart.yml b/roles/keycloak_quarkus/tasks/restart.yml index bcb8c1d..2a1fabd 100644 --- a/roles/keycloak_quarkus/tasks/restart.yml +++ b/roles/keycloak_quarkus/tasks/restart.yml @@ -12,9 +12,9 @@ url: "{{ keycloak.health_url }}" register: keycloak_status until: keycloak_status.status == 200 - retries: 25 - delay: 10 - when: keycloak_quarkus_restart_health_check + retries: "{{ keycloak_quarkus_restart_health_check_reries }}" + delay: "{{ keycloak_quarkus_restart_health_check_delay }}" + when: internal_force_health_check | default(keycloak_quarkus_restart_health_check) - name: Pause to give distributed ispn caches time to (re-)replicate back onto first host ansible.builtin.pause: diff --git a/roles/keycloak_quarkus/tasks/restart/serial_then_parallel.yml b/roles/keycloak_quarkus/tasks/restart/serial_then_parallel.yml index 372a302..d883ff1 100644 --- a/roles/keycloak_quarkus/tasks/restart/serial_then_parallel.yml +++ b/roles/keycloak_quarkus/tasks/restart/serial_then_parallel.yml @@ -1,31 +1,14 @@ --- - name: Verify first restarted service with health URL, then rest restart in parallel block: - - name: "Restart and enable {{ keycloak.service_name }} service on first host" - ansible.builtin.systemd: - name: "{{ keycloak.service_name }}" - enabled: true - state: restarted - daemon_reload: true - become: true - delegate_to: "{{ ansible_play_hosts | first }}" - run_once: true - - - name: "Wait until {{ keycloak.service_name }} service becomes active {{ keycloak.health_url }}" - ansible.builtin.uri: - url: "{{ keycloak.health_url }}" - register: keycloak_status - until: keycloak_status.status == 200 - retries: 25 - delay: 10 - delegate_to: "{{ ansible_play_hosts | first }}" - run_once: true - - - name: Pause to give distributed ispn caches time to (re-)replicate back onto first host - ansible.builtin.pause: - seconds: "{{ keycloak_quarkus_restart_pause }}" - when: - - keycloak_quarkus_ha_enabled + - name: "Restart and enable {{ keycloak.service_name }} service on initial host" + ansible.builtin.include_tasks: + file: restart.yml + apply: + delegate_to: "{{ ansible_play_hosts | first }}" + run_once: true + vars: + internal_force_health_check: true - name: "Restart and enable {{ keycloak.service_name }} service on other hosts" ansible.builtin.systemd: From 6f2ed4d53b9a20f5e613556bbb2136314cea6ebe Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 14 May 2024 10:41:46 +0200 Subject: [PATCH 139/205] Fix #226 - minor proxy-header enhancement --- roles/keycloak_quarkus/templates/keycloak.conf.j2 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index f55ee80..6291b38 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -69,13 +69,12 @@ cache-config-file=cache-ispn.xml {% endif %} {% endif %} -{% if keycloak_quarkus_proxy_mode is defined and keycloak_quarkus_proxy_mode != "none" %} -# Deprecated Proxy configuration -proxy={{ keycloak_quarkus_proxy_mode }} -{% endif %} {% if keycloak_quarkus_proxy_headers is defined and keycloak_quarkus_proxy_headers != "none" %} # Proxy proxy-headers={{ keycloak_quarkus_proxy_headers }} +{% elif keycloak_quarkus_proxy_mode is defined and keycloak_quarkus_proxy_mode != "none" %} +# Deprecated Proxy configuration +proxy={{ keycloak_quarkus_proxy_mode }} {% endif %} spi-sticky-session-encoder-infinispan-should-attach-route={{ keycloak_quarkus_spi_sticky_session_encoder_infinispan_should_attach_route | d(true) | lower }} From 0fd8eb52d2920e16a3db9c229b32b358b775020b Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 14 May 2024 20:05:14 +0200 Subject: [PATCH 140/205] #226: CR changes --- roles/keycloak_quarkus/tasks/prereqs.yml | 7 +++++++ roles/keycloak_quarkus/templates/keycloak.conf.j2 | 5 ++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index 220f65b..503b308 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -93,3 +93,10 @@ fail_msg: "Additional env variable definition is incorrect: `key` and `value` are mandatory." no_log: true loop: "{{ keycloak_quarkus_additional_env_vars }}" + +- name: "Validate proxy-headers" + ansible.builtin.assert: + that: + - keycloak_quarkus_proxy_headers | lower in ['', 'forwarded', 'xforwarded'] + quiet: true + fail_msg: "keycloak_quarkus_proxy_headers must be either '', 'forwarded' or 'xforwarded'" diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index 6291b38..ab4024b 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -69,9 +69,8 @@ cache-config-file=cache-ispn.xml {% endif %} {% endif %} -{% if keycloak_quarkus_proxy_headers is defined and keycloak_quarkus_proxy_headers != "none" %} -# Proxy -proxy-headers={{ keycloak_quarkus_proxy_headers }} +{% if keycloak_quarkus_proxy_headers | length > 0 %} +proxy-headers={{ keycloak_quarkus_proxy_headers | lower }} {% elif keycloak_quarkus_proxy_mode is defined and keycloak_quarkus_proxy_mode != "none" %} # Deprecated Proxy configuration proxy={{ keycloak_quarkus_proxy_mode }} From 4d31117c16555c3ac6f46f0911d6ad7c85dfdec0 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 14 May 2024 20:15:51 +0200 Subject: [PATCH 141/205] Fix RHBK version --- roles/keycloak_quarkus/meta/argument_specs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 57eea53..66cae79 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -456,7 +456,7 @@ argument_specs: downstream: options: rhbk_version: - default: "24.0.4" + default: "24.0.3" description: "Red Hat Build of Keycloak version" type: "str" rhbk_archive: From cc012767a4416a5348cea2038661dc4bb42feb38 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 14 May 2024 20:16:00 +0200 Subject: [PATCH 142/205] #226 - add deprecation warning --- roles/keycloak_quarkus/tasks/deprecations.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/roles/keycloak_quarkus/tasks/deprecations.yml b/roles/keycloak_quarkus/tasks/deprecations.yml index a81c808..556879a 100644 --- a/roles/keycloak_quarkus/tasks/deprecations.yml +++ b/roles/keycloak_quarkus/tasks/deprecations.yml @@ -34,3 +34,20 @@ - name: Flush handlers ansible.builtin.meta: flush_handlers + +# https://access.redhat.com/documentation/en-us/red_hat_build_of_keycloak/24.0/html-single/upgrading_guide/index#deprecated_literal_proxy_literal_option +- name: Check deprecation of keycloak_quarkus_proxy_mode + delegate_to: localhost + run_once: true + when: + - keycloak_quarkus_proxy_mode is defined + - keycloak_quarkus_proxy_headers is defined and keycloak_quarkus_proxy_headers | length == 0 + - keycloak_quarkus_version.split('.') | first | int >= 24 + changed_when: true + ansible.builtin.set_fact: + deprecated_variable: "keycloak_quarkus_proxy_mode" # read in deprecation handler + notify: + - print deprecation warning + +- name: Flush handlers + ansible.builtin.meta: flush_handlers From 92c24e49e7f1a1ad7e1683bb1ea3e8ac1741dbf5 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Wed, 15 May 2024 11:09:58 +0200 Subject: [PATCH 143/205] #226: add proper default value for proxy-headers --- roles/keycloak_quarkus/defaults/main.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 46aca81..a0f6fa4 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -91,7 +91,10 @@ keycloak_quarkus_hostname_strict: true # If all applications use the public URL this option should be enabled. keycloak_quarkus_hostname_strict_backchannel: false -# proxy address forwarding mode if the server is behind a reverse proxy. [none, edge, reencrypt, passthrough] +# The proxy headers that should be accepted by the server. ['', 'forwarded', 'xforwarded'] +keycloak_quarkus_proxy_headers: "" + +# deprecated: proxy address forwarding mode if the server is behind a reverse proxy. [none, edge, reencrypt, passthrough] keycloak_quarkus_proxy_mode: edge # disable xa transactions From 62cbaa35966f7edfeeeb4f76497a4b87de840f7e Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Thu, 16 May 2024 16:24:25 +0200 Subject: [PATCH 144/205] Introduce keycloak_quarkus_show_deprecation_warnings, disabled in molecule tests --- molecule/debian/converge.yml | 1 + molecule/https_revproxy/converge.yml | 3 ++- molecule/quarkus-devmode/converge.yml | 3 ++- molecule/quarkus/converge.yml | 1 + molecule/quarkus_ha/converge.yml | 1 + molecule/quarkus_upgrade/converge.yml | 1 + roles/keycloak_quarkus/README.md | 1 + roles/keycloak_quarkus/defaults/main.yml | 2 ++ roles/keycloak_quarkus/meta/argument_specs.yml | 4 ++++ roles/keycloak_quarkus/tasks/deprecations.yml | 10 +++++----- 10 files changed, 20 insertions(+), 7 deletions(-) diff --git a/molecule/debian/converge.yml b/molecule/debian/converge.yml index 17517b8..e6319b7 100644 --- a/molecule/debian/converge.yml +++ b/molecule/debian/converge.yml @@ -2,6 +2,7 @@ - name: Converge hosts: all vars: + keycloak_quarkus_show_deprecation_warnings: false keycloak_quarkus_admin_pass: "remembertochangeme" keycloak_realm: TestRealm keycloak_quarkus_log: file diff --git a/molecule/https_revproxy/converge.yml b/molecule/https_revproxy/converge.yml index b1eb7bc..b490721 100644 --- a/molecule/https_revproxy/converge.yml +++ b/molecule/https_revproxy/converge.yml @@ -1,7 +1,8 @@ --- - name: Converge hosts: all - vars: + vars: + keycloak_quarkus_show_deprecation_warnings: false keycloak_quarkus_admin_pass: "remembertochangeme" keycloak_admin_password: "remembertochangeme" keycloak_realm: TestRealm diff --git a/molecule/quarkus-devmode/converge.yml b/molecule/quarkus-devmode/converge.yml index 2a45189..2e5d351 100644 --- a/molecule/quarkus-devmode/converge.yml +++ b/molecule/quarkus-devmode/converge.yml @@ -1,7 +1,8 @@ --- - name: Converge hosts: all - vars: + vars: + keycloak_quarkus_show_deprecation_warnings: false keycloak_quarkus_admin_pass: "remembertochangeme" keycloak_admin_password: "remembertochangeme" keycloak_realm: TestRealm diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index b7430a1..7c86756 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -2,6 +2,7 @@ - name: Converge hosts: all vars: + keycloak_quarkus_show_deprecation_warnings: false keycloak_quarkus_admin_pass: "remembertochangeme" keycloak_admin_password: "remembertochangeme" keycloak_realm: TestRealm diff --git a/molecule/quarkus_ha/converge.yml b/molecule/quarkus_ha/converge.yml index 2434e65..00246b8 100644 --- a/molecule/quarkus_ha/converge.yml +++ b/molecule/quarkus_ha/converge.yml @@ -2,6 +2,7 @@ - name: Converge hosts: keycloak vars: + keycloak_quarkus_show_deprecation_warnings: false keycloak_quarkus_admin_pass: "remembertochangeme" keycloak_admin_password: "remembertochangeme" keycloak_realm: TestRealm diff --git a/molecule/quarkus_upgrade/converge.yml b/molecule/quarkus_upgrade/converge.yml index eb84589..6025b7c 100644 --- a/molecule/quarkus_upgrade/converge.yml +++ b/molecule/quarkus_upgrade/converge.yml @@ -4,6 +4,7 @@ vars_files: - vars.yml vars: + keycloak_quarkus_show_deprecation_warnings: false keycloak_quarkus_version: 24.0.3 roles: - role: keycloak_quarkus diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index ce94392..a20c760 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -167,6 +167,7 @@ Role Defaults |`keycloak_quarkus_start_dev`| Whether to start the service in development mode (start-dev) | `False` | |`keycloak_quarkus_transaction_xa_enabled`| Whether to use XA transactions | `True` | |`keycloak_quarkus_spi_sticky_session_encoder_infinispan_should_attach_route`| If the route should be attached to cookies to reflect the node that owns a particular session. If false, route is not attached to cookies and we rely on the session affinity capabilities from reverse proxy | `True` | +|`keycloak_quarkus_show_deprecation_warnings`| Whether deprecation warnings should be shown | `True` | #### Vault SPI diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index a0f6fa4..b3752c5 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -8,6 +8,8 @@ keycloak_quarkus_installdir: "{{ keycloak_quarkus_dest }}/keycloak-{{ keycloak_q # whether to install from local archive keycloak_quarkus_offline_install: false +keycloak_quarkus_show_deprecation_warnings: true + ### Install location and service settings keycloak_quarkus_java_home: keycloak_quarkus_dest: /opt/keycloak diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 66cae79..659e7f6 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -483,6 +483,10 @@ argument_specs: default: false description: "Perform an offline install" type: "bool" + keycloak_quarkus_show_deprecation_warnings: + default: true + description: "Whether deprecation warnings should be shown" + type: "bool" rhbk_service_name: default: "rhbk" description: "systemd service name for Red Hat Build of Keycloak" diff --git a/roles/keycloak_quarkus/tasks/deprecations.yml b/roles/keycloak_quarkus/tasks/deprecations.yml index 556879a..27ea6e3 100644 --- a/roles/keycloak_quarkus/tasks/deprecations.yml +++ b/roles/keycloak_quarkus/tasks/deprecations.yml @@ -10,7 +10,7 @@ - keycloak_quarkus_key_store_file is defined - keycloak_quarkus_key_store_file != '' - keycloak_quarkus_https_key_store_file == keycloak.home + "/conf/key_store.p12" # default value - changed_when: true + changed_when: keycloak_quarkus_show_deprecation_warnings ansible.builtin.set_fact: keycloak_quarkus_https_key_store_file: "{{ keycloak_quarkus_key_store_file }}" deprecated_variable: "keycloak_quarkus_key_store_file" # read in deprecation handler @@ -25,7 +25,7 @@ - keycloak_quarkus_key_store_password is defined - keycloak_quarkus_key_store_password != '' - keycloak_quarkus_https_key_store_password == "" # default value - changed_when: true + changed_when: keycloak_quarkus_show_deprecation_warnings ansible.builtin.set_fact: keycloak_quarkus_https_key_store_password: "{{ keycloak_quarkus_key_store_password }}" deprecated_variable: "keycloak_quarkus_key_store_password" # read in deprecation handler @@ -37,13 +37,13 @@ # https://access.redhat.com/documentation/en-us/red_hat_build_of_keycloak/24.0/html-single/upgrading_guide/index#deprecated_literal_proxy_literal_option - name: Check deprecation of keycloak_quarkus_proxy_mode - delegate_to: localhost - run_once: true when: - keycloak_quarkus_proxy_mode is defined - keycloak_quarkus_proxy_headers is defined and keycloak_quarkus_proxy_headers | length == 0 - keycloak_quarkus_version.split('.') | first | int >= 24 - changed_when: true + delegate_to: localhost + run_once: true + changed_when: keycloak_quarkus_show_deprecation_warnings ansible.builtin.set_fact: deprecated_variable: "keycloak_quarkus_proxy_mode" # read in deprecation handler notify: From df1939e387f6028b88faee6227be6a87d27c8ce6 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Mon, 20 May 2024 10:21:55 +0000 Subject: [PATCH 145/205] Update changelog for release 2.3.0 Signed-off-by: ansible-middleware-core --- CHANGELOG.rst | 23 +++++++++++++++++++++++ changelogs/changelog.yaml | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3d0f005..f139898 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,29 @@ middleware\_automation.keycloak Release Notes This changelog describes changes after version 0.2.6. +v2.3.0 +====== + +Major Changes +------------- + +- Allow for custom providers hosted on maven repositories `#223 `_ +- Restart handler strategy behaviour `#231 `_ + +Minor Changes +------------- + +- Add support for policy files `#225 `_ +- Allow to add extra custom env vars in sysconfig file `#229 `_ +- Download from alternate URL with optional http authentication `#220 `_ +- Update Keycloak to version 24.0.4 `#218 `_ +- ``proxy-header`` enhancement `#227 `_ + +Bugfixes +-------- + +- ``kc.sh build`` uses configured jdk `#211 `_ + v2.2.2 ====== diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index fe5c499..773f77d 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -532,3 +532,42 @@ releases: - 209.yaml - 210.yaml release_date: '2024-05-06' + 2.3.0: + changes: + bugfixes: + - '``kc.sh build`` uses configured jdk `#211 `_ + + ' + major_changes: + - 'Allow for custom providers hosted on maven repositories `#223 `_ + + ' + - 'Restart handler strategy behaviour `#231 `_ + + ' + minor_changes: + - 'Add support for policy files `#225 `_ + + ' + - 'Allow to add extra custom env vars in sysconfig file `#229 `_ + + ' + - 'Download from alternate URL with optional http authentication `#220 `_ + + ' + - 'Update Keycloak to version 24.0.4 `#218 `_ + + ' + - '``proxy-header`` enhancement `#227 `_ + + ' + fragments: + - 211.yaml + - 218.yaml + - 220.yaml + - 223.yaml + - 225.yaml + - 227.yaml + - 229.yaml + - 231.yaml + release_date: '2024-05-20' From 8ca73364e98e283e5b798d4381d75967386d77c4 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Mon, 20 May 2024 10:22:09 +0000 Subject: [PATCH 146/205] Bump version to 2.3.1 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index da8794c..1a4d35a 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.3.0" +version: "2.3.1" readme: README.md authors: - Romain Pelisse From 2092c2d23a2c028149d314205735a8970b713fd8 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 21 May 2024 12:27:45 +0200 Subject: [PATCH 147/205] Update minimum ansible-core version > 2.15 --- README.md | 2 +- meta/runtime.yml | 2 +- roles/keycloak/meta/main.yml | 2 +- roles/keycloak_quarkus/meta/main.yml | 2 +- roles/keycloak_realm/meta/main.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0cd3ba0..e71a8f6 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Collection to install and configure [Keycloak](https://www.keycloak.org/) or [Re ## Ansible version compatibility -This collection has been tested against following Ansible versions: **>=2.14.0**. +This collection has been tested against following Ansible versions: **>=2.15.0**. Plugins and modules within a collection may be tested with only specific Ansible versions. A collection may contain metadata that identifies these versions. diff --git a/meta/runtime.yml b/meta/runtime.yml index ce6befd..1e85b01 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -1,2 +1,2 @@ --- -requires_ansible: ">=2.14.0" +requires_ansible: ">=2.15.0" diff --git a/roles/keycloak/meta/main.yml b/roles/keycloak/meta/main.yml index a70e9f1..a27afb8 100644 --- a/roles/keycloak/meta/main.yml +++ b/roles/keycloak/meta/main.yml @@ -12,7 +12,7 @@ galaxy_info: license: Apache License 2.0 - min_ansible_version: "2.14" + min_ansible_version: "2.15" platforms: - name: EL diff --git a/roles/keycloak_quarkus/meta/main.yml b/roles/keycloak_quarkus/meta/main.yml index 0f82003..40a487f 100644 --- a/roles/keycloak_quarkus/meta/main.yml +++ b/roles/keycloak_quarkus/meta/main.yml @@ -8,7 +8,7 @@ galaxy_info: license: Apache License 2.0 - min_ansible_version: "2.14" + min_ansible_version: "2.15" platforms: - name: EL diff --git a/roles/keycloak_realm/meta/main.yml b/roles/keycloak_realm/meta/main.yml index 915f62c..ab861ed 100644 --- a/roles/keycloak_realm/meta/main.yml +++ b/roles/keycloak_realm/meta/main.yml @@ -8,7 +8,7 @@ galaxy_info: license: Apache License 2.0 - min_ansible_version: "2.14" + min_ansible_version: "2.15" platforms: - name: EL From ef53ca545af031cb662cb143caf9e288e7fafbb7 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 21 May 2024 12:31:40 +0200 Subject: [PATCH 148/205] update yamllint --- .yamllint | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.yamllint b/.yamllint index fa1f1fc..10e554e 100644 --- a/.yamllint +++ b/.yamllint @@ -15,7 +15,8 @@ rules: commas: max-spaces-after: -1 level: error - comments: disable + comments: + min-spaces-from-content: 1 comments-indentation: disable document-start: disable empty-lines: @@ -30,4 +31,8 @@ rules: new-lines: type: unix trailing-spaces: disable - truthy: disable \ No newline at end of file + truthy: disable + octal-values: + forbid-implicit-octal: true + forbid-explicit-octal: true + From adfee5f6e1e4767fe6fbf70d3431322409491798 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 21 May 2024 12:34:11 +0200 Subject: [PATCH 149/205] ci --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0927320..3d71b46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,7 @@ on: branches: - main pull_request: + workflow_dispatch: schedule: - cron: '15 6 * * *' From bf1871182b3ce806991278a1efbc99d1e72b387a Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 21 May 2024 12:35:33 +0200 Subject: [PATCH 150/205] linter --- roles/keycloak/tasks/fastpackages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/keycloak/tasks/fastpackages.yml b/roles/keycloak/tasks/fastpackages.yml index be34c72..a89f7f6 100644 --- a/roles/keycloak/tasks/fastpackages.yml +++ b/roles/keycloak/tasks/fastpackages.yml @@ -14,7 +14,7 @@ - name: "Install packages: {{ packages_to_install }}" become: true - ansible.builtin.yum: + ansible.builtin.dnf: name: "{{ packages_to_install }}" state: present when: From e69e5b7ba4086d5ad0dda3529e2f239669e76392 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 21 May 2024 12:41:31 +0200 Subject: [PATCH 151/205] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e71a8f6..c5ee5cf 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ ansible-playbook -i -e @rhn-creds.yml playbooks/keycloak.yml -e localhost ansible_connection=local ``` -Note: when deploying clustered configurations, all hosts belonging to the cluster must be present in ansible_play_batch; ie. they must be targeted by the same ansible-playbook execution. +Note: when deploying clustered configurations, all hosts belonging to the cluster must be present in `ansible_play_batch`; ie. they must be targeted by the same ansible-playbook execution. ## Configuration From 4fb44091d6504a669592ce22ea23ebbedeeefa10 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 30 May 2024 08:44:04 +0200 Subject: [PATCH 152/205] ci: fix missing symlink --- molecule/quarkus_upgrade/roles | 1 + 1 file changed, 1 insertion(+) create mode 120000 molecule/quarkus_upgrade/roles diff --git a/molecule/quarkus_upgrade/roles b/molecule/quarkus_upgrade/roles new file mode 120000 index 0000000..b741aa3 --- /dev/null +++ b/molecule/quarkus_upgrade/roles @@ -0,0 +1 @@ +../../roles \ No newline at end of file From a4deaa005a374fc599eae658740fd4ff4120c3fe Mon Sep 17 00:00:00 2001 From: Giovanni Toraldo Date: Tue, 4 Jun 2024 17:00:11 +0200 Subject: [PATCH 153/205] Enable by default health check on restart --- roles/keycloak_quarkus/README.md | 2 +- roles/keycloak_quarkus/defaults/main.yml | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index a20c760..a166725 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -102,7 +102,7 @@ Role Defaults |`keycloak_quarkus_systemd_wait_for_timeout`| How long to wait for service to be alive (seconds) | `60` | |`keycloak_quarkus_systemd_wait_for_delay`| Activation delay for service systemd unit (seconds) | `10` | |`keycloak_quarkus_restart_strategy`| Strategy task file for restarting in HA (one of provided restart/['serial.yml','none.yml','serial_then_parallel.yml']) or path to file when providing custom strategy | `restart/serial.yml` | -|`keycloak_quarkus_restart_health_check`| Whether to wait for successful health check after restart | `{{ keycloak_quarkus_ha_enabled }}` | +|`keycloak_quarkus_restart_health_check`| Whether to wait for successful health check after restart | `true` | |`keycloak_quarkus_restart_health_check_delay`| Seconds to let pass before starting healch checks | `10` | |`keycloak_quarkus_restart_health_check_reries`| Number of attempts for successful health check before failing | `25` | |`keycloak_quarkus_restart_pause`| Seconds to wait between restarts in HA strategy | `15` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index b3752c5..4f6deb3 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -161,7 +161,7 @@ keycloak_quarkus_supported_policy_types: ['password-blacklists'] # files in restart directory (one of [ 'serial', 'none', 'serial_then_parallel' ]), or path to file when providing custom strategy keycloak_quarkus_restart_strategy: restart/serial.yml -keycloak_quarkus_restart_health_check: "{{ keycloak_quarkus_ha_enabled }}" +keycloak_quarkus_restart_health_check: true keycloak_quarkus_restart_health_check_delay: 10 keycloak_quarkus_restart_health_check_reries: 25 keycloak_quarkus_restart_pause: 15 diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 659e7f6..978ca7e 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -432,7 +432,7 @@ argument_specs: description: "Allow the option to ignore invalid certificates when downloading JDBC drivers from a custom URL" type: "bool" keycloak_quarkus_restart_health_check: - default: "{{ keycloak_quarkus_ha_enabled }}" + default: true description: "Whether to wait for successful health check after restart" type: "bool" keycloak_quarkus_restart_strategy: From a82bdfbbb6a079e96b013479955b8b5cf612de19 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 4 Jun 2024 17:36:20 +0200 Subject: [PATCH 154/205] Bump to 2.4.0 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index 1a4d35a..c64908f 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.3.1" +version: "2.4.0" readme: README.md authors: - Romain Pelisse From e927ddbb6caa3ddd0fba30b9fdd68b6510c5f710 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Tue, 4 Jun 2024 15:44:20 +0000 Subject: [PATCH 155/205] Update changelog for release 2.4.0 Signed-off-by: ansible-middleware-core --- CHANGELOG.rst | 9 +++++++++ changelogs/changelog.yaml | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f139898..d8fbfdd 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,15 @@ middleware\_automation.keycloak Release Notes This changelog describes changes after version 0.2.6. +v2.4.0 +====== + +Major Changes +------------- + +- Enable by default health check on restart `#234 `_ +- Update minimum ansible-core version > 2.15 `#232 `_ + v2.3.0 ====== diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 773f77d..e5de562 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -571,3 +571,16 @@ releases: - 229.yaml - 231.yaml release_date: '2024-05-20' + 2.4.0: + changes: + major_changes: + - 'Enable by default health check on restart `#234 `_ + + ' + - 'Update minimum ansible-core version > 2.15 `#232 `_ + + ' + fragments: + - 232.yaml + - 234.yaml + release_date: '2024-06-04' From 5f059e8d63b8e5e04d957951a4820a4ff90cb901 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Tue, 4 Jun 2024 15:44:35 +0000 Subject: [PATCH 156/205] Bump version to 2.4.1 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index c64908f..7ff57c6 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.4.0" +version: "2.4.1" readme: README.md authors: - Romain Pelisse From c6fac7bb70932f6ea852483f86deea8a3f9b3d36 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 27 Jun 2024 11:00:29 +0200 Subject: [PATCH 157/205] ci: add traffic wf --- .github/workflows/traffic.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/traffic.yml diff --git a/.github/workflows/traffic.yml b/.github/workflows/traffic.yml new file mode 100644 index 0000000..6b0dde7 --- /dev/null +++ b/.github/workflows/traffic.yml @@ -0,0 +1,24 @@ +on: + schedule: + - cron: "51 23 * * 0" + +jobs: + traffic: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + ref: "traffic" + + - name: GitHub traffic + uses: sangonzal/repository-traffic-action@v.0.1.6 + env: + TRAFFIC_ACTION_TOKEN: ${{ secrets.TRIGGERING_PAT }} + + - name: Commit changes + uses: EndBug/add-and-commit@v4 + with: + author_name: Ansible Middleware + message: "GitHub traffic" + add: "./traffic/*" + ref: "traffic" From 64e2a95685459155f1b2fcb3a9314ba1c9bf245b Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 27 Jun 2024 11:01:38 +0200 Subject: [PATCH 158/205] ci: add traffic wf --- .github/workflows/traffic.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/traffic.yml b/.github/workflows/traffic.yml index 6b0dde7..1d85eac 100644 --- a/.github/workflows/traffic.yml +++ b/.github/workflows/traffic.yml @@ -1,6 +1,8 @@ +name: Collect traffic stats on: schedule: - cron: "51 23 * * 0" + workflow_dispatch: jobs: traffic: From e40f5549367e124103863db08d18f8edb389854d Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 27 Jun 2024 11:02:32 +0200 Subject: [PATCH 159/205] ci: add traffic wf --- .github/workflows/traffic.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/traffic.yml b/.github/workflows/traffic.yml index 1d85eac..b4f245e 100644 --- a/.github/workflows/traffic.yml +++ b/.github/workflows/traffic.yml @@ -10,7 +10,7 @@ jobs: steps: - uses: actions/checkout@v2 with: - ref: "traffic" + ref: "gh-pages" - name: GitHub traffic uses: sangonzal/repository-traffic-action@v.0.1.6 @@ -23,4 +23,4 @@ jobs: author_name: Ansible Middleware message: "GitHub traffic" add: "./traffic/*" - ref: "traffic" + ref: "gh-pages" From 94f1b8b35589edd75667188115afec8a35b2c787 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 2 Jul 2024 15:46:05 +0200 Subject: [PATCH 160/205] ci: update README --- README.md | 4 +++- roles/keycloak_quarkus/README.md | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c5ee5cf..3827b90 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ > **_NOTE:_ If you are Red Hat customer, install `redhat.sso` (for Red Hat Single Sign-On) or `redhat.rhbk` (for Red Hat Build of Keycloak) from [Automation Hub](https://console.redhat.com/ansible/ansible-dashboard) as the certified version of this collection.** + Collection to install and configure [Keycloak](https://www.keycloak.org/) or [Red Hat Single Sign-On](https://access.redhat.com/products/red-hat-single-sign-on) / [Red Hat Build of Keycloak](https://access.redhat.com/products/red-hat-build-of-keycloak). - + ## Ansible version compatibility @@ -39,6 +40,7 @@ collections: The keycloak collection also depends on the following python packages to be present on the controller host: * netaddr +* lxml A requirement file is provided to install: diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index a166725..1fb0cd1 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -1,8 +1,8 @@ keycloak_quarkus ================ - + Install [keycloak](https://keycloak.org/) >= 20.0.0 (quarkus) server configurations. - + Requirements ------------ From 35b3b090f61ff54687138496080f98260f98c548 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 2 Jul 2024 15:59:16 +0200 Subject: [PATCH 161/205] ci: update READMEs --- roles/keycloak_realm/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/roles/keycloak_realm/README.md b/roles/keycloak_realm/README.md index 73d823f..d6ce30c 100644 --- a/roles/keycloak_realm/README.md +++ b/roles/keycloak_realm/README.md @@ -1,8 +1,9 @@ keycloak_realm ============== + Create realms and clients in [keycloak](https://keycloak.org/) or [Red Hat Single Sign-On](https://access.redhat.com/products/red-hat-single-sign-on) services. - + Role Defaults ------------- @@ -136,4 +137,4 @@ Author Information ------------------ * [Guido Grazioli](https://github.com/guidograzioli) -* [Romain Pelisse](https://github.com/rpelisse) \ No newline at end of file +* [Romain Pelisse](https://github.com/rpelisse) From 7c520dcdd2f4a424a52a5d8bc6522f17f707b41b Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Tue, 2 Jul 2024 14:23:37 +0000 Subject: [PATCH 162/205] Update changelog for release 2.4.1 Signed-off-by: ansible-middleware-core --- CHANGELOG.rst | 8 ++++++++ changelogs/changelog.yaml | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d8fbfdd..1aed396 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,14 @@ middleware\_automation.keycloak Release Notes This changelog describes changes after version 0.2.6. +v2.4.1 +====== + +Release Summary +--------------- + +Internal release, documentation or test changes only. + v2.4.0 ====== diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index e5de562..c841535 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -584,3 +584,9 @@ releases: - 232.yaml - 234.yaml release_date: '2024-06-04' + 2.4.1: + changes: + release_summary: Internal release, documentation or test changes only. + fragments: + - v2.4.1-devel_summary.yaml + release_date: '2024-07-02' From fa2319d5da0922a5161d8475b17b0c2c0d0457a8 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Tue, 2 Jul 2024 14:23:53 +0000 Subject: [PATCH 163/205] Bump version to 2.4.2 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index 7ff57c6..2091f28 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.4.1" +version: "2.4.2" readme: README.md authors: - Romain Pelisse From 11aab0f5e2bc68f7b895de3f10e4a39e67639ed1 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 18 Jul 2024 12:53:49 +0200 Subject: [PATCH 164/205] add verify steps for quarkus/keycloak_realm --- molecule/quarkus/verify.yml | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/molecule/quarkus/verify.yml b/molecule/quarkus/verify.yml index dd8490f..24c27aa 100644 --- a/molecule/quarkus/verify.yml +++ b/molecule/quarkus/verify.yml @@ -1,6 +1,8 @@ --- - name: Verify hosts: all + vars: + keycloak_admin_password: "remembertochangeme" tasks: - name: Populate service facts ansible.builtin.service_facts: @@ -84,3 +86,42 @@ changed_when: false failed_when: slurped_log.rc != 0 register: slurped_log + + - name: Verify token api call + ansible.builtin.uri: + url: "https://localhost:8443/realms/master/protocol/openid-connect/token" + method: POST + body: "client_id=admin-cli&username=admin&password={{ keycloak_admin_password }}&grant_type=password" + validate_certs: no + register: keycloak_auth_response + until: keycloak_auth_response.status == 200 + retries: 2 + delay: 2 + + - name: "Get Clients" + ansible.builtin.uri: + url: "https://localhost:8443/admin/realms/TestRealm/clients" + headers: + validate_certs: false + Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" + register: keycloak_clients + + - name: Get client uuid + ansible.builtin.set_fact: + keycloak_client_uuid: "{{ ((keycloak_clients.json | selectattr('clientId', '==', 'TestClient')) | first).id }}" + + - name: "Get Client {{ keycloak_client_uuid }}" + ansible.builtin.uri: + url: "https://localhost:8443/admin/realms/TestRealm/clients/{{ keycloak_client_uuid }}" + headers: + validate_certs: false + Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" + register: keycloak_test_client + + - name: "Get Client roles" + ansible.builtin.uri: + url: "https://localhost:8443/admin/realms/TestRealm/clients/{{ keycloak_client_uuid }}/roles" + headers: + validate_certs: false + Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" + register: keycloak_test_client_roles \ No newline at end of file From a35c963a65c0a61ff7a2c65b13ee4e23baa894e4 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 18 Jul 2024 13:01:01 +0200 Subject: [PATCH 165/205] add verify steps for quarkus/keycloak_realm --- molecule/quarkus/verify.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/molecule/quarkus/verify.yml b/molecule/quarkus/verify.yml index 24c27aa..63769dc 100644 --- a/molecule/quarkus/verify.yml +++ b/molecule/quarkus/verify.yml @@ -89,7 +89,7 @@ - name: Verify token api call ansible.builtin.uri: - url: "https://localhost:8443/realms/master/protocol/openid-connect/token" + url: "https://instance:8443/realms/master/protocol/openid-connect/token" method: POST body: "client_id=admin-cli&username=admin&password={{ keycloak_admin_password }}&grant_type=password" validate_certs: no @@ -100,7 +100,7 @@ - name: "Get Clients" ansible.builtin.uri: - url: "https://localhost:8443/admin/realms/TestRealm/clients" + url: "https://instance:8443/admin/realms/TestRealm/clients" headers: validate_certs: false Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" @@ -112,7 +112,7 @@ - name: "Get Client {{ keycloak_client_uuid }}" ansible.builtin.uri: - url: "https://localhost:8443/admin/realms/TestRealm/clients/{{ keycloak_client_uuid }}" + url: "https://instance:8443/admin/realms/TestRealm/clients/{{ keycloak_client_uuid }}" headers: validate_certs: false Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" @@ -120,7 +120,7 @@ - name: "Get Client roles" ansible.builtin.uri: - url: "https://localhost:8443/admin/realms/TestRealm/clients/{{ keycloak_client_uuid }}/roles" + url: "https://instance:8443/admin/realms/TestRealm/clients/{{ keycloak_client_uuid }}/roles" headers: validate_certs: false Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" From 34caf6a490e3762f2d6864c00683594ae89f9ecc Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 31 Jul 2024 17:18:30 +0200 Subject: [PATCH 166/205] add wait_for_port number parameter --- roles/keycloak_quarkus/README.md | 1 + roles/keycloak_quarkus/defaults/main.yml | 1 + roles/keycloak_quarkus/meta/argument_specs.yml | 4 ++++ roles/keycloak_quarkus/templates/keycloak.service.j2 | 2 +- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 1fb0cd1..01163cd 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -98,6 +98,7 @@ Role Defaults |`keycloak_quarkus_db_enabled`| Enable auto configuration for database backend | `True` if `keycloak_quarkus_ha_enabled` is True, else `False` | |`keycloak_quarkus_jgroups_port`| jgroups cluster tcp port | `7800` | |`keycloak_quarkus_systemd_wait_for_port` | Whether systemd unit should wait for keycloak port before returning | `{{ keycloak_quarkus_ha_enabled }}` | +|`keycloak_quarkus_systemd_wait_for_port_number`| Which port the systemd unit should wait for | `{{ keycloak_quarkus_https_port }}` | |`keycloak_quarkus_systemd_wait_for_log` | Whether systemd unit should wait for service to be up in logs | `false` | |`keycloak_quarkus_systemd_wait_for_timeout`| How long to wait for service to be alive (seconds) | `60` | |`keycloak_quarkus_systemd_wait_for_delay`| Activation delay for service systemd unit (seconds) | `10` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 4f6deb3..f99e9ff 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -74,6 +74,7 @@ keycloak_quarkus_ha_discovery: "TCPPING" ### Enable database configuration, must be enabled when HA is configured keycloak_quarkus_db_enabled: "{{ keycloak_quarkus_ha_enabled }}" keycloak_quarkus_systemd_wait_for_port: "{{ keycloak_quarkus_ha_enabled }}" +keycloak_quarkus_systemd_wait_for_port_number: "{{ keycloak_quarkus_https_port }}" keycloak_quarkus_systemd_wait_for_log: false keycloak_quarkus_systemd_wait_for_timeout: 60 keycloak_quarkus_systemd_wait_for_delay: 10 diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 978ca7e..2c68460 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -386,6 +386,10 @@ argument_specs: description: 'Whether systemd unit should wait for keycloak port before returning' default: "{{ keycloak_quarkus_ha_enabled }}" type: "bool" + keycloak_quarkus_systemd_wait_for_port_number: + default: "{{ keycloak_quarkus_https_port }}" + description: "The port the systemd unit should wait for, by default the https port" + type: "int" keycloak_quarkus_systemd_wait_for_log: description: 'Whether systemd unit should wait for service to be up in logs' default: false diff --git a/roles/keycloak_quarkus/templates/keycloak.service.j2 b/roles/keycloak_quarkus/templates/keycloak.service.j2 index 9cabb69..96207ed 100644 --- a/roles/keycloak_quarkus/templates/keycloak.service.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.service.j2 @@ -23,7 +23,7 @@ RestartSec={{ keycloak_quarkus_service_restartsec }} AmbientCapabilities=CAP_NET_BIND_SERVICE {% endif %} {% if keycloak_quarkus_systemd_wait_for_port %} -ExecStartPost=/usr/bin/timeout {{ keycloak_quarkus_systemd_wait_for_timeout }} sh -c 'while ! ss -H -t -l -n sport = :{{ keycloak_quarkus_https_port }} | grep -q "^LISTEN.*:{{ keycloak_quarkus_https_port }}"; do sleep 1; done && /bin/sleep {{ keycloak_quarkus_systemd_wait_for_delay }}' +ExecStartPost=/usr/bin/timeout {{ keycloak_quarkus_systemd_wait_for_timeout }} sh -c 'while ! ss -H -t -l -n sport = :{{ keycloak_quarkus_systemd_wait_for_port_number }} | grep -q "^LISTEN.*:{{ keycloak_quarkus_systemd_wait_for_port_number }}"; do sleep 1; done && /bin/sleep {{ keycloak_quarkus_systemd_wait_for_delay }}' {% endif %} {% if keycloak_quarkus_systemd_wait_for_log %} ExecStartPost=/usr/bin/timeout {{ keycloak_quarkus_systemd_wait_for_timeout }} sh -c 'cat {{ keycloak.log.file }} | sed "/Profile.*activated/ q" && /bin/sleep {{ keycloak_quarkus_systemd_wait_for_delay }}' From f1702572059585bb97537deaa6a1096230314055 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 24 Sep 2024 09:21:10 +0200 Subject: [PATCH 167/205] Add local download path --- .ansible-lint | 1 + roles/keycloak_quarkus/README.md | 1 + roles/keycloak_quarkus/defaults/main.yml | 1 + roles/keycloak_quarkus/handlers/main.yml | 2 +- .../keycloak_quarkus/meta/argument_specs.yml | 18 ++++---- roles/keycloak_quarkus/tasks/bootstrapped.yml | 4 +- roles/keycloak_quarkus/tasks/config_store.yml | 6 +-- roles/keycloak_quarkus/tasks/install.yml | 13 ++---- roles/keycloak_quarkus/tasks/main.yml | 2 +- roles/keycloak_quarkus/tasks/prereqs.yml | 42 ++++++++++++++++++- .../keycloak_quarkus/tasks/rebuild_config.yml | 2 +- roles/keycloak_quarkus/tasks/restart.yml | 2 +- 12 files changed, 67 insertions(+), 27 deletions(-) diff --git a/.ansible-lint b/.ansible-lint index 9c2702e..e6607a4 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -34,6 +34,7 @@ warn_list: skip_list: - vars_should_not_be_used - file_is_small_enough + - file_has_valid_name - name[template] - var-naming[no-role-prefix] diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 01163cd..00c785f 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -37,6 +37,7 @@ Role Defaults |`keycloak_quarkus_offline_install` | Perform an offline install | `False`| |`keycloak_quarkus_dest`| Installation root path | `/opt/keycloak` | |`keycloak_quarkus_download_url` | Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}` | +|`keycloak_quarkus_download_path`| Path local to controller for offline/download of install archives | `{{ lookup('env', 'PWD') }}` | #### Service configuration diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index f99e9ff..b029fee 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -15,6 +15,7 @@ keycloak_quarkus_java_home: keycloak_quarkus_dest: /opt/keycloak keycloak_quarkus_home: "{{ keycloak_quarkus_installdir }}" keycloak_quarkus_config_dir: "{{ keycloak_quarkus_home }}/conf" +keycloak_quarkus_download_path: "{{ lookup('env', 'PWD') }}" keycloak_quarkus_start_dev: false keycloak_quarkus_service_user: keycloak keycloak_quarkus_service_group: keycloak diff --git a/roles/keycloak_quarkus/handlers/main.yml b/roles/keycloak_quarkus/handlers/main.yml index 5851a71..37d65c5 100644 --- a/roles/keycloak_quarkus/handlers/main.yml +++ b/roles/keycloak_quarkus/handlers/main.yml @@ -10,7 +10,7 @@ ansible.builtin.include_tasks: file: "{{ keycloak_quarkus_restart_strategy if keycloak_quarkus_ha_enabled else 'restart.yml' }}" listen: "restart keycloak" -- name: "Print deprecation warning" +- name: "Display deprecation warning" ansible.builtin.fail: msg: "Deprecation warning: you are using the deprecated variable '{{ deprecated_variable | d('NotSet') }}', check docs on how to upgrade." failed_when: false diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 2c68460..34ec365 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -56,15 +56,15 @@ argument_specs: default: false description: "Ensure firewalld is running and configure keycloak ports" type: "bool" - keycloak_service_restart_always: + keycloak_quarkus_service_restart_always: default: false description: "systemd restart always behavior of service; takes precedence over keycloak_service_restart_on_failure if true" type: "bool" - keycloak_service_restart_on_failure: + keycloak_quarkus_service_restart_on_failure: default: false description: "systemd restart on-failure behavior of service" type: "bool" - keycloak_service_restartsec: + keycloak_quarkus_service_restartsec: default: "10s" description: "systemd RestartSec for service" type: "str" @@ -457,6 +457,14 @@ argument_specs: description: "Number of attempts for successful health check before failing" default: 25 type: 'int' + keycloak_quarkus_show_deprecation_warnings: + default: true + description: "Whether or not deprecation warnings should be shown" + type: "bool" + keycloak_quarkus_download_path: + description: "Path local to controller for offline/download of install archives" + default: "{{ lookup('env', 'PWD') }}" + type: "str" downstream: options: rhbk_version: @@ -487,10 +495,6 @@ argument_specs: default: false description: "Perform an offline install" type: "bool" - keycloak_quarkus_show_deprecation_warnings: - default: true - description: "Whether deprecation warnings should be shown" - type: "bool" rhbk_service_name: default: "rhbk" description: "systemd service name for Red Hat Build of Keycloak" diff --git a/roles/keycloak_quarkus/tasks/bootstrapped.yml b/roles/keycloak_quarkus/tasks/bootstrapped.yml index 46278ab..3cbc5c4 100644 --- a/roles/keycloak_quarkus/tasks/bootstrapped.yml +++ b/roles/keycloak_quarkus/tasks/bootstrapped.yml @@ -1,5 +1,5 @@ --- -- name: Write ansible custom facts +- name: Save ansible custom facts become: true ansible.builtin.template: src: keycloak.fact.j2 @@ -8,7 +8,7 @@ vars: bootstrapped: true -- name: Re-read custom facts +- name: Refresh custom facts ansible.builtin.setup: filter: ansible_local diff --git a/roles/keycloak_quarkus/tasks/config_store.yml b/roles/keycloak_quarkus/tasks/config_store.yml index 40acc65..2d8b39e 100644 --- a/roles/keycloak_quarkus/tasks/config_store.yml +++ b/roles/keycloak_quarkus/tasks/config_store.yml @@ -8,7 +8,7 @@ - name: "Initialize empty configuration key store" become: true # keytool doesn't allow creating an empty key store, so this is a hacky way around it - ansible.builtin.shell: | + ansible.builtin.shell: | # noqa blocked_modules shell is necessary here set -o nounset # abort on unbound variable set -o pipefail # do not hide errors within pipes set -o errexit # abort on nonzero exit status @@ -19,7 +19,7 @@ creates: "{{ keycloak_quarkus_config_key_store_file }}" - name: "Set configuration key store using keytool" - ansible.builtin.shell: | + ansible.builtin.shell: | # noqa blocked_modules shell is necessary here set -o nounset # abort on unbound variable set -o pipefail # do not hide errors within pipes @@ -36,7 +36,7 @@ fi echo {{ item.value | quote }} | keytool -noprompt -importpass -alias {{ item.key | quote }} -keystore {{ keycloak_quarkus_config_key_store_file | quote }} -storepass {{ keycloak_quarkus_config_key_store_password | quote }} -storetype PKCS12 - with_items: "{{ store_items }}" + loop: "{{ store_items }}" no_log: true become: true changed_when: true diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index 7745031..809e07e 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -8,6 +8,7 @@ - keycloak_quarkus_archive is defined - keycloak_quarkus_download_url is defined - keycloak_quarkus_version is defined + - local_path is defined quiet: true - name: Check for an existing deployment @@ -52,14 +53,6 @@ register: archive_path ## download to controller -- name: Check local download archive path - ansible.builtin.stat: - path: "{{ lookup('env', 'PWD') }}" - register: local_path - delegate_to: localhost - run_once: true - become: false - - name: Download keycloak archive ansible.builtin.get_url: # noqa risky-file-permissions delegated, uses controller host user url: "{{ keycloak_quarkus_download_url }}" @@ -244,7 +237,7 @@ no_log: "{{ item.maven.password is defined and item.maven.password | length > 0 | default(false) }}" notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or not item.restart else [] }}" -- name: "Upload local maven providers" +- name: "Copy maven providers" ansible.builtin.copy: src: "{{ local_path.stat.path }}/{{ item.id }}.jar" dest: "{{ keycloak.home }}/providers/{{ item.id }}.jar" @@ -256,7 +249,7 @@ when: item.maven is defined no_log: "{{ item.maven.password is defined and item.maven.password | length > 0 | default(false) }}" -- name: "Upload local providers" +- name: "Copy providers" ansible.builtin.copy: src: "{{ item.local_path }}" dest: "{{ keycloak.home }}/providers/{{ item.id }}.jar" diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index 2dadf61..bb86b2c 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -91,7 +91,7 @@ register: keycloak_service_status changed_when: false -- name: "Trigger bootstrapped notification: remove `keycloak_quarkus_admin_user[_pass]` env vars" +- name: "Notify to remove `keycloak_quarkus_admin_user[_pass]` env vars" when: - not ansible_local.keycloak.general.bootstrapped | default(false) | bool # it was not bootstrapped prior to the current role's execution - keycloak_service_status.status.ActiveState == "active" # but it is now diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index 503b308..ae2dacf 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -43,10 +43,50 @@ vars: packages_list: "{{ keycloak_quarkus_prereq_package_list }}" +- name: Check local download archive path + ansible.builtin.stat: + path: "{{ keycloak_quarkus_download_path }}" + register: local_path + delegate_to: localhost + run_once: true + become: false + +- name: Validate local download path + ansible.builtin.assert: + that: + - local_path.stat.exists + - local_path.stat.readable + - keycloak_quarkus_offline_install or local_path.stat.writeable + quiet: true + fail_msg: "Defined controller path for downloading resource is incorrect: {{ keycloak_quarkus_download_path }}" + success_msg: "Will download resource to controller path: {{ local_path.stat.path }}" + delegate_to: localhost + run_once: true + +- name: Check downloaded archive if offline + ansible.builtin.stat: + path: "{{ local_path.stat.path }}/{{ keycloak.bundle }}" + when: keycloak_quarkus_offline_install + register: local_archive_path_check + delegate_to: localhost + run_once: true + +- name: Validate local downloaded archive if offline + ansible.builtin.assert: + that: + - local_archive_path_check.stat.exists + - local_archive_path_check.stat.readable + quiet: true + fail_msg: "Configured for offline install but install archive not found at: {{ local_archive_path_check.stat.path }}" + success_msg: "Will install offline with expected archive: {{ local_archive_path_check.stat.path }}" + when: keycloak_quarkus_offline_install + delegate_to: localhost + run_once: true + - name: "Validate keytool" when: keycloak_quarkus_config_key_store_password | length > 0 block: - - name: "Attempt to run keytool" + - name: "Check run keytool" changed_when: false ansible.builtin.command: keytool -help register: keytool_check diff --git a/roles/keycloak_quarkus/tasks/rebuild_config.yml b/roles/keycloak_quarkus/tasks/rebuild_config.yml index 5d2247d..ac78504 100644 --- a/roles/keycloak_quarkus/tasks/rebuild_config.yml +++ b/roles/keycloak_quarkus/tasks/rebuild_config.yml @@ -1,7 +1,7 @@ --- # cf. https://www.keycloak.org/server/configuration#_optimize_the_keycloak_startup - name: "Rebuild {{ keycloak.service_name }} config" - ansible.builtin.shell: | + ansible.builtin.shell: | # noqa blocked_modules shell is necessary here {{ keycloak.home }}/bin/kc.sh build environment: PATH: "{{ keycloak_quarkus_java_home | default(keycloak_quarkus_pkg_java_home, true) }}/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" diff --git a/roles/keycloak_quarkus/tasks/restart.yml b/roles/keycloak_quarkus/tasks/restart.yml index 2a1fabd..61356d5 100644 --- a/roles/keycloak_quarkus/tasks/restart.yml +++ b/roles/keycloak_quarkus/tasks/restart.yml @@ -16,7 +16,7 @@ delay: "{{ keycloak_quarkus_restart_health_check_delay }}" when: internal_force_health_check | default(keycloak_quarkus_restart_health_check) -- name: Pause to give distributed ispn caches time to (re-)replicate back onto first host +- name: Wait to give distributed ispn caches time to (re-)replicate back onto first host ansible.builtin.pause: seconds: "{{ keycloak_quarkus_restart_pause }}" when: From eb66d4a412528bfb4cb560a7b3ae730e97f8225f Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 26 Sep 2024 10:22:28 +0200 Subject: [PATCH 168/205] update prereqs validation --- .ansible-lint | 1 + .gitignore | 1 + roles/keycloak_quarkus/tasks/prereqs.yml | 8 ++++---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.ansible-lint b/.ansible-lint index e6607a4..8e4b5ca 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -30,6 +30,7 @@ warn_list: - schema[meta] - key-order[task] - blocked_modules + - run-once[task] skip_list: - vars_should_not_be_used diff --git a/.gitignore b/.gitignore index f2ffea4..ce41aef 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ docs/_build/ changelogs/.plugin-cache.yaml *.pem *.key +*.p12 diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index ae2dacf..0835aab 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -58,8 +58,8 @@ - local_path.stat.readable - keycloak_quarkus_offline_install or local_path.stat.writeable quiet: true - fail_msg: "Defined controller path for downloading resource is incorrect: {{ keycloak_quarkus_download_path }}" - success_msg: "Will download resource to controller path: {{ local_path.stat.path }}" + fail_msg: "Defined controller path for downloading resources is incorrect or unreadable: {{ keycloak_quarkus_download_path }}" + success_msg: "Will download resource to controller path: {{ keycloak_quarkus_download_path }}" delegate_to: localhost run_once: true @@ -77,8 +77,8 @@ - local_archive_path_check.stat.exists - local_archive_path_check.stat.readable quiet: true - fail_msg: "Configured for offline install but install archive not found at: {{ local_archive_path_check.stat.path }}" - success_msg: "Will install offline with expected archive: {{ local_archive_path_check.stat.path }}" + fail_msg: "Configured for offline install but install archive not found at: {{ local_path.stat.path }}/{{ keycloak.bundle }}" + success_msg: "Will install offline with expected archive: {{ local_path.stat.path }}/{{ keycloak.bundle }}" when: keycloak_quarkus_offline_install delegate_to: localhost run_once: true From fc0ee5a89654324ead9a8a66809fa0418d28d122 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 26 Sep 2024 10:22:42 +0200 Subject: [PATCH 169/205] refactor default test for keycloak-quarkus offline --- molecule/default/converge.yml | 97 +++++++++++++++-------------------- molecule/default/prepare.yml | 28 +++++----- molecule/default/verify.yml | 69 +------------------------ 3 files changed, 57 insertions(+), 137 deletions(-) diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index 07cd724..bb8c552 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -2,61 +2,46 @@ - name: Converge hosts: all vars: + keycloak_quarkus_show_deprecation_warnings: false + keycloak_quarkus_admin_pass: "remembertochangeme" keycloak_admin_password: "remembertochangeme" - keycloak_jvm_package: java-11-openjdk-headless - keycloak_modcluster_enabled: True - keycloak_modcluster_urls: - - host: myhost1 - port: 16667 - - host: myhost2 - port: 16668 - keycloak_jboss_port_offset: 10 - keycloak_log_target: /tmp/keycloak + keycloak_quarkus_host: instance + keycloak_quarkus_log: file + keycloak_quarkus_log_level: debug + keycloak_quarkus_log_target: /tmp/keycloak + keycloak_quarkus_start_dev: True + keycloak_quarkus_proxy_mode: none + keycloak_quarkus_offline_install: true + keycloak_quarkus_download_path: /tmp/keycloak/ roles: - - role: keycloak - tasks: - - name: Keycloak Realm Role - ansible.builtin.include_role: - name: keycloak_realm - vars: - keycloak_client_default_roles: - - TestRoleAdmin - - TestRoleUser - keycloak_client_users: - - username: TestUser - password: password - client_roles: - - client: TestClient - role: TestRoleUser - realm: "{{ keycloak_realm }}" - - username: TestAdmin - password: password - client_roles: - - client: TestClient - role: TestRoleUser - realm: "{{ keycloak_realm }}" - - client: TestClient - role: TestRoleAdmin - realm: "{{ keycloak_realm }}" - keycloak_realm: TestRealm - keycloak_clients: - - name: TestClient - roles: "{{ keycloak_client_default_roles }}" - realm: "{{ keycloak_realm }}" - public_client: "{{ keycloak_client_public }}" - web_origins: "{{ keycloak_client_web_origins }}" - users: "{{ keycloak_client_users }}" - client_id: TestClient - attributes: - post.logout.redirect.uris: '/public/logout' - pre_tasks: - - name: "Retrieve assets server from env" - ansible.builtin.set_fact: - assets_server: "{{ lookup('env', 'MIDDLEWARE_DOWNLOAD_RELEASE_SERVER_URL') }}" - - - name: "Set offline when assets server from env is defined" - ansible.builtin.set_fact: - sso_offline_install: True - when: - - assets_server is defined - - assets_server | length > 0 + - role: keycloak_quarkus + - role: keycloak_realm + keycloak_context: '' + keycloak_client_default_roles: + - TestRoleAdmin + - TestRoleUser + keycloak_client_users: + - username: TestUser + password: password + client_roles: + - client: TestClient + role: TestRoleUser + realm: "{{ keycloak_realm }}" + - username: TestAdmin + password: password + client_roles: + - client: TestClient + role: TestRoleUser + realm: "{{ keycloak_realm }}" + - client: TestClient + role: TestRoleAdmin + realm: "{{ keycloak_realm }}" + keycloak_realm: TestRealm + keycloak_clients: + - name: TestClient + roles: "{{ keycloak_client_default_roles }}" + realm: "{{ keycloak_realm }}" + public_client: "{{ keycloak_client_public }}" + web_origins: "{{ keycloak_client_web_origins }}" + users: "{{ keycloak_client_users }}" + client_id: TestClient diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml index b707f6c..a50dfa4 100644 --- a/molecule/default/prepare.yml +++ b/molecule/default/prepare.yml @@ -12,18 +12,18 @@ - "{{ assets_server }}/sso/7.6.0/rh-sso-7.6.0-server-dist.zip" - "{{ assets_server }}/sso/7.6.1/rh-sso-7.6.1-patch.zip" - - name: Install JDK8 - become: yes - ansible.builtin.yum: - name: - - java-1.8.0-openjdk - state: present - when: ansible_facts['os_family'] == "RedHat" + - name: Create controller directory for downloads + ansible.builtin.file: # noqa risky-file-permissions delegated, uses controller host user + path: /tmp/keycloak + state: directory + mode: '0750' + delegate_to: localhost + run_once: true - - name: Install JDK8 - become: yes - ansible.builtin.apt: - name: - - openjdk-8-jdk - state: present - when: ansible_facts['os_family'] == "Debian" + - name: Download keycloak archive to controller directory + ansible.builtin.get_url: # noqa risky-file-permissions delegated, uses controller host user + url: https://github.com/keycloak/keycloak/releases/download/24.0.4/keycloak-24.0.4.zip + dest: /tmp/keycloak + mode: '0640' + delegate_to: localhost + run_once: true diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index 39e94c5..b880105 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -3,10 +3,7 @@ hosts: all vars: keycloak_admin_password: "remembertochangeme" - keycloak_jvm_package: java-11-openjdk-headless - keycloak_uri: "http://localhost:{{ 8080 + ( keycloak_jboss_port_offset | default(0) ) }}" - keycloak_management_port: "http://localhost:{{ 9990 + ( keycloak_jboss_port_offset | default(0) ) }}" - keycloak_jboss_port_offset: 10 + keycloak_uri: "http://localhost:8080" tasks: - name: Populate service facts ansible.builtin.service_facts: @@ -15,16 +12,9 @@ that: - ansible_facts.services["keycloak.service"]["state"] == "running" - ansible_facts.services["keycloak.service"]["status"] == "enabled" - - name: Verify we are running on requested jvm # noqa blocked_modules command-instead-of-module - ansible.builtin.shell: | - set -o pipefail - ps -ef | grep '/etc/alternatives/jre_11/' | grep -v grep - args: - executable: /bin/bash - changed_when: no - name: Verify token api call ansible.builtin.uri: - url: "{{ keycloak_uri }}/auth/realms/master/protocol/openid-connect/token" + url: "{{ keycloak_uri }}/realms/master/protocol/openid-connect/token" method: POST body: "client_id=admin-cli&username=admin&password={{ keycloak_admin_password }}&grant_type=password" validate_certs: no @@ -32,58 +22,3 @@ until: keycloak_auth_response.status == 200 retries: 2 delay: 2 - - name: Fetch openid-connect config - ansible.builtin.uri: - url: "{{ keycloak_uri }}/auth/realms/TestRealm/.well-known/openid-configuration" - method: GET - validate_certs: no - status_code: 200 - register: keycloak_openid_config - - name: Verify expected config - ansible.builtin.assert: - that: - - keycloak_openid_config.json.registration_endpoint == 'http://localhost:8080/auth/realms/TestRealm/clients-registrations/openid-connect' - - name: Get test realm clients - ansible.builtin.uri: - url: "{{ keycloak_uri }}/auth/admin/realms/TestRealm/clients" - method: GET - validate_certs: no - status_code: 200 - headers: - Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" - register: keycloak_query_clients - - name: Verify expected config - ansible.builtin.assert: - that: - - (keycloak_query_clients.json | selectattr('clientId','equalto','TestClient') | first)["attributes"]["post.logout.redirect.uris"] == '/public/logout' - - name: "Privilege escalation as some files/folders may requires it" - become: yes - block: - - name: Check log folder - ansible.builtin.stat: - path: "/tmp/keycloak" - register: keycloak_log_folder - - name: Check that keycloak log folder exists and is a link - ansible.builtin.assert: - that: - - keycloak_log_folder.stat.exists - - not keycloak_log_folder.stat.isdir - - keycloak_log_folder.stat.islnk - - name: Check log file - ansible.builtin.stat: - path: "/tmp/keycloak/server.log" - register: keycloak_log_file - - name: Check if keycloak file exists - ansible.builtin.assert: - that: - - keycloak_log_file.stat.exists - - not keycloak_log_file.stat.isdir - - name: Check default log folder - ansible.builtin.stat: - path: "/var/log/keycloak" - register: keycloak_default_log_folder - failed_when: false - - name: Check that default keycloak log folder doesn't exist - ansible.builtin.assert: - that: - - not keycloak_default_log_folder.stat.exists From b2edea87771fb59d46f2bb2ecc81fc91fd02c8ed Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Thu, 26 Sep 2024 10:22:54 +0200 Subject: [PATCH 170/205] linter --- molecule/quarkus/prepare.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/molecule/quarkus/prepare.yml b/molecule/quarkus/prepare.yml index 459bafa..21a0f30 100644 --- a/molecule/quarkus/prepare.yml +++ b/molecule/quarkus/prepare.yml @@ -12,14 +12,14 @@ - name: Create certificate request ansible.builtin.command: openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes -subj '/CN=instance' delegate_to: localhost - changed_when: False + changed_when: false - name: Create vault directory become: true ansible.builtin.file: state: directory path: "/opt/keycloak/vault" - mode: 0755 + mode: '0755' - name: Make sure a jre is available (for keytool to prepare keystore) delegate_to: localhost @@ -41,4 +41,4 @@ ansible.builtin.copy: src: keystore.p12 dest: /opt/keycloak/vault/keystore.p12 - mode: 0444 + mode: '0444' From c8021f3102b156f077054a714a36648d01e03deb Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Thu, 26 Sep 2024 08:52:04 +0000 Subject: [PATCH 171/205] Update changelog for release 2.4.2 Signed-off-by: ansible-middleware-core --- CHANGELOG.rst | 13 +++++++++++++ changelogs/changelog.yaml | 14 ++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1aed396..7283c76 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,19 @@ middleware\_automation.keycloak Release Notes This changelog describes changes after version 0.2.6. +v2.4.2 +====== + +Minor Changes +------------- + +- New parameter ``keycloak_quarkus_download_path`` `#239 `_ + +Bugfixes +-------- + +- Add wait_for_port number parameter `#237 `_ + v2.4.1 ====== diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index c841535..41a4076 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -590,3 +590,17 @@ releases: fragments: - v2.4.1-devel_summary.yaml release_date: '2024-07-02' + 2.4.2: + changes: + bugfixes: + - 'Add wait_for_port number parameter `#237 `_ + + ' + minor_changes: + - 'New parameter ``keycloak_quarkus_download_path`` `#239 `_ + + ' + fragments: + - 237.yaml + - 239.yaml + release_date: '2024-09-26' From ac4511bea9e39263fec9eec12dadb19feb356db3 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Thu, 26 Sep 2024 08:52:17 +0000 Subject: [PATCH 172/205] Bump version to 2.4.3 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index 2091f28..a782353 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.4.2" +version: "2.4.3" readme: README.md authors: - Romain Pelisse From c6bb815979a875c6b0bdb1384c3d9c9c81ab25c9 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 14 Oct 2024 10:07:44 +0200 Subject: [PATCH 173/205] update keycloak modules --- .../identity/keycloak/keycloak.py | 1251 +++++++++++++++-- plugins/modules/keycloak_client.py | 289 +++- plugins/modules/keycloak_role.py | 97 +- plugins/modules/keycloak_user_federation.py | 257 ++-- 4 files changed, 1605 insertions(+), 289 deletions(-) diff --git a/plugins/module_utils/identity/keycloak/keycloak.py b/plugins/module_utils/identity/keycloak/keycloak.py index 15b6657..128b0fe 100644 --- a/plugins/module_utils/identity/keycloak/keycloak.py +++ b/plugins/module_utils/identity/keycloak/keycloak.py @@ -9,6 +9,7 @@ __metaclass__ = type import json import traceback +import copy from ansible.module_utils.urls import open_url from ansible.module_utils.six.moves.urllib.parse import urlencode, quote @@ -18,6 +19,7 @@ from ansible.module_utils.common.text.converters import to_native, to_text URL_REALM_INFO = "{url}/realms/{realm}" URL_REALMS = "{url}/admin/realms" URL_REALM = "{url}/admin/realms/{realm}" +URL_REALM_KEYS_METADATA = "{url}/admin/realms/{realm}/keys" URL_TOKEN = "{url}/realms/{realm}/protocol/openid-connect/token" URL_CLIENT = "{url}/admin/realms/{realm}/clients/{id}" @@ -27,6 +29,9 @@ URL_CLIENT_ROLES = "{url}/admin/realms/{realm}/clients/{id}/roles" URL_CLIENT_ROLE = "{url}/admin/realms/{realm}/clients/{id}/roles/{name}" URL_CLIENT_ROLE_COMPOSITES = "{url}/admin/realms/{realm}/clients/{id}/roles/{name}/composites" +URL_CLIENT_ROLE_SCOPE_CLIENTS = "{url}/admin/realms/{realm}/clients/{id}/scope-mappings/clients/{scopeid}" +URL_CLIENT_ROLE_SCOPE_REALM = "{url}/admin/realms/{realm}/clients/{id}/scope-mappings/realm" + URL_REALM_ROLES = "{url}/admin/realms/{realm}/roles" URL_REALM_ROLE = "{url}/admin/realms/{realm}/roles/{name}" URL_REALM_ROLEMAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings/realm" @@ -49,16 +54,36 @@ URL_CLIENTSCOPE = "{url}/admin/realms/{realm}/client-scopes/{id}" URL_CLIENTSCOPE_PROTOCOLMAPPERS = "{url}/admin/realms/{realm}/client-scopes/{id}/protocol-mappers/models" URL_CLIENTSCOPE_PROTOCOLMAPPER = "{url}/admin/realms/{realm}/client-scopes/{id}/protocol-mappers/models/{mapper_id}" +URL_DEFAULT_CLIENTSCOPES = "{url}/admin/realms/{realm}/default-default-client-scopes" +URL_DEFAULT_CLIENTSCOPE = "{url}/admin/realms/{realm}/default-default-client-scopes/{id}" +URL_OPTIONAL_CLIENTSCOPES = "{url}/admin/realms/{realm}/default-optional-client-scopes" +URL_OPTIONAL_CLIENTSCOPE = "{url}/admin/realms/{realm}/default-optional-client-scopes/{id}" + +URL_CLIENT_DEFAULT_CLIENTSCOPES = "{url}/admin/realms/{realm}/clients/{cid}/default-client-scopes" +URL_CLIENT_DEFAULT_CLIENTSCOPE = "{url}/admin/realms/{realm}/clients/{cid}/default-client-scopes/{id}" +URL_CLIENT_OPTIONAL_CLIENTSCOPES = "{url}/admin/realms/{realm}/clients/{cid}/optional-client-scopes" +URL_CLIENT_OPTIONAL_CLIENTSCOPE = "{url}/admin/realms/{realm}/clients/{cid}/optional-client-scopes/{id}" + URL_CLIENT_GROUP_ROLEMAPPINGS = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}" URL_CLIENT_GROUP_ROLEMAPPINGS_AVAILABLE = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}/available" URL_CLIENT_GROUP_ROLEMAPPINGS_COMPOSITE = "{url}/admin/realms/{realm}/groups/{id}/role-mappings/clients/{client}/composite" URL_USERS = "{url}/admin/realms/{realm}/users" +URL_USER = "{url}/admin/realms/{realm}/users/{id}" +URL_USER_ROLE_MAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings" +URL_USER_REALM_ROLE_MAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings/realm" +URL_USER_CLIENTS_ROLE_MAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings/clients" +URL_USER_CLIENT_ROLE_MAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings/clients/{client_id}" +URL_USER_GROUPS = "{url}/admin/realms/{realm}/users/{id}/groups" +URL_USER_GROUP = "{url}/admin/realms/{realm}/users/{id}/groups/{group_id}" + URL_CLIENT_SERVICE_ACCOUNT_USER = "{url}/admin/realms/{realm}/clients/{id}/service-account-user" URL_CLIENT_USER_ROLEMAPPINGS = "{url}/admin/realms/{realm}/users/{id}/role-mappings/clients/{client}" URL_CLIENT_USER_ROLEMAPPINGS_AVAILABLE = "{url}/admin/realms/{realm}/users/{id}/role-mappings/clients/{client}/available" URL_CLIENT_USER_ROLEMAPPINGS_COMPOSITE = "{url}/admin/realms/{realm}/users/{id}/role-mappings/clients/{client}/composite" +URL_REALM_GROUP_ROLEMAPPINGS = "{url}/admin/realms/{realm}/groups/{group}/role-mappings/realm" + URL_CLIENTSECRET = "{url}/admin/realms/{realm}/clients/{id}/client-secret" URL_AUTHENTICATION_FLOWS = "{url}/admin/realms/{realm}/authentication/flows" @@ -71,6 +96,9 @@ URL_AUTHENTICATION_EXECUTION_CONFIG = "{url}/admin/realms/{realm}/authentication URL_AUTHENTICATION_EXECUTION_RAISE_PRIORITY = "{url}/admin/realms/{realm}/authentication/executions/{id}/raise-priority" URL_AUTHENTICATION_EXECUTION_LOWER_PRIORITY = "{url}/admin/realms/{realm}/authentication/executions/{id}/lower-priority" URL_AUTHENTICATION_CONFIG = "{url}/admin/realms/{realm}/authentication/config/{id}" +URL_AUTHENTICATION_REGISTER_REQUIRED_ACTION = "{url}/admin/realms/{realm}/authentication/register-required-action" +URL_AUTHENTICATION_REQUIRED_ACTIONS = "{url}/admin/realms/{realm}/authentication/required-actions" +URL_AUTHENTICATION_REQUIRED_ACTIONS_ALIAS = "{url}/admin/realms/{realm}/authentication/required-actions/{alias}" URL_IDENTITY_PROVIDERS = "{url}/admin/realms/{realm}/identity-provider/instances" URL_IDENTITY_PROVIDER = "{url}/admin/realms/{realm}/identity-provider/instances/{alias}" @@ -80,6 +108,23 @@ URL_IDENTITY_PROVIDER_MAPPER = "{url}/admin/realms/{realm}/identity-provider/ins URL_COMPONENTS = "{url}/admin/realms/{realm}/components" URL_COMPONENT = "{url}/admin/realms/{realm}/components/{id}" +URL_AUTHZ_AUTHORIZATION_SCOPE = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/scope/{id}" +URL_AUTHZ_AUTHORIZATION_SCOPES = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/scope" + +# This URL is used for: +# - Querying client authorization permissions +# - Removing client authorization permissions +URL_AUTHZ_POLICIES = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/policy" +URL_AUTHZ_POLICY = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/policy/{id}" + +URL_AUTHZ_PERMISSION = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/permission/{permission_type}/{id}" +URL_AUTHZ_PERMISSIONS = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/permission/{permission_type}" + +URL_AUTHZ_RESOURCES = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/resource" + +URL_AUTHZ_CUSTOM_POLICY = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/policy/{policy_type}" +URL_AUTHZ_CUSTOM_POLICIES = "{url}/admin/realms/{realm}/clients/{client_id}/authz/resource-server/policy" + def keycloak_argument_spec(): """ @@ -140,8 +185,7 @@ def get_token(module_params): 'password': auth_password, } # Remove empty items, for instance missing client_secret - payload = dict( - (k, v) for k, v in temp_payload.items() if v is not None) + payload = {k: v for k, v in temp_payload.items() if v is not None} try: r = json.loads(to_native(open_url(auth_url, method='POST', validate_certs=validate_certs, http_agent=http_agent, timeout=connection_timeout, @@ -194,24 +238,30 @@ def is_struct_included(struct1, struct2, exclude=None): Return True if all element of dict 1 are present in dict 2, return false otherwise. """ if isinstance(struct1, list) and isinstance(struct2, list): + if not struct1 and not struct2: + return True for item1 in struct1: if isinstance(item1, (list, dict)): for item2 in struct2: - if not is_struct_included(item1, item2, exclude): - return False + if is_struct_included(item1, item2, exclude): + break + else: + return False else: if item1 not in struct2: return False return True elif isinstance(struct1, dict) and isinstance(struct2, dict): + if not struct1 and not struct2: + return True try: for key in struct1: if not (exclude and key in exclude): if not is_struct_included(struct1[key], struct2[key], exclude): return False - return True except KeyError: return False + return True elif isinstance(struct1, bool) and isinstance(struct2, bool): return struct1 == struct2 else: @@ -247,8 +297,39 @@ class KeycloakAPI(object): if e.code == 404: return None else: - self.module.fail_json(msg='Could not obtain realm %s: %s' % (realm, str(e)), - exception=traceback.format_exc()) + self.fail_open_url(e, msg='Could not obtain realm %s: %s' % (realm, str(e)), + exception=traceback.format_exc()) + except ValueError as e: + self.module.fail_json(msg='API returned incorrect JSON when trying to obtain realm %s: %s' % (realm, str(e)), + exception=traceback.format_exc()) + except Exception as e: + self.module.fail_json(msg='Could not obtain realm %s: %s' % (realm, str(e)), + exception=traceback.format_exc()) + + def get_realm_keys_metadata_by_id(self, realm='master'): + """Obtain realm public info by id + + :param realm: realm id + + :return: None, or a 'KeysMetadataRepresentation' + (https://www.keycloak.org/docs-api/latest/rest-api/index.html#KeysMetadataRepresentation) + -- a dict containing the keys 'active' and 'keys', the former containing a mapping + from algorithms to key-ids, the latter containing a list of dicts with key + information. + """ + realm_keys_metadata_url = URL_REALM_KEYS_METADATA.format(url=self.baseurl, realm=realm) + + try: + return json.loads(to_native(open_url(realm_keys_metadata_url, method='GET', http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs).read())) + + except HTTPError as e: + if e.code == 404: + return None + else: + self.fail_open_url(e, msg='Could not obtain realm %s: %s' % (realm, str(e)), + exception=traceback.format_exc()) except ValueError as e: self.module.fail_json(msg='API returned incorrect JSON when trying to obtain realm %s: %s' % (realm, str(e)), exception=traceback.format_exc()) @@ -272,8 +353,8 @@ class KeycloakAPI(object): if e.code == 404: return None else: - self.module.fail_json(msg='Could not obtain realm %s: %s' % (realm, str(e)), - exception=traceback.format_exc()) + self.fail_open_url(e, msg='Could not obtain realm %s: %s' % (realm, str(e)), + exception=traceback.format_exc()) except ValueError as e: self.module.fail_json(msg='API returned incorrect JSON when trying to obtain realm %s: %s' % (realm, str(e)), exception=traceback.format_exc()) @@ -293,8 +374,8 @@ class KeycloakAPI(object): return open_url(realm_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(realmrep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not update realm %s: %s' % (realm, str(e)), - exception=traceback.format_exc()) + self.fail_open_url(e, msg='Could not update realm %s: %s' % (realm, str(e)), + exception=traceback.format_exc()) def create_realm(self, realmrep): """ Create a realm in keycloak @@ -307,8 +388,8 @@ class KeycloakAPI(object): return open_url(realm_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(realmrep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not create realm %s: %s' % (realmrep['id'], str(e)), - exception=traceback.format_exc()) + self.fail_open_url(e, msg='Could not create realm %s: %s' % (realmrep['id'], str(e)), + exception=traceback.format_exc()) def delete_realm(self, realm="master"): """ Delete a realm from Keycloak @@ -322,8 +403,8 @@ class KeycloakAPI(object): return open_url(realm_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not delete realm %s: %s' % (realm, str(e)), - exception=traceback.format_exc()) + self.fail_open_url(e, msg='Could not delete realm %s: %s' % (realm, str(e)), + exception=traceback.format_exc()) def get_clients(self, realm='master', filter=None): """ Obtains client representations for clients in a realm @@ -344,7 +425,7 @@ class KeycloakAPI(object): self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of clients for realm %s: %s' % (realm, str(e))) except Exception as e: - self.module.fail_json(msg='Could not obtain list of clients for realm %s: %s' + self.fail_open_url(e, msg='Could not obtain list of clients for realm %s: %s' % (realm, str(e))) def get_client_by_clientid(self, client_id, realm='master'): @@ -377,7 +458,7 @@ class KeycloakAPI(object): if e.code == 404: return None else: - self.module.fail_json(msg='Could not obtain client %s for realm %s: %s' + self.fail_open_url(e, msg='Could not obtain client %s for realm %s: %s' % (id, realm, str(e))) except ValueError as e: self.module.fail_json(msg='API returned incorrect JSON when trying to obtain client %s for realm %s: %s' @@ -412,7 +493,7 @@ class KeycloakAPI(object): return open_url(client_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(clientrep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not update client %s in realm %s: %s' + self.fail_open_url(e, msg='Could not update client %s in realm %s: %s' % (id, realm, str(e))) def create_client(self, clientrep, realm="master"): @@ -427,7 +508,7 @@ class KeycloakAPI(object): return open_url(client_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(clientrep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not create client %s in realm %s: %s' + self.fail_open_url(e, msg='Could not create client %s in realm %s: %s' % (clientrep['clientId'], realm, str(e))) def delete_client(self, id, realm="master"): @@ -443,7 +524,7 @@ class KeycloakAPI(object): return open_url(client_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not delete client %s in realm %s: %s' + self.fail_open_url(e, msg='Could not delete client %s in realm %s: %s' % (id, realm, str(e))) def get_client_roles_by_id(self, cid, realm="master"): @@ -459,7 +540,7 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except Exception as e: - self.module.fail_json(msg="Could not fetch rolemappings for client %s in realm %s: %s" + self.fail_open_url(e, msg="Could not fetch rolemappings for client %s in realm %s: %s" % (cid, realm, str(e))) def get_client_role_id_by_name(self, cid, name, realm="master"): @@ -494,12 +575,12 @@ class KeycloakAPI(object): if rid == role['id']: return role except Exception as e: - self.module.fail_json(msg="Could not fetch rolemappings for client %s in group %s, realm %s: %s" + self.fail_open_url(e, msg="Could not fetch rolemappings for client %s in group %s, realm %s: %s" % (cid, gid, realm, str(e))) return None def get_client_group_available_rolemappings(self, gid, cid, realm="master"): - """ Fetch the available role of a client in a specified goup on the Keycloak server. + """ Fetch the available role of a client in a specified group on the Keycloak server. :param gid: ID of the group from which to obtain the rolemappings. :param cid: ID of the client from which to obtain the rolemappings. @@ -512,7 +593,7 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except Exception as e: - self.module.fail_json(msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s" + self.fail_open_url(e, msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s" % (cid, gid, realm, str(e))) def get_client_group_composite_rolemappings(self, gid, cid, realm="master"): @@ -529,7 +610,7 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except Exception as e: - self.module.fail_json(msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s" + self.fail_open_url(e, msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s" % (cid, gid, realm, str(e))) def get_role_by_id(self, rid, realm="master"): @@ -545,7 +626,7 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except Exception as e: - self.module.fail_json(msg="Could not fetch role for id %s in realm %s: %s" + self.fail_open_url(e, msg="Could not fetch role for id %s in realm %s: %s" % (rid, realm, str(e))) def get_client_roles_by_id_composite_rolemappings(self, rid, cid, realm="master"): @@ -562,7 +643,7 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except Exception as e: - self.module.fail_json(msg="Could not fetch role for id %s and cid %s in realm %s: %s" + self.fail_open_url(e, msg="Could not fetch role for id %s and cid %s in realm %s: %s" % (rid, cid, realm, str(e))) def add_client_roles_by_id_composite_rolemapping(self, rid, roles_rep, realm="master"): @@ -578,11 +659,43 @@ class KeycloakAPI(object): open_url(available_rolemappings_url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(roles_rep), validate_certs=self.validate_certs, timeout=self.connection_timeout) except Exception as e: - self.module.fail_json(msg="Could not assign roles to composite role %s and realm %s: %s" + self.fail_open_url(e, msg="Could not assign roles to composite role %s and realm %s: %s" % (rid, realm, str(e))) + def add_group_realm_rolemapping(self, gid, role_rep, realm="master"): + """ Add the specified realm role to specified group on the Keycloak server. + + :param gid: ID of the group to add the role mapping. + :param role_rep: Representation of the role to assign. + :param realm: Realm from which to obtain the rolemappings. + :return: None. + """ + url = URL_REALM_GROUP_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, group=gid) + try: + open_url(url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep), + validate_certs=self.validate_certs, timeout=self.connection_timeout) + except Exception as e: + self.fail_open_url(e, msg="Could add realm role mappings for group %s, realm %s: %s" + % (gid, realm, str(e))) + + def delete_group_realm_rolemapping(self, gid, role_rep, realm="master"): + """ Delete the specified realm role from the specified group on the Keycloak server. + + :param gid: ID of the group from which to obtain the rolemappings. + :param role_rep: Representation of the role to assign. + :param realm: Realm from which to obtain the rolemappings. + :return: None. + """ + url = URL_REALM_GROUP_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, group=gid) + try: + open_url(url, method="DELETE", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep), + validate_certs=self.validate_certs, timeout=self.connection_timeout) + except Exception as e: + self.fail_open_url(e, msg="Could not delete realm role mappings for group %s, realm %s: %s" + % (gid, realm, str(e))) + def add_group_rolemapping(self, gid, cid, role_rep, realm="master"): - """ Fetch the composite role of a client in a specified goup on the Keycloak server. + """ Fetch the composite role of a client in a specified group on the Keycloak server. :param gid: ID of the group from which to obtain the rolemappings. :param cid: ID of the client from which to obtain the rolemappings. @@ -595,7 +708,7 @@ class KeycloakAPI(object): open_url(available_rolemappings_url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep), validate_certs=self.validate_certs, timeout=self.connection_timeout) except Exception as e: - self.module.fail_json(msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s" + self.fail_open_url(e, msg="Could not fetch available rolemappings for client %s in group %s, realm %s: %s" % (cid, gid, realm, str(e))) def delete_group_rolemapping(self, gid, cid, role_rep, realm="master"): @@ -612,7 +725,7 @@ class KeycloakAPI(object): open_url(available_rolemappings_url, method="DELETE", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep), validate_certs=self.validate_certs, timeout=self.connection_timeout) except Exception as e: - self.module.fail_json(msg="Could not delete available rolemappings for client %s in group %s, realm %s: %s" + self.fail_open_url(e, msg="Could not delete available rolemappings for client %s in group %s, realm %s: %s" % (cid, gid, realm, str(e))) def get_client_user_rolemapping_by_id(self, uid, cid, rid, realm='master'): @@ -633,7 +746,7 @@ class KeycloakAPI(object): if rid == role['id']: return role except Exception as e: - self.module.fail_json(msg="Could not fetch rolemappings for client %s and user %s, realm %s: %s" + self.fail_open_url(e, msg="Could not fetch rolemappings for client %s and user %s, realm %s: %s" % (cid, uid, realm, str(e))) return None @@ -651,7 +764,7 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except Exception as e: - self.module.fail_json(msg="Could not fetch effective rolemappings for client %s and user %s, realm %s: %s" + self.fail_open_url(e, msg="Could not fetch effective rolemappings for client %s and user %s, realm %s: %s" % (cid, uid, realm, str(e))) def get_client_user_composite_rolemappings(self, uid, cid, realm="master"): @@ -668,7 +781,7 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except Exception as e: - self.module.fail_json(msg="Could not fetch available rolemappings for user %s of realm %s: %s" + self.fail_open_url(e, msg="Could not fetch available rolemappings for user %s of realm %s: %s" % (uid, realm, str(e))) def get_realm_user_rolemapping_by_id(self, uid, rid, realm='master'): @@ -688,7 +801,7 @@ class KeycloakAPI(object): if rid == role['id']: return role except Exception as e: - self.module.fail_json(msg="Could not fetch rolemappings for user %s, realm %s: %s" + self.fail_open_url(e, msg="Could not fetch rolemappings for user %s, realm %s: %s" % (uid, realm, str(e))) return None @@ -705,7 +818,7 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except Exception as e: - self.module.fail_json(msg="Could not fetch available rolemappings for user %s of realm %s: %s" + self.fail_open_url(e, msg="Could not fetch available rolemappings for user %s of realm %s: %s" % (uid, realm, str(e))) def get_realm_user_composite_rolemappings(self, uid, realm="master"): @@ -721,7 +834,7 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except Exception as e: - self.module.fail_json(msg="Could not fetch effective rolemappings for user %s, realm %s: %s" + self.fail_open_url(e, msg="Could not fetch effective rolemappings for user %s, realm %s: %s" % (uid, realm, str(e))) def get_user_by_username(self, username, realm="master"): @@ -734,13 +847,21 @@ class KeycloakAPI(object): users_url = URL_USERS.format(url=self.baseurl, realm=realm) users_url += '?username=%s&exact=true' % username try: - return json.loads(to_native(open_url(users_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout, - validate_certs=self.validate_certs).read())) + userrep = None + users = json.loads(to_native(open_url(users_url, method='GET', http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs).read())) + for user in users: + if user['username'] == username: + userrep = user + break + return userrep + except ValueError as e: self.module.fail_json(msg='API returned incorrect JSON when trying to obtain the user for realm %s and username %s: %s' % (realm, username, str(e))) except Exception as e: - self.module.fail_json(msg='Could not obtain the user for realm %s and username %s: %s' + self.fail_open_url(e, msg='Could not obtain the user for realm %s and username %s: %s' % (realm, username, str(e))) def get_service_account_user_by_client_id(self, client_id, realm="master"): @@ -754,13 +875,14 @@ class KeycloakAPI(object): service_account_user_url = URL_CLIENT_SERVICE_ACCOUNT_USER.format(url=self.baseurl, realm=realm, id=cid) try: - return json.loads(to_native(open_url(service_account_user_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout, + return json.loads(to_native(open_url(service_account_user_url, method='GET', http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except ValueError as e: self.module.fail_json(msg='API returned incorrect JSON when trying to obtain the service-account-user for realm %s and client_id %s: %s' % (realm, client_id, str(e))) except Exception as e: - self.module.fail_json(msg='Could not obtain the service-account-user for realm %s and client_id %s: %s' + self.fail_open_url(e, msg='Could not obtain the service-account-user for realm %s and client_id %s: %s' % (realm, client_id, str(e))) def add_user_rolemapping(self, uid, cid, role_rep, realm="master"): @@ -778,7 +900,7 @@ class KeycloakAPI(object): open_url(user_realm_rolemappings_url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep), validate_certs=self.validate_certs, timeout=self.connection_timeout) except Exception as e: - self.module.fail_json(msg="Could not map roles to userId %s for realm %s and roles %s: %s" + self.fail_open_url(e, msg="Could not map roles to userId %s for realm %s and roles %s: %s" % (uid, realm, json.dumps(role_rep), str(e))) else: user_client_rolemappings_url = URL_CLIENT_USER_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=uid, client=cid) @@ -786,7 +908,7 @@ class KeycloakAPI(object): open_url(user_client_rolemappings_url, method="POST", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep), validate_certs=self.validate_certs, timeout=self.connection_timeout) except Exception as e: - self.module.fail_json(msg="Could not map roles to userId %s for client %s, realm %s and roles %s: %s" + self.fail_open_url(e, msg="Could not map roles to userId %s for client %s, realm %s and roles %s: %s" % (cid, uid, realm, json.dumps(role_rep), str(e))) def delete_user_rolemapping(self, uid, cid, role_rep, realm="master"): @@ -804,7 +926,7 @@ class KeycloakAPI(object): open_url(user_realm_rolemappings_url, method="DELETE", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep), validate_certs=self.validate_certs, timeout=self.connection_timeout) except Exception as e: - self.module.fail_json(msg="Could not remove roles %s from userId %s, realm %s: %s" + self.fail_open_url(e, msg="Could not remove roles %s from userId %s, realm %s: %s" % (json.dumps(role_rep), uid, realm, str(e))) else: user_client_rolemappings_url = URL_CLIENT_USER_ROLEMAPPINGS.format(url=self.baseurl, realm=realm, id=uid, client=cid) @@ -812,7 +934,7 @@ class KeycloakAPI(object): open_url(user_client_rolemappings_url, method="DELETE", http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(role_rep), validate_certs=self.validate_certs, timeout=self.connection_timeout) except Exception as e: - self.module.fail_json(msg="Could not remove roles %s for client %s from userId %s, realm %s: %s" + self.fail_open_url(e, msg="Could not remove roles %s for client %s from userId %s, realm %s: %s" % (json.dumps(role_rep), cid, uid, realm, str(e))) def get_client_templates(self, realm='master'): @@ -830,7 +952,7 @@ class KeycloakAPI(object): self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of client templates for realm %s: %s' % (realm, str(e))) except Exception as e: - self.module.fail_json(msg='Could not obtain list of client templates for realm %s: %s' + self.fail_open_url(e, msg='Could not obtain list of client templates for realm %s: %s' % (realm, str(e))) def get_client_template_by_id(self, id, realm='master'): @@ -849,7 +971,7 @@ class KeycloakAPI(object): self.module.fail_json(msg='API returned incorrect JSON when trying to obtain client templates %s for realm %s: %s' % (id, realm, str(e))) except Exception as e: - self.module.fail_json(msg='Could not obtain client template %s for realm %s: %s' + self.fail_open_url(e, msg='Could not obtain client template %s for realm %s: %s' % (id, realm, str(e))) def get_client_template_by_name(self, name, realm='master'): @@ -892,7 +1014,7 @@ class KeycloakAPI(object): return open_url(url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(clienttrep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not update client template %s in realm %s: %s' + self.fail_open_url(e, msg='Could not update client template %s in realm %s: %s' % (id, realm, str(e))) def create_client_template(self, clienttrep, realm="master"): @@ -907,7 +1029,7 @@ class KeycloakAPI(object): return open_url(url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(clienttrep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not create client template %s in realm %s: %s' + self.fail_open_url(e, msg='Could not create client template %s in realm %s: %s' % (clienttrep['clientId'], realm, str(e))) def delete_client_template(self, id, realm="master"): @@ -923,7 +1045,7 @@ class KeycloakAPI(object): return open_url(url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not delete client template %s in realm %s: %s' + self.fail_open_url(e, msg='Could not delete client template %s in realm %s: %s' % (id, realm, str(e))) def get_clientscopes(self, realm="master"): @@ -941,7 +1063,7 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except Exception as e: - self.module.fail_json(msg="Could not fetch list of clientscopes in realm %s: %s" + self.fail_open_url(e, msg="Could not fetch list of clientscopes in realm %s: %s" % (realm, str(e))) def get_clientscope_by_clientscopeid(self, cid, realm="master"): @@ -963,7 +1085,7 @@ class KeycloakAPI(object): if e.code == 404: return None else: - self.module.fail_json(msg="Could not fetch clientscope %s in realm %s: %s" + self.fail_open_url(e, msg="Could not fetch clientscope %s in realm %s: %s" % (cid, realm, str(e))) except Exception as e: self.module.fail_json(msg="Could not clientscope group %s in realm %s: %s" @@ -1004,7 +1126,7 @@ class KeycloakAPI(object): return open_url(clientscopes_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(clientscoperep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg="Could not create clientscope %s in realm %s: %s" + self.fail_open_url(e, msg="Could not create clientscope %s in realm %s: %s" % (clientscoperep['name'], realm, str(e))) def update_clientscope(self, clientscoperep, realm="master"): @@ -1020,7 +1142,7 @@ class KeycloakAPI(object): data=json.dumps(clientscoperep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not update clientscope %s in realm %s: %s' + self.fail_open_url(e, msg='Could not update clientscope %s in realm %s: %s' % (clientscoperep['name'], realm, str(e))) def delete_clientscope(self, name=None, cid=None, realm="master"): @@ -1058,7 +1180,7 @@ class KeycloakAPI(object): validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg="Unable to delete clientscope %s: %s" % (cid, str(e))) + self.fail_open_url(e, msg="Unable to delete clientscope %s: %s" % (cid, str(e))) def get_clientscope_protocolmappers(self, cid, realm="master"): """ Fetch the name and ID of all clientscopes on the Keycloak server. @@ -1076,7 +1198,7 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except Exception as e: - self.module.fail_json(msg="Could not fetch list of protocolmappers in realm %s: %s" + self.fail_open_url(e, msg="Could not fetch list of protocolmappers in realm %s: %s" % (realm, str(e))) def get_clientscope_protocolmapper_by_protocolmapperid(self, pid, cid, realm="master"): @@ -1100,7 +1222,7 @@ class KeycloakAPI(object): if e.code == 404: return None else: - self.module.fail_json(msg="Could not fetch protocolmapper %s in realm %s: %s" + self.fail_open_url(e, msg="Could not fetch protocolmapper %s in realm %s: %s" % (pid, realm, str(e))) except Exception as e: self.module.fail_json(msg="Could not fetch protocolmapper %s in realm %s: %s" @@ -1143,7 +1265,7 @@ class KeycloakAPI(object): return open_url(protocolmappers_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(mapper_rep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg="Could not create protocolmapper %s in realm %s: %s" + self.fail_open_url(e, msg="Could not create protocolmapper %s in realm %s: %s" % (mapper_rep['name'], realm, str(e))) def update_clientscope_protocolmappers(self, cid, mapper_rep, realm="master"): @@ -1160,9 +1282,134 @@ class KeycloakAPI(object): data=json.dumps(mapper_rep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not update protocolmappers for clientscope %s in realm %s: %s' + self.fail_open_url(e, msg='Could not update protocolmappers for clientscope %s in realm %s: %s' % (mapper_rep, realm, str(e))) + def get_default_clientscopes(self, realm, client_id=None): + """Fetch the name and ID of all clientscopes on the Keycloak server. + + To fetch the full data of the client scope, make a subsequent call to + get_clientscope_by_clientscopeid, passing in the ID of the client scope you wish to return. + + :param realm: Realm in which the clientscope resides. + :param client_id: The client in which the clientscope resides. + :return The default clientscopes of this realm or client + """ + url = URL_DEFAULT_CLIENTSCOPES if client_id is None else URL_CLIENT_DEFAULT_CLIENTSCOPES + return self._get_clientscopes_of_type(realm, url, 'default', client_id) + + def get_optional_clientscopes(self, realm, client_id=None): + """Fetch the name and ID of all clientscopes on the Keycloak server. + + To fetch the full data of the client scope, make a subsequent call to + get_clientscope_by_clientscopeid, passing in the ID of the client scope you wish to return. + + :param realm: Realm in which the clientscope resides. + :param client_id: The client in which the clientscope resides. + :return The optional clientscopes of this realm or client + """ + url = URL_OPTIONAL_CLIENTSCOPES if client_id is None else URL_CLIENT_OPTIONAL_CLIENTSCOPES + return self._get_clientscopes_of_type(realm, url, 'optional', client_id) + + def _get_clientscopes_of_type(self, realm, url_template, scope_type, client_id=None): + """Fetch the name and ID of all clientscopes on the Keycloak server. + + To fetch the full data of the client scope, make a subsequent call to + get_clientscope_by_clientscopeid, passing in the ID of the client scope you wish to return. + + :param realm: Realm in which the clientscope resides. + :param url_template the template for the right type + :param scope_type this can be either optional or default + :param client_id: The client in which the clientscope resides. + :return The clientscopes of the specified type of this realm + """ + if client_id is None: + clientscopes_url = url_template.format(url=self.baseurl, realm=realm) + try: + return json.loads(to_native(open_url(clientscopes_url, method="GET", http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) + except Exception as e: + self.fail_open_url(e, msg="Could not fetch list of %s clientscopes in realm %s: %s" % (scope_type, realm, str(e))) + else: + cid = self.get_client_id(client_id=client_id, realm=realm) + clientscopes_url = url_template.format(url=self.baseurl, realm=realm, cid=cid) + try: + return json.loads(to_native(open_url(clientscopes_url, method="GET", http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) + except Exception as e: + self.fail_open_url(e, msg="Could not fetch list of %s clientscopes in client %s: %s" % (scope_type, client_id, clientscopes_url)) + + def _decide_url_type_clientscope(self, client_id=None, scope_type="default"): + """Decides which url to use. + :param scope_type this can be either optional or default + :param client_id: The client in which the clientscope resides. + """ + if client_id is None: + if scope_type == "default": + return URL_DEFAULT_CLIENTSCOPE + if scope_type == "optional": + return URL_OPTIONAL_CLIENTSCOPE + else: + if scope_type == "default": + return URL_CLIENT_DEFAULT_CLIENTSCOPE + if scope_type == "optional": + return URL_CLIENT_OPTIONAL_CLIENTSCOPE + + def add_default_clientscope(self, id, realm="master", client_id=None): + """Add a client scope as default either on realm or client level. + + :param id: Client scope Id. + :param realm: Realm in which the clientscope resides. + :param client_id: The client in which the clientscope resides. + """ + self._action_type_clientscope(id, client_id, "default", realm, 'add') + + def add_optional_clientscope(self, id, realm="master", client_id=None): + """Add a client scope as optional either on realm or client level. + + :param id: Client scope Id. + :param realm: Realm in which the clientscope resides. + :param client_id: The client in which the clientscope resides. + """ + self._action_type_clientscope(id, client_id, "optional", realm, 'add') + + def delete_default_clientscope(self, id, realm="master", client_id=None): + """Remove a client scope as default either on realm or client level. + + :param id: Client scope Id. + :param realm: Realm in which the clientscope resides. + :param client_id: The client in which the clientscope resides. + """ + self._action_type_clientscope(id, client_id, "default", realm, 'delete') + + def delete_optional_clientscope(self, id, realm="master", client_id=None): + """Remove a client scope as optional either on realm or client level. + + :param id: Client scope Id. + :param realm: Realm in which the clientscope resides. + :param client_id: The client in which the clientscope resides. + """ + self._action_type_clientscope(id, client_id, "optional", realm, 'delete') + + def _action_type_clientscope(self, id=None, client_id=None, scope_type="default", realm="master", action='add'): + """ Delete or add a clientscope of type. + :param name: The name of the clientscope. A lookup will be performed to retrieve the clientscope ID. + :param client_id: The ID of the clientscope (preferred to name). + :param scope_type 'default' or 'optional' + :param realm: The realm in which this group resides, default "master". + """ + cid = None if client_id is None else self.get_client_id(client_id=client_id, realm=realm) + # should have a good cid by here. + clientscope_type_url = self._decide_url_type_clientscope(client_id, scope_type).format(realm=realm, id=id, cid=cid, url=self.baseurl) + try: + method = 'PUT' if action == "add" else 'DELETE' + return open_url(clientscope_type_url, method=method, http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + validate_certs=self.validate_certs) + + except Exception as e: + place = 'realm' if client_id is None else 'client ' + client_id + self.fail_open_url(e, msg="Unable to %s %s clientscope %s @ %s : %s" % (action, scope_type, id, place, str(e))) + def create_clientsecret(self, id, realm="master"): """ Generate a new client secret by id @@ -1173,14 +1420,15 @@ class KeycloakAPI(object): clientsecret_url = URL_CLIENTSECRET.format(url=self.baseurl, realm=realm, id=id) try: - return json.loads(to_native(open_url(clientsecret_url, method='POST', headers=self.restheaders, timeout=self.connection_timeout, + return json.loads(to_native(open_url(clientsecret_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except HTTPError as e: if e.code == 404: return None else: - self.module.fail_json(msg='Could not obtain clientsecret of client %s for realm %s: %s' + self.fail_open_url(e, msg='Could not obtain clientsecret of client %s for realm %s: %s' % (id, realm, str(e))) except Exception as e: self.module.fail_json(msg='Could not obtain clientsecret of client %s for realm %s: %s' @@ -1196,14 +1444,15 @@ class KeycloakAPI(object): clientsecret_url = URL_CLIENTSECRET.format(url=self.baseurl, realm=realm, id=id) try: - return json.loads(to_native(open_url(clientsecret_url, method='GET', headers=self.restheaders, timeout=self.connection_timeout, + return json.loads(to_native(open_url(clientsecret_url, method='GET', http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except HTTPError as e: if e.code == 404: return None else: - self.module.fail_json(msg='Could not obtain clientsecret of client %s for realm %s: %s' + self.fail_open_url(e, msg='Could not obtain clientsecret of client %s for realm %s: %s' % (id, realm, str(e))) except Exception as e: self.module.fail_json(msg='Could not obtain clientsecret of client %s for realm %s: %s' @@ -1223,7 +1472,7 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except Exception as e: - self.module.fail_json(msg="Could not fetch list of groups in realm %s: %s" + self.fail_open_url(e, msg="Could not fetch list of groups in realm %s: %s" % (realm, str(e))) def get_group_by_groupid(self, gid, realm="master"): @@ -1244,7 +1493,7 @@ class KeycloakAPI(object): if e.code == 404: return None else: - self.module.fail_json(msg="Could not fetch group %s in realm %s: %s" + self.fail_open_url(e, msg="Could not fetch group %s in realm %s: %s" % (gid, realm, str(e))) except Exception as e: self.module.fail_json(msg="Could not fetch group %s in realm %s: %s" @@ -1339,7 +1588,7 @@ class KeycloakAPI(object): def get_subgroup_direct_parent(self, parents, realm="master", children_to_resolve=None): """ Get keycloak direct parent group API object for a given chain of parents. - To succesfully work the API for subgroups we actually dont need + To successfully work the API for subgroups we actually don't need to "walk the whole tree" for nested groups but only need to know the ID for the direct predecessor of current subgroup. This method will guarantee us this information getting there with @@ -1391,7 +1640,7 @@ class KeycloakAPI(object): return open_url(groups_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(grouprep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg="Could not create group %s in realm %s: %s" + self.fail_open_url(e, msg="Could not create group %s in realm %s: %s" % (grouprep['name'], realm, str(e))) def create_subgroup(self, parents, grouprep, realm="master"): @@ -1419,7 +1668,7 @@ class KeycloakAPI(object): return open_url(url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(grouprep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg="Could not create subgroup %s for parent group %s in realm %s: %s" + self.fail_open_url(e, msg="Could not create subgroup %s for parent group %s in realm %s: %s" % (grouprep['name'], parent_id, realm, str(e))) def update_group(self, grouprep, realm="master"): @@ -1434,7 +1683,7 @@ class KeycloakAPI(object): return open_url(group_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(grouprep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not update group %s in realm %s: %s' + self.fail_open_url(e, msg='Could not update group %s in realm %s: %s' % (grouprep['name'], realm, str(e))) def delete_group(self, name=None, groupid=None, realm="master"): @@ -1471,7 +1720,7 @@ class KeycloakAPI(object): return open_url(group_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg="Unable to delete group %s: %s" % (groupid, str(e))) + self.fail_open_url(e, msg="Unable to delete group %s: %s" % (groupid, str(e))) def get_realm_roles(self, realm='master'): """ Obtains role representations for roles in a realm @@ -1488,7 +1737,7 @@ class KeycloakAPI(object): self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of roles for realm %s: %s' % (realm, str(e))) except Exception as e: - self.module.fail_json(msg='Could not obtain list of roles for realm %s: %s' + self.fail_open_url(e, msg='Could not obtain list of roles for realm %s: %s' % (realm, str(e))) def get_realm_role(self, name, realm='master'): @@ -1498,7 +1747,7 @@ class KeycloakAPI(object): :param name: Name of the role to fetch. :param realm: Realm in which the role resides; default 'master'. """ - role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(name)) + role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(name, safe='')) try: return json.loads(to_native(open_url(role_url, method="GET", http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) @@ -1506,7 +1755,7 @@ class KeycloakAPI(object): if e.code == 404: return None else: - self.module.fail_json(msg='Could not fetch role %s in realm %s: %s' + self.fail_open_url(e, msg='Could not fetch role %s in realm %s: %s' % (name, realm, str(e))) except Exception as e: self.module.fail_json(msg='Could not fetch role %s in realm %s: %s' @@ -1520,10 +1769,13 @@ class KeycloakAPI(object): """ roles_url = URL_REALM_ROLES.format(url=self.baseurl, realm=realm) try: + if "composites" in rolerep: + keycloak_compatible_composites = self.convert_role_composites(rolerep["composites"]) + rolerep["composites"] = keycloak_compatible_composites return open_url(roles_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(rolerep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not create role %s in realm %s: %s' + self.fail_open_url(e, msg='Could not create role %s in realm %s: %s' % (rolerep['name'], realm, str(e))) def update_realm_role(self, rolerep, realm='master'): @@ -1532,26 +1784,138 @@ class KeycloakAPI(object): :param rolerep: A RoleRepresentation of the updated role. :return HTTPResponse object on success """ - role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(rolerep['name'])) + role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(rolerep['name']), safe='') try: - return open_url(role_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, - data=json.dumps(rolerep), validate_certs=self.validate_certs) + composites = None + if "composites" in rolerep: + composites = copy.deepcopy(rolerep["composites"]) + del rolerep["composites"] + role_response = open_url(role_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + data=json.dumps(rolerep), validate_certs=self.validate_certs) + if composites is not None: + self.update_role_composites(rolerep=rolerep, composites=composites, realm=realm) + return role_response except Exception as e: - self.module.fail_json(msg='Could not update role %s in realm %s: %s' + self.fail_open_url(e, msg='Could not update role %s in realm %s: %s' % (rolerep['name'], realm, str(e))) + def get_role_composites(self, rolerep, clientid=None, realm='master'): + composite_url = '' + try: + if clientid is not None: + client = self.get_client_by_clientid(client_id=clientid, realm=realm) + cid = client['id'] + composite_url = URL_CLIENT_ROLE_COMPOSITES.format(url=self.baseurl, realm=realm, id=cid, name=quote(rolerep["name"], safe='')) + else: + composite_url = URL_REALM_ROLE_COMPOSITES.format(url=self.baseurl, realm=realm, name=quote(rolerep["name"], safe='')) + # Get existing composites + return json.loads(to_native(open_url( + composite_url, + method='GET', + http_agent=self.http_agent, + headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs).read())) + except Exception as e: + self.fail_open_url(e, msg='Could not get role %s composites in realm %s: %s' + % (rolerep['name'], realm, str(e))) + + def create_role_composites(self, rolerep, composites, clientid=None, realm='master'): + composite_url = '' + try: + if clientid is not None: + client = self.get_client_by_clientid(client_id=clientid, realm=realm) + cid = client['id'] + composite_url = URL_CLIENT_ROLE_COMPOSITES.format(url=self.baseurl, realm=realm, id=cid, name=quote(rolerep["name"], safe='')) + else: + composite_url = URL_REALM_ROLE_COMPOSITES.format(url=self.baseurl, realm=realm, name=quote(rolerep["name"], safe='')) + # Get existing composites + # create new composites + return open_url(composite_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + data=json.dumps(composites), validate_certs=self.validate_certs) + except Exception as e: + self.fail_open_url(e, msg='Could not create role %s composites in realm %s: %s' + % (rolerep['name'], realm, str(e))) + + def delete_role_composites(self, rolerep, composites, clientid=None, realm='master'): + composite_url = '' + try: + if clientid is not None: + client = self.get_client_by_clientid(client_id=clientid, realm=realm) + cid = client['id'] + composite_url = URL_CLIENT_ROLE_COMPOSITES.format(url=self.baseurl, realm=realm, id=cid, name=quote(rolerep["name"], safe='')) + else: + composite_url = URL_REALM_ROLE_COMPOSITES.format(url=self.baseurl, realm=realm, name=quote(rolerep["name"], safe='')) + # Get existing composites + # create new composites + return open_url(composite_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + data=json.dumps(composites), validate_certs=self.validate_certs) + except Exception as e: + self.fail_open_url(e, msg='Could not create role %s composites in realm %s: %s' + % (rolerep['name'], realm, str(e))) + + def update_role_composites(self, rolerep, composites, clientid=None, realm='master'): + # Get existing composites + existing_composites = self.get_role_composites(rolerep=rolerep, clientid=clientid, realm=realm) + composites_to_be_created = [] + composites_to_be_deleted = [] + for composite in composites: + composite_found = False + existing_composite_client = None + for existing_composite in existing_composites: + if existing_composite["clientRole"]: + existing_composite_client = self.get_client_by_id(existing_composite["containerId"], realm=realm) + if ("client_id" in composite + and composite['client_id'] is not None + and existing_composite_client["clientId"] == composite["client_id"] + and composite["name"] == existing_composite["name"]): + composite_found = True + break + else: + if (("client_id" not in composite or composite['client_id'] is None) + and composite["name"] == existing_composite["name"]): + composite_found = True + break + if (not composite_found and ('state' not in composite or composite['state'] == 'present')): + if "client_id" in composite and composite['client_id'] is not None: + client_roles = self.get_client_roles(clientid=composite['client_id'], realm=realm) + for client_role in client_roles: + if client_role['name'] == composite['name']: + composites_to_be_created.append(client_role) + break + else: + realm_role = self.get_realm_role(name=composite["name"], realm=realm) + composites_to_be_created.append(realm_role) + elif composite_found and 'state' in composite and composite['state'] == 'absent': + if "client_id" in composite and composite['client_id'] is not None: + client_roles = self.get_client_roles(clientid=composite['client_id'], realm=realm) + for client_role in client_roles: + if client_role['name'] == composite['name']: + composites_to_be_deleted.append(client_role) + break + else: + realm_role = self.get_realm_role(name=composite["name"], realm=realm) + composites_to_be_deleted.append(realm_role) + + if len(composites_to_be_created) > 0: + # create new composites + self.create_role_composites(rolerep=rolerep, composites=composites_to_be_created, clientid=clientid, realm=realm) + if len(composites_to_be_deleted) > 0: + # delete new composites + self.delete_role_composites(rolerep=rolerep, composites=composites_to_be_deleted, clientid=clientid, realm=realm) + def delete_realm_role(self, name, realm='master'): """ Delete a realm role. :param name: The name of the role. :param realm: The realm in which this role resides, default "master". """ - role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(name)) + role_url = URL_REALM_ROLE.format(url=self.baseurl, realm=realm, name=quote(name, safe='')) try: return open_url(role_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Unable to delete role %s in realm %s: %s' + self.fail_open_url(e, msg='Unable to delete role %s in realm %s: %s' % (name, realm, str(e))) def get_client_roles(self, clientid, realm='master'): @@ -1574,7 +1938,7 @@ class KeycloakAPI(object): self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of roles for client %s in realm %s: %s' % (clientid, realm, str(e))) except Exception as e: - self.module.fail_json(msg='Could not obtain list of roles for client %s in realm %s: %s' + self.fail_open_url(e, msg='Could not obtain list of roles for client %s in realm %s: %s' % (clientid, realm, str(e))) def get_client_role(self, name, clientid, realm='master'): @@ -1590,7 +1954,7 @@ class KeycloakAPI(object): if cid is None: self.module.fail_json(msg='Could not find client %s in realm %s' % (clientid, realm)) - role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(name)) + role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(name, safe='')) try: return json.loads(to_native(open_url(role_url, method="GET", http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) @@ -1598,7 +1962,7 @@ class KeycloakAPI(object): if e.code == 404: return None else: - self.module.fail_json(msg='Could not fetch role %s in client %s of realm %s: %s' + self.fail_open_url(e, msg='Could not fetch role %s in client %s of realm %s: %s' % (name, clientid, realm, str(e))) except Exception as e: self.module.fail_json(msg='Could not fetch role %s for client %s in realm %s: %s' @@ -1618,12 +1982,30 @@ class KeycloakAPI(object): % (clientid, realm)) roles_url = URL_CLIENT_ROLES.format(url=self.baseurl, realm=realm, id=cid) try: + if "composites" in rolerep: + keycloak_compatible_composites = self.convert_role_composites(rolerep["composites"]) + rolerep["composites"] = keycloak_compatible_composites return open_url(roles_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(rolerep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not create role %s for client %s in realm %s: %s' + self.fail_open_url(e, msg='Could not create role %s for client %s in realm %s: %s' % (rolerep['name'], clientid, realm, str(e))) + def convert_role_composites(self, composites): + keycloak_compatible_composites = { + 'client': {}, + 'realm': [] + } + for composite in composites: + if 'state' not in composite or composite['state'] == 'present': + if "client_id" in composite and composite["client_id"] is not None: + if composite["client_id"] not in keycloak_compatible_composites["client"]: + keycloak_compatible_composites["client"][composite["client_id"]] = [] + keycloak_compatible_composites["client"][composite["client_id"]].append(composite["name"]) + else: + keycloak_compatible_composites["realm"].append(composite["name"]) + return keycloak_compatible_composites + def update_client_role(self, rolerep, clientid, realm="master"): """ Update an existing client role. @@ -1636,12 +2018,19 @@ class KeycloakAPI(object): if cid is None: self.module.fail_json(msg='Could not find client %s in realm %s' % (clientid, realm)) - role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(rolerep['name'])) + role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(rolerep['name'], safe='')) try: - return open_url(role_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, - data=json.dumps(rolerep), validate_certs=self.validate_certs) + composites = None + if "composites" in rolerep: + composites = copy.deepcopy(rolerep["composites"]) + del rolerep['composites'] + update_role_response = open_url(role_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + data=json.dumps(rolerep), validate_certs=self.validate_certs) + if composites is not None: + self.update_role_composites(rolerep=rolerep, clientid=clientid, composites=composites, realm=realm) + return update_role_response except Exception as e: - self.module.fail_json(msg='Could not update role %s for client %s in realm %s: %s' + self.fail_open_url(e, msg='Could not update role %s for client %s in realm %s: %s' % (rolerep['name'], clientid, realm, str(e))) def delete_client_role(self, name, clientid, realm="master"): @@ -1655,12 +2044,12 @@ class KeycloakAPI(object): if cid is None: self.module.fail_json(msg='Could not find client %s in realm %s' % (clientid, realm)) - role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(name)) + role_url = URL_CLIENT_ROLE.format(url=self.baseurl, realm=realm, id=cid, name=quote(name, safe='')) try: return open_url(role_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Unable to delete role %s for client %s in realm %s: %s' + self.fail_open_url(e, msg='Unable to delete role %s for client %s in realm %s: %s' % (name, clientid, realm, str(e))) def get_authentication_flow_by_alias(self, alias, realm='master'): @@ -1682,7 +2071,7 @@ class KeycloakAPI(object): break return authentication_flow except Exception as e: - self.module.fail_json(msg="Unable get authentication flow %s: %s" % (alias, str(e))) + self.fail_open_url(e, msg="Unable get authentication flow %s: %s" % (alias, str(e))) def delete_authentication_flow_by_id(self, id, realm='master'): """ @@ -1697,8 +2086,8 @@ class KeycloakAPI(object): return open_url(flow_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not delete authentication flow %s in realm %s: %s' - % (id, realm, str(e))) + self.fail_open_url(e, msg='Could not delete authentication flow %s in realm %s: %s' + % (id, realm, str(e))) def copy_auth_flow(self, config, realm='master'): """ @@ -1715,7 +2104,7 @@ class KeycloakAPI(object): URL_AUTHENTICATION_FLOW_COPY.format( url=self.baseurl, realm=realm, - copyfrom=quote(config["copyFrom"])), + copyfrom=quote(config["copyFrom"], safe='')), method='POST', http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(new_name), @@ -1734,8 +2123,8 @@ class KeycloakAPI(object): return flow return None except Exception as e: - self.module.fail_json(msg='Could not copy authentication flow %s in realm %s: %s' - % (config["alias"], realm, str(e))) + self.fail_open_url(e, msg='Could not copy authentication flow %s in realm %s: %s' + % (config["alias"], realm, str(e))) def create_empty_auth_flow(self, config, realm='master'): """ @@ -1774,8 +2163,8 @@ class KeycloakAPI(object): return flow return None except Exception as e: - self.module.fail_json(msg='Could not create empty authentication flow %s in realm %s: %s' - % (config["alias"], realm, str(e))) + self.fail_open_url(e, msg='Could not create empty authentication flow %s in realm %s: %s' + % (config["alias"], realm, str(e))) def update_authentication_executions(self, flowAlias, updatedExec, realm='master'): """ Update authentication executions @@ -1789,12 +2178,15 @@ class KeycloakAPI(object): URL_AUTHENTICATION_FLOW_EXECUTIONS.format( url=self.baseurl, realm=realm, - flowalias=quote(flowAlias)), + flowalias=quote(flowAlias, safe='')), method='PUT', http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(updatedExec), timeout=self.connection_timeout, validate_certs=self.validate_certs) + except HTTPError as e: + self.fail_open_url(e, msg="Unable to update execution '%s': %s: %s %s" + % (flowAlias, repr(e), ";".join([e.url, e.msg, str(e.code), str(e.hdrs)]), str(updatedExec))) except Exception as e: self.module.fail_json(msg="Unable to update executions %s: %s" % (updatedExec, str(e))) @@ -1817,9 +2209,9 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg="Unable to add authenticationConfig %s: %s" % (executionId, str(e))) + self.fail_open_url(e, msg="Unable to add authenticationConfig %s: %s" % (executionId, str(e))) - def create_subflow(self, subflowName, flowAlias, realm='master'): + def create_subflow(self, subflowName, flowAlias, realm='master', flowType='basic-flow'): """ Create new sublow on the flow :param subflowName: name of the subflow to create @@ -1830,19 +2222,19 @@ class KeycloakAPI(object): newSubFlow = {} newSubFlow["alias"] = subflowName newSubFlow["provider"] = "registration-page-form" - newSubFlow["type"] = "basic-flow" + newSubFlow["type"] = flowType open_url( URL_AUTHENTICATION_FLOW_EXECUTIONS_FLOW.format( url=self.baseurl, realm=realm, - flowalias=quote(flowAlias)), + flowalias=quote(flowAlias, safe='')), method='POST', http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(newSubFlow), timeout=self.connection_timeout, validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg="Unable to create new subflow %s: %s" % (subflowName, str(e))) + self.fail_open_url(e, msg="Unable to create new subflow %s: %s" % (subflowName, str(e))) def create_execution(self, execution, flowAlias, realm='master'): """ Create new execution on the flow @@ -1859,14 +2251,17 @@ class KeycloakAPI(object): URL_AUTHENTICATION_FLOW_EXECUTIONS_EXECUTION.format( url=self.baseurl, realm=realm, - flowalias=quote(flowAlias)), + flowalias=quote(flowAlias, safe='')), method='POST', http_agent=self.http_agent, headers=self.restheaders, data=json.dumps(newExec), timeout=self.connection_timeout, validate_certs=self.validate_certs) + except HTTPError as e: + self.fail_open_url(e, msg="Unable to create new execution '%s' %s: %s: %s %s" + % (flowAlias, execution["providerId"], repr(e), ";".join([e.url, e.msg, str(e.code), str(e.hdrs)]), str(newExec))) except Exception as e: - self.module.fail_json(msg="Unable to create new execution %s: %s" % (execution["provider"], str(e))) + self.module.fail_json(msg="Unable to create new execution '%s' %s: %s" % (flowAlias, execution["providerId"], repr(e))) def change_execution_priority(self, executionId, diff, realm='master'): """ Raise or lower execution priority of diff time @@ -1900,7 +2295,7 @@ class KeycloakAPI(object): timeout=self.connection_timeout, validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg="Unable to change execution priority %s: %s" % (executionId, str(e))) + self.fail_open_url(e, msg="Unable to change execution priority %s: %s" % (executionId, str(e))) def get_executions_representation(self, config, realm='master'): """ @@ -1916,7 +2311,7 @@ class KeycloakAPI(object): URL_AUTHENTICATION_FLOW_EXECUTIONS.format( url=self.baseurl, realm=realm, - flowalias=quote(config["alias"])), + flowalias=quote(config["alias"], safe='')), method='GET', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, @@ -1937,8 +2332,121 @@ class KeycloakAPI(object): execution["authenticationConfig"] = execConfig return executions except Exception as e: - self.module.fail_json(msg='Could not get executions for authentication flow %s in realm %s: %s' - % (config["alias"], realm, str(e))) + self.fail_open_url(e, msg='Could not get executions for authentication flow %s in realm %s: %s' + % (config["alias"], realm, str(e))) + + def get_required_actions(self, realm='master'): + """ + Get required actions. + :param realm: Realm name (not id). + :return: List of representations of the required actions. + """ + + try: + required_actions = json.load( + open_url( + URL_AUTHENTICATION_REQUIRED_ACTIONS.format( + url=self.baseurl, + realm=realm + ), + method='GET', + http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs + ) + ) + + return required_actions + except Exception: + return None + + def register_required_action(self, rep, realm='master'): + """ + Register required action. + :param rep: JSON containing 'providerId', and 'name' attributes. + :param realm: Realm name (not id). + :return: Representation of the required action. + """ + + data = { + 'name': rep['name'], + 'providerId': rep['providerId'] + } + + try: + return open_url( + URL_AUTHENTICATION_REGISTER_REQUIRED_ACTION.format( + url=self.baseurl, + realm=realm + ), + method='POST', + http_agent=self.http_agent, headers=self.restheaders, + data=json.dumps(data), + timeout=self.connection_timeout, + validate_certs=self.validate_certs + ) + except Exception as e: + self.fail_open_url( + e, + msg='Unable to register required action %s in realm %s: %s' + % (rep["name"], realm, str(e)) + ) + + def update_required_action(self, alias, rep, realm='master'): + """ + Update required action. + :param alias: Alias of required action. + :param rep: JSON describing new state of required action. + :param realm: Realm name (not id). + :return: HTTPResponse object on success. + """ + + try: + return open_url( + URL_AUTHENTICATION_REQUIRED_ACTIONS_ALIAS.format( + url=self.baseurl, + alias=quote(alias, safe=''), + realm=realm + ), + method='PUT', + http_agent=self.http_agent, headers=self.restheaders, + data=json.dumps(rep), + timeout=self.connection_timeout, + validate_certs=self.validate_certs + ) + except Exception as e: + self.fail_open_url( + e, + msg='Unable to update required action %s in realm %s: %s' + % (alias, realm, str(e)) + ) + + def delete_required_action(self, alias, realm='master'): + """ + Delete required action. + :param alias: Alias of required action. + :param realm: Realm name (not id). + :return: HTTPResponse object on success. + """ + + try: + return open_url( + URL_AUTHENTICATION_REQUIRED_ACTIONS_ALIAS.format( + url=self.baseurl, + alias=quote(alias, safe=''), + realm=realm + ), + method='DELETE', + http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs + ) + except Exception as e: + self.fail_open_url( + e, + msg='Unable to delete required action %s in realm %s: %s' + % (alias, realm, str(e)) + ) def get_identity_providers(self, realm='master'): """ Fetch representations for identity providers in a realm @@ -1953,7 +2461,7 @@ class KeycloakAPI(object): self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of identity providers for realm %s: %s' % (realm, str(e))) except Exception as e: - self.module.fail_json(msg='Could not obtain list of identity providers for realm %s: %s' + self.fail_open_url(e, msg='Could not obtain list of identity providers for realm %s: %s' % (realm, str(e))) def get_identity_provider(self, alias, realm='master'): @@ -1970,7 +2478,7 @@ class KeycloakAPI(object): if e.code == 404: return None else: - self.module.fail_json(msg='Could not fetch identity provider %s in realm %s: %s' + self.fail_open_url(e, msg='Could not fetch identity provider %s in realm %s: %s' % (alias, realm, str(e))) except Exception as e: self.module.fail_json(msg='Could not fetch identity provider %s in realm %s: %s' @@ -1987,7 +2495,7 @@ class KeycloakAPI(object): return open_url(idps_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(idprep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not create identity provider %s in realm %s: %s' + self.fail_open_url(e, msg='Could not create identity provider %s in realm %s: %s' % (idprep['alias'], realm, str(e))) def update_identity_provider(self, idprep, realm='master'): @@ -2001,7 +2509,7 @@ class KeycloakAPI(object): return open_url(idp_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(idprep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not update identity provider %s in realm %s: %s' + self.fail_open_url(e, msg='Could not update identity provider %s in realm %s: %s' % (idprep['alias'], realm, str(e))) def delete_identity_provider(self, alias, realm='master'): @@ -2014,7 +2522,7 @@ class KeycloakAPI(object): return open_url(idp_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Unable to delete identity provider %s in realm %s: %s' + self.fail_open_url(e, msg='Unable to delete identity provider %s in realm %s: %s' % (alias, realm, str(e))) def get_identity_provider_mappers(self, alias, realm='master'): @@ -2032,7 +2540,7 @@ class KeycloakAPI(object): self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of identity provider mappers for idp %s in realm %s: %s' % (alias, realm, str(e))) except Exception as e: - self.module.fail_json(msg='Could not obtain list of identity provider mappers for idp %s in realm %s: %s' + self.fail_open_url(e, msg='Could not obtain list of identity provider mappers for idp %s in realm %s: %s' % (alias, realm, str(e))) def get_identity_provider_mapper(self, mid, alias, realm='master'): @@ -2051,7 +2559,7 @@ class KeycloakAPI(object): if e.code == 404: return None else: - self.module.fail_json(msg='Could not fetch mapper %s for identity provider %s in realm %s: %s' + self.fail_open_url(e, msg='Could not fetch mapper %s for identity provider %s in realm %s: %s' % (mid, alias, realm, str(e))) except Exception as e: self.module.fail_json(msg='Could not fetch mapper %s for identity provider %s in realm %s: %s' @@ -2069,7 +2577,7 @@ class KeycloakAPI(object): return open_url(mappers_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(mapper), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not create identity provider mapper %s for idp %s in realm %s: %s' + self.fail_open_url(e, msg='Could not create identity provider mapper %s for idp %s in realm %s: %s' % (mapper['name'], alias, realm, str(e))) def update_identity_provider_mapper(self, mapper, alias, realm='master'): @@ -2084,7 +2592,7 @@ class KeycloakAPI(object): return open_url(mapper_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(mapper), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not update mapper %s for identity provider %s in realm %s: %s' + self.fail_open_url(e, msg='Could not update mapper %s for identity provider %s in realm %s: %s' % (mapper['id'], alias, realm, str(e))) def delete_identity_provider_mapper(self, mid, alias, realm='master'): @@ -2098,7 +2606,7 @@ class KeycloakAPI(object): return open_url(mapper_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Unable to delete mapper %s for identity provider %s in realm %s: %s' + self.fail_open_url(e, msg='Unable to delete mapper %s for identity provider %s in realm %s: %s' % (mid, alias, realm, str(e))) def get_components(self, filter=None, realm='master'): @@ -2118,7 +2626,7 @@ class KeycloakAPI(object): self.module.fail_json(msg='API returned incorrect JSON when trying to obtain list of components for realm %s: %s' % (realm, str(e))) except Exception as e: - self.module.fail_json(msg='Could not obtain list of components for realm %s: %s' + self.fail_open_url(e, msg='Could not obtain list of components for realm %s: %s' % (realm, str(e))) def get_component(self, cid, realm='master'): @@ -2135,7 +2643,7 @@ class KeycloakAPI(object): if e.code == 404: return None else: - self.module.fail_json(msg='Could not fetch component %s in realm %s: %s' + self.fail_open_url(e, msg='Could not fetch component %s in realm %s: %s' % (cid, realm, str(e))) except Exception as e: self.module.fail_json(msg='Could not fetch component %s in realm %s: %s' @@ -2158,7 +2666,7 @@ class KeycloakAPI(object): return json.loads(to_native(open_url(comp_url, method="GET", http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs).read())) except Exception as e: - self.module.fail_json(msg='Could not create component in realm %s: %s' + self.fail_open_url(e, msg='Could not create component in realm %s: %s' % (realm, str(e))) def update_component(self, comprep, realm='master'): @@ -2175,7 +2683,7 @@ class KeycloakAPI(object): return open_url(comp_url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, data=json.dumps(comprep), validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Could not update component %s in realm %s: %s' + self.fail_open_url(e, msg='Could not update component %s in realm %s: %s' % (cid, realm, str(e))) def delete_component(self, cid, realm='master'): @@ -2188,5 +2696,496 @@ class KeycloakAPI(object): return open_url(comp_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, validate_certs=self.validate_certs) except Exception as e: - self.module.fail_json(msg='Unable to delete component %s in realm %s: %s' + self.fail_open_url(e, msg='Unable to delete component %s in realm %s: %s' % (cid, realm, str(e))) + + def get_authz_authorization_scope_by_name(self, name, client_id, realm): + url = URL_AUTHZ_AUTHORIZATION_SCOPES.format(url=self.baseurl, client_id=client_id, realm=realm) + search_url = "%s/search?name=%s" % (url, quote(name, safe='')) + + try: + return json.loads(to_native(open_url(search_url, method='GET', http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs).read())) + except Exception: + return False + + def create_authz_authorization_scope(self, payload, client_id, realm): + """Create an authorization scope for a Keycloak client""" + url = URL_AUTHZ_AUTHORIZATION_SCOPES.format(url=self.baseurl, client_id=client_id, realm=realm) + + try: + return open_url(url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + data=json.dumps(payload), validate_certs=self.validate_certs) + except Exception as e: + self.fail_open_url(e, msg='Could not create authorization scope %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e))) + + def update_authz_authorization_scope(self, payload, id, client_id, realm): + """Update an authorization scope for a Keycloak client""" + url = URL_AUTHZ_AUTHORIZATION_SCOPE.format(url=self.baseurl, id=id, client_id=client_id, realm=realm) + + try: + return open_url(url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + data=json.dumps(payload), validate_certs=self.validate_certs) + except Exception as e: + self.fail_open_url(e, msg='Could not create update scope %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e))) + + def remove_authz_authorization_scope(self, id, client_id, realm): + """Remove an authorization scope from a Keycloak client""" + url = URL_AUTHZ_AUTHORIZATION_SCOPE.format(url=self.baseurl, id=id, client_id=client_id, realm=realm) + + try: + return open_url(url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + validate_certs=self.validate_certs) + except Exception as e: + self.fail_open_url(e, msg='Could not delete scope %s for client %s in realm %s: %s' % (id, client_id, realm, str(e))) + + def get_user_by_id(self, user_id, realm='master'): + """ + Get a User by its ID. + :param user_id: ID of the user. + :param realm: Realm + :return: Representation of the user. + """ + try: + user_url = URL_USER.format( + url=self.baseurl, + realm=realm, + id=user_id) + userrep = json.load( + open_url( + user_url, + method='GET', + http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs)) + return userrep + except Exception as e: + self.fail_open_url(e, msg='Could not get user %s in realm %s: %s' + % (user_id, realm, str(e))) + + def create_user(self, userrep, realm='master'): + """ + Create a new User. + :param userrep: Representation of the user to create + :param realm: Realm + :return: Representation of the user created. + """ + try: + if 'attributes' in userrep and isinstance(userrep['attributes'], list): + attributes = copy.deepcopy(userrep['attributes']) + userrep['attributes'] = self.convert_user_attributes_to_keycloak_dict(attributes=attributes) + users_url = URL_USERS.format( + url=self.baseurl, + realm=realm) + open_url(users_url, + method='POST', + http_agent=self.http_agent, headers=self.restheaders, + data=json.dumps(userrep), + timeout=self.connection_timeout, + validate_certs=self.validate_certs) + created_user = self.get_user_by_username( + username=userrep['username'], + realm=realm) + return created_user + except Exception as e: + self.fail_open_url(e, msg='Could not create user %s in realm %s: %s' + % (userrep['username'], realm, str(e))) + + def convert_user_attributes_to_keycloak_dict(self, attributes): + keycloak_user_attributes_dict = {} + for attribute in attributes: + if ('state' not in attribute or attribute['state'] == 'present') and 'name' in attribute: + keycloak_user_attributes_dict[attribute['name']] = attribute['values'] if 'values' in attribute else [] + return keycloak_user_attributes_dict + + def convert_keycloak_user_attributes_dict_to_module_list(self, attributes): + module_attributes_list = [] + for key in attributes: + attr = {} + attr['name'] = key + attr['values'] = attributes[key] + module_attributes_list.append(attr) + return module_attributes_list + + def update_user(self, userrep, realm='master'): + """ + Update a User. + :param userrep: Representation of the user to update. This representation must include the ID of the user. + :param realm: Realm + :return: Representation of the updated user. + """ + try: + if 'attributes' in userrep and isinstance(userrep['attributes'], list): + attributes = copy.deepcopy(userrep['attributes']) + userrep['attributes'] = self.convert_user_attributes_to_keycloak_dict(attributes=attributes) + user_url = URL_USER.format( + url=self.baseurl, + realm=realm, + id=userrep["id"]) + open_url( + user_url, + method='PUT', + http_agent=self.http_agent, headers=self.restheaders, + data=json.dumps(userrep), + timeout=self.connection_timeout, + validate_certs=self.validate_certs) + updated_user = self.get_user_by_id( + user_id=userrep['id'], + realm=realm) + return updated_user + except Exception as e: + self.fail_open_url(e, msg='Could not update user %s in realm %s: %s' + % (userrep['username'], realm, str(e))) + + def delete_user(self, user_id, realm='master'): + """ + Delete a User. + :param user_id: ID of the user to be deleted + :param realm: Realm + :return: HTTP response. + """ + try: + user_url = URL_USER.format( + url=self.baseurl, + realm=realm, + id=user_id) + return open_url( + user_url, + method='DELETE', + http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs) + except Exception as e: + self.fail_open_url(e, msg='Could not delete user %s in realm %s: %s' + % (user_id, realm, str(e))) + + def get_user_groups(self, user_id, realm='master'): + """ + Get groups for a user. + :param user_id: User ID + :param realm: Realm + :return: Representation of the client groups. + """ + try: + groups = [] + user_groups_url = URL_USER_GROUPS.format( + url=self.baseurl, + realm=realm, + id=user_id) + user_groups = json.load( + open_url( + user_groups_url, + method='GET', + http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs)) + for user_group in user_groups: + groups.append(user_group["name"]) + return groups + except Exception as e: + self.fail_open_url(e, msg='Could not get groups for user %s in realm %s: %s' + % (user_id, realm, str(e))) + + def add_user_in_group(self, user_id, group_id, realm='master'): + """ + Add a user to a group. + :param user_id: User ID + :param group_id: Group Id to add the user to. + :param realm: Realm + :return: HTTP Response + """ + try: + user_group_url = URL_USER_GROUP.format( + url=self.baseurl, + realm=realm, + id=user_id, + group_id=group_id) + return open_url( + user_group_url, + method='PUT', + http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs) + except Exception as e: + self.fail_open_url(e, msg='Could not add user %s in group %s in realm %s: %s' + % (user_id, group_id, realm, str(e))) + + def remove_user_from_group(self, user_id, group_id, realm='master'): + """ + Remove a user from a group for a user. + :param user_id: User ID + :param group_id: Group Id to add the user to. + :param realm: Realm + :return: HTTP response + """ + try: + user_group_url = URL_USER_GROUP.format( + url=self.baseurl, + realm=realm, + id=user_id, + group_id=group_id) + return open_url( + user_group_url, + method='DELETE', + http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs) + except Exception as e: + self.fail_open_url(e, msg='Could not remove user %s from group %s in realm %s: %s' + % (user_id, group_id, realm, str(e))) + + def update_user_groups_membership(self, userrep, groups, realm='master'): + """ + Update user's group membership + :param userrep: Representation of the user. This representation must include the ID. + :param realm: Realm + :return: True if group membership has been changed. False Otherwise. + """ + changed = False + try: + user_existing_groups = self.get_user_groups( + user_id=userrep['id'], + realm=realm) + groups_to_add_and_remove = self.extract_groups_to_add_to_and_remove_from_user(groups) + # If group membership need to be changed + if not is_struct_included(groups_to_add_and_remove['add'], user_existing_groups): + # Get available groups in the realm + realm_groups = self.get_groups(realm=realm) + for realm_group in realm_groups: + if "name" in realm_group and realm_group["name"] in groups_to_add_and_remove['add']: + self.add_user_in_group( + user_id=userrep["id"], + group_id=realm_group["id"], + realm=realm) + changed = True + elif "name" in realm_group and realm_group['name'] in groups_to_add_and_remove['remove']: + self.remove_user_from_group( + user_id=userrep['id'], + group_id=realm_group['id'], + realm=realm) + changed = True + return changed + except Exception as e: + self.module.fail_json(msg='Could not update group membership for user %s in realm %s: %s' + % (userrep['id]'], realm, str(e))) + + def extract_groups_to_add_to_and_remove_from_user(self, groups): + groups_extract = {} + groups_to_add = [] + groups_to_remove = [] + if isinstance(groups, list) and len(groups) > 0: + for group in groups: + group_name = group['name'] if isinstance(group, dict) and 'name' in group else group + if isinstance(group, dict) and ('state' not in group or group['state'] == 'present'): + groups_to_add.append(group_name) + else: + groups_to_remove.append(group_name) + groups_extract['add'] = groups_to_add + groups_extract['remove'] = groups_to_remove + + return groups_extract + + def convert_user_group_list_of_str_to_list_of_dict(self, groups): + list_of_groups = [] + if isinstance(groups, list) and len(groups) > 0: + for group in groups: + if isinstance(group, str): + group_dict = {} + group_dict['name'] = group + list_of_groups.append(group_dict) + return list_of_groups + + def create_authz_custom_policy(self, policy_type, payload, client_id, realm): + """Create a custom policy for a Keycloak client""" + url = URL_AUTHZ_CUSTOM_POLICY.format(url=self.baseurl, policy_type=policy_type, client_id=client_id, realm=realm) + + try: + return open_url(url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + data=json.dumps(payload), validate_certs=self.validate_certs) + except Exception as e: + self.fail_open_url(e, msg='Could not create permission %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e))) + + def remove_authz_custom_policy(self, policy_id, client_id, realm): + """Remove a custom policy from a Keycloak client""" + url = URL_AUTHZ_CUSTOM_POLICIES.format(url=self.baseurl, client_id=client_id, realm=realm) + delete_url = "%s/%s" % (url, policy_id) + + try: + return open_url(delete_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + validate_certs=self.validate_certs) + except Exception as e: + self.fail_open_url(e, msg='Could not delete custom policy %s for client %s in realm %s: %s' % (id, client_id, realm, str(e))) + + def get_authz_permission_by_name(self, name, client_id, realm): + """Get authorization permission by name""" + url = URL_AUTHZ_POLICIES.format(url=self.baseurl, client_id=client_id, realm=realm) + search_url = "%s/search?name=%s" % (url, name.replace(' ', '%20')) + + try: + return json.loads(to_native(open_url(search_url, method='GET', http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs).read())) + except Exception: + return False + + def create_authz_permission(self, payload, permission_type, client_id, realm): + """Create an authorization permission for a Keycloak client""" + url = URL_AUTHZ_PERMISSIONS.format(url=self.baseurl, permission_type=permission_type, client_id=client_id, realm=realm) + + try: + return open_url(url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + data=json.dumps(payload), validate_certs=self.validate_certs) + except Exception as e: + self.fail_open_url(e, msg='Could not create permission %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e))) + + def remove_authz_permission(self, id, client_id, realm): + """Create an authorization permission for a Keycloak client""" + url = URL_AUTHZ_POLICY.format(url=self.baseurl, id=id, client_id=client_id, realm=realm) + + try: + return open_url(url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + validate_certs=self.validate_certs) + except Exception as e: + self.fail_open_url(e, msg='Could not delete permission %s for client %s in realm %s: %s' % (id, client_id, realm, str(e))) + + def update_authz_permission(self, payload, permission_type, id, client_id, realm): + """Update a permission for a Keycloak client""" + url = URL_AUTHZ_PERMISSION.format(url=self.baseurl, permission_type=permission_type, id=id, client_id=client_id, realm=realm) + + try: + return open_url(url, method='PUT', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + data=json.dumps(payload), validate_certs=self.validate_certs) + except Exception as e: + self.fail_open_url(e, msg='Could not create update permission %s for client %s in realm %s: %s' % (payload['name'], client_id, realm, str(e))) + + def get_authz_resource_by_name(self, name, client_id, realm): + """Get authorization resource by name""" + url = URL_AUTHZ_RESOURCES.format(url=self.baseurl, client_id=client_id, realm=realm) + search_url = "%s/search?name=%s" % (url, name.replace(' ', '%20')) + + try: + return json.loads(to_native(open_url(search_url, method='GET', http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs).read())) + except Exception: + return False + + def get_authz_policy_by_name(self, name, client_id, realm): + """Get authorization policy by name""" + url = URL_AUTHZ_POLICIES.format(url=self.baseurl, client_id=client_id, realm=realm) + search_url = "%s/search?name=%s&permission=false" % (url, name.replace(' ', '%20')) + + try: + return json.loads(to_native(open_url(search_url, method='GET', http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs).read())) + except Exception: + return False + + def get_client_role_scope_from_client(self, clientid, clientscopeid, realm="master"): + """ Fetch the roles associated with the client's scope for a specific client on the Keycloak server. + :param clientid: ID of the client from which to obtain the associated roles. + :param clientscopeid: ID of the client who owns the roles. + :param realm: Realm from which to obtain the scope. + :return: The client scope of roles from specified client. + """ + client_role_scope_url = URL_CLIENT_ROLE_SCOPE_CLIENTS.format(url=self.baseurl, realm=realm, id=clientid, scopeid=clientscopeid) + try: + return json.loads(to_native(open_url(client_role_scope_url, method='GET', http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs).read())) + except Exception as e: + self.fail_open_url(e, msg='Could not fetch roles scope for client %s in realm %s: %s' % (clientid, realm, str(e))) + + def update_client_role_scope_from_client(self, payload, clientid, clientscopeid, realm="master"): + """ Update and fetch the roles associated with the client's scope on the Keycloak server. + :param payload: List of roles to be added to the scope. + :param clientid: ID of the client to update scope. + :param clientscopeid: ID of the client who owns the roles. + :param realm: Realm from which to obtain the clients. + :return: The client scope of roles from specified client. + """ + client_role_scope_url = URL_CLIENT_ROLE_SCOPE_CLIENTS.format(url=self.baseurl, realm=realm, id=clientid, scopeid=clientscopeid) + try: + open_url(client_role_scope_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + data=json.dumps(payload), validate_certs=self.validate_certs) + + except Exception as e: + self.fail_open_url(e, msg='Could not update roles scope for client %s in realm %s: %s' % (clientid, realm, str(e))) + + return self.get_client_role_scope_from_client(clientid, clientscopeid, realm) + + def delete_client_role_scope_from_client(self, payload, clientid, clientscopeid, realm="master"): + """ Delete the roles contains in the payload from the client's scope on the Keycloak server. + :param payload: List of roles to be deleted. + :param clientid: ID of the client to delete roles from scope. + :param clientscopeid: ID of the client who owns the roles. + :param realm: Realm from which to obtain the clients. + :return: The client scope of roles from specified client. + """ + client_role_scope_url = URL_CLIENT_ROLE_SCOPE_CLIENTS.format(url=self.baseurl, realm=realm, id=clientid, scopeid=clientscopeid) + try: + open_url(client_role_scope_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + data=json.dumps(payload), validate_certs=self.validate_certs) + + except Exception as e: + self.fail_open_url(e, msg='Could not delete roles scope for client %s in realm %s: %s' % (clientid, realm, str(e))) + + return self.get_client_role_scope_from_client(clientid, clientscopeid, realm) + + def get_client_role_scope_from_realm(self, clientid, realm="master"): + """ Fetch the realm roles from the client's scope on the Keycloak server. + :param clientid: ID of the client from which to obtain the associated realm roles. + :param realm: Realm from which to obtain the clients. + :return: The client realm roles scope. + """ + client_role_scope_url = URL_CLIENT_ROLE_SCOPE_REALM.format(url=self.baseurl, realm=realm, id=clientid) + try: + return json.loads(to_native(open_url(client_role_scope_url, method='GET', http_agent=self.http_agent, headers=self.restheaders, + timeout=self.connection_timeout, + validate_certs=self.validate_certs).read())) + except Exception as e: + self.fail_open_url(e, msg='Could not fetch roles scope for client %s in realm %s: %s' % (clientid, realm, str(e))) + + def update_client_role_scope_from_realm(self, payload, clientid, realm="master"): + """ Update and fetch the realm roles from the client's scope on the Keycloak server. + :param payload: List of realm roles to add. + :param clientid: ID of the client to update scope. + :param realm: Realm from which to obtain the clients. + :return: The client realm roles scope. + """ + client_role_scope_url = URL_CLIENT_ROLE_SCOPE_REALM.format(url=self.baseurl, realm=realm, id=clientid) + try: + open_url(client_role_scope_url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + data=json.dumps(payload), validate_certs=self.validate_certs) + + except Exception as e: + self.fail_open_url(e, msg='Could not update roles scope for client %s in realm %s: %s' % (clientid, realm, str(e))) + + return self.get_client_role_scope_from_realm(clientid, realm) + + def delete_client_role_scope_from_realm(self, payload, clientid, realm="master"): + """ Delete the realm roles contains in the payload from the client's scope on the Keycloak server. + :param payload: List of realm roles to delete. + :param clientid: ID of the client to delete roles from scope. + :param realm: Realm from which to obtain the clients. + :return: The client realm roles scope. + """ + client_role_scope_url = URL_CLIENT_ROLE_SCOPE_REALM.format(url=self.baseurl, realm=realm, id=clientid) + try: + open_url(client_role_scope_url, method='DELETE', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout, + data=json.dumps(payload), validate_certs=self.validate_certs) + + except Exception as e: + self.fail_open_url(e, msg='Could not delete roles scope for client %s in realm %s: %s' % (clientid, realm, str(e))) + + return self.get_client_role_scope_from_realm(clientid, realm) + + def fail_open_url(self, e, msg, **kwargs): + try: + if isinstance(e, HTTPError): + msg = "%s: %s" % (msg, to_native(e.read())) + except Exception as ingore: + pass + self.module.fail_json(msg, **kwargs) diff --git a/plugins/modules/keycloak_client.py b/plugins/modules/keycloak_client.py index dc824ca..0afa52b 100644 --- a/plugins/modules/keycloak_client.py +++ b/plugins/modules/keycloak_client.py @@ -40,8 +40,8 @@ options: state: description: - State of the client - - On C(present), the client will be created (or updated if it exists already). - - On C(absent), the client will be removed if it exists + - On V(present), the client will be created (or updated if it exists already). + - On V(absent), the client will be removed if it exists choices: ['present', 'absent'] default: 'present' type: str @@ -55,7 +55,7 @@ options: client_id: description: - Client id of client to be worked on. This is usually an alphanumeric name chosen by - you. Either this or I(id) is required. If you specify both, I(id) takes precedence. + you. Either this or O(id) is required. If you specify both, O(id) takes precedence. This is 'clientId' in the Keycloak REST API. aliases: - clientId @@ -63,13 +63,13 @@ options: id: description: - - Id of client to be worked on. This is usually an UUID. Either this or I(client_id) + - Id of client to be worked on. This is usually an UUID. Either this or O(client_id) is required. If you specify both, this takes precedence. type: str name: description: - - Name of the client (this is not the same as I(client_id)). + - Name of the client (this is not the same as O(client_id)). type: str description: @@ -108,20 +108,21 @@ options: client_authenticator_type: description: - - How do clients authenticate with the auth server? Either C(client-secret) or - C(client-jwt) can be chosen. When using C(client-secret), the module parameter - I(secret) can set it, while for C(client-jwt), you can use the keys C(use.jwks.url), - C(jwks.url), and C(jwt.credential.certificate) in the I(attributes) module parameter - to configure its behavior. - This is 'clientAuthenticatorType' in the Keycloak REST API. - choices: ['client-secret', 'client-jwt'] + - How do clients authenticate with the auth server? Either V(client-secret), + V(client-jwt), or V(client-x509) can be chosen. When using V(client-secret), the module parameter + O(secret) can set it, for V(client-jwt), you can use the keys C(use.jwks.url), + C(jwks.url), and C(jwt.credential.certificate) in the O(attributes) module parameter + to configure its behavior. For V(client-x509) you can use the keys C(x509.allow.regex.pattern.comparison) + and C(x509.subjectdn) in the O(attributes) module parameter to configure which certificate(s) to accept. + - This is 'clientAuthenticatorType' in the Keycloak REST API. + choices: ['client-secret', 'client-jwt', 'client-x509'] aliases: - clientAuthenticatorType type: str secret: description: - - When using I(client_authenticator_type) C(client-secret) (the default), you can + - When using O(client_authenticator_type=client-secret) (the default), you can specify a secret here (otherwise one will be generated if it does not exit). If changing this secret, the module will not register a change currently (but the changed secret will be saved). @@ -246,9 +247,11 @@ options: protocol: description: - - Type of client (either C(openid-connect) or C(saml). + - Type of client. + - At creation only, default value will be V(openid-connect) if O(protocol) is omitted. + - The V(docker-v2) value was added in community.general 8.6.0. type: str - choices: ['openid-connect', 'saml'] + choices: ['openid-connect', 'saml', 'docker-v2'] full_scope_allowed: description: @@ -286,7 +289,7 @@ options: use_template_config: description: - - Whether or not to use configuration from the I(client_template). + - Whether or not to use configuration from the O(client_template). This is 'useTemplateConfig' in the Keycloak REST API. aliases: - useTemplateConfig @@ -294,7 +297,7 @@ options: use_template_scope: description: - - Whether or not to use scope configuration from the I(client_template). + - Whether or not to use scope configuration from the O(client_template). This is 'useTemplateScope' in the Keycloak REST API. aliases: - useTemplateScope @@ -302,7 +305,7 @@ options: use_template_mappers: description: - - Whether or not to use mapper configuration from the I(client_template). + - Whether or not to use mapper configuration from the O(client_template). This is 'useTemplateMappers' in the Keycloak REST API. aliases: - useTemplateMappers @@ -338,6 +341,42 @@ options: description: - Override realm authentication flow bindings. type: dict + suboptions: + browser: + description: + - Flow ID of the browser authentication flow. + - O(authentication_flow_binding_overrides.browser) + and O(authentication_flow_binding_overrides.browser_name) are mutually exclusive. + type: str + + browser_name: + description: + - Flow name of the browser authentication flow. + - O(authentication_flow_binding_overrides.browser) + and O(authentication_flow_binding_overrides.browser_name) are mutually exclusive. + aliases: + - browserName + type: str + version_added: 9.1.0 + + direct_grant: + description: + - Flow ID of the direct grant authentication flow. + - O(authentication_flow_binding_overrides.direct_grant) + and O(authentication_flow_binding_overrides.direct_grant_name) are mutually exclusive. + aliases: + - directGrant + type: str + + direct_grant_name: + description: + - Flow name of the direct grant authentication flow. + - O(authentication_flow_binding_overrides.direct_grant) + and O(authentication_flow_binding_overrides.direct_grant_name) are mutually exclusive. + aliases: + - directGrantName + type: str + version_added: 9.1.0 aliases: - authenticationFlowBindingOverrides version_added: 3.4.0 @@ -391,38 +430,37 @@ options: protocol: description: - - This is either C(openid-connect) or C(saml), this specifies for which protocol this protocol mapper. - is active. - choices: ['openid-connect', 'saml'] + - This specifies for which protocol this protocol mapper is active. + choices: ['openid-connect', 'saml', 'docker-v2'] type: str protocolMapper: description: - - The Keycloak-internal name of the type of this protocol-mapper. While an exhaustive list is + - "The Keycloak-internal name of the type of this protocol-mapper. While an exhaustive list is impossible to provide since this may be extended through SPIs by the user of Keycloak, - by default Keycloak as of 3.4 ships with at least - - C(docker-v2-allow-all-mapper) - - C(oidc-address-mapper) - - C(oidc-full-name-mapper) - - C(oidc-group-membership-mapper) - - C(oidc-hardcoded-claim-mapper) - - C(oidc-hardcoded-role-mapper) - - C(oidc-role-name-mapper) - - C(oidc-script-based-protocol-mapper) - - C(oidc-sha256-pairwise-sub-mapper) - - C(oidc-usermodel-attribute-mapper) - - C(oidc-usermodel-client-role-mapper) - - C(oidc-usermodel-property-mapper) - - C(oidc-usermodel-realm-role-mapper) - - C(oidc-usersessionmodel-note-mapper) - - C(saml-group-membership-mapper) - - C(saml-hardcode-attribute-mapper) - - C(saml-hardcode-role-mapper) - - C(saml-role-list-mapper) - - C(saml-role-name-mapper) - - C(saml-user-attribute-mapper) - - C(saml-user-property-mapper) - - C(saml-user-session-note-mapper) + by default Keycloak as of 3.4 ships with at least:" + - V(docker-v2-allow-all-mapper) + - V(oidc-address-mapper) + - V(oidc-full-name-mapper) + - V(oidc-group-membership-mapper) + - V(oidc-hardcoded-claim-mapper) + - V(oidc-hardcoded-role-mapper) + - V(oidc-role-name-mapper) + - V(oidc-script-based-protocol-mapper) + - V(oidc-sha256-pairwise-sub-mapper) + - V(oidc-usermodel-attribute-mapper) + - V(oidc-usermodel-client-role-mapper) + - V(oidc-usermodel-property-mapper) + - V(oidc-usermodel-realm-role-mapper) + - V(oidc-usersessionmodel-note-mapper) + - V(saml-group-membership-mapper) + - V(saml-hardcode-attribute-mapper) + - V(saml-hardcode-role-mapper) + - V(saml-role-list-mapper) + - V(saml-role-name-mapper) + - V(saml-user-attribute-mapper) + - V(saml-user-property-mapper) + - V(saml-user-session-note-mapper) - An exhaustive list of available mappers on your installation can be obtained on the admin console by going to Server Info -> Providers and looking under 'protocol-mapper'. @@ -431,10 +469,10 @@ options: config: description: - Dict specifying the configuration options for the protocol mapper; the - contents differ depending on the value of I(protocolMapper) and are not documented + contents differ depending on the value of O(protocol_mappers[].protocolMapper) and are not documented other than by the source of the mappers and its parent class(es). An example is given below. It is easiest to obtain valid config values by dumping an already-existing - protocol mapper configuration through check-mode in the I(existing) field. + protocol mapper configuration through check-mode in the RV(existing) field. type: dict attributes: @@ -478,7 +516,7 @@ options: saml.signature.algorithm: description: - - Signature algorithm used to sign SAML documents. One of C(RSA_SHA256), C(RSA_SHA1), C(RSA_SHA512), or C(DSA_SHA1). + - Signature algorithm used to sign SAML documents. One of V(RSA_SHA256), V(RSA_SHA1), V(RSA_SHA512), or V(DSA_SHA1). saml.signing.certificate: description: @@ -496,22 +534,21 @@ options: description: - SAML Redirect Binding URL for the client's assertion consumer service (login responses). - saml_force_name_id_format: description: - For SAML clients, Boolean specifying whether to ignore requested NameID subject format and using the configured one instead. saml_name_id_format: description: - - For SAML clients, the NameID format to use (one of C(username), C(email), C(transient), or C(persistent)) + - For SAML clients, the NameID format to use (one of V(username), V(email), V(transient), or V(persistent)) saml_signature_canonicalization_method: description: - SAML signature canonicalization method. This is one of four values, namely - C(http://www.w3.org/2001/10/xml-exc-c14n#) for EXCLUSIVE, - C(http://www.w3.org/2001/10/xml-exc-c14n#WithComments) for EXCLUSIVE_WITH_COMMENTS, - C(http://www.w3.org/TR/2001/REC-xml-c14n-20010315) for INCLUSIVE, and - C(http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments) for INCLUSIVE_WITH_COMMENTS. + V(http://www.w3.org/2001/10/xml-exc-c14n#) for EXCLUSIVE, + V(http://www.w3.org/2001/10/xml-exc-c14n#WithComments) for EXCLUSIVE_WITH_COMMENTS, + V(http://www.w3.org/TR/2001/REC-xml-c14n-20010315) for INCLUSIVE, and + V(http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments) for INCLUSIVE_WITH_COMMENTS. saml_single_logout_service_url_post: description: @@ -523,12 +560,12 @@ options: user.info.response.signature.alg: description: - - For OpenID-Connect clients, JWA algorithm for signed UserInfo-endpoint responses. One of C(RS256) or C(unsigned). + - For OpenID-Connect clients, JWA algorithm for signed UserInfo-endpoint responses. One of V(RS256) or V(unsigned). request.object.signature.alg: description: - For OpenID-Connect clients, JWA algorithm which the client needs to use when sending - OIDC request object. One of C(any), C(none), C(RS256). + OIDC request object. One of V(any), V(none), V(RS256). use.jwks.url: description: @@ -544,9 +581,21 @@ options: - For OpenID-Connect clients, client certificate for validating JWT issued by client and signed by its key, base64-encoded. + x509.subjectdn: + description: + - For OpenID-Connect clients, subject which will be used to authenticate the client. + type: str + version_added: 9.5.0 + + x509.allow.regex.pattern.comparison: + description: + - For OpenID-Connect clients, boolean specifying whether to allow C(x509.subjectdn) as regular expression. + type: bool + version_added: 9.5.0 + extends_documentation_fragment: - - middleware_automation.keycloak.keycloak - - middleware_automation.keycloak.attributes + - middleware_automation.keycloak.keycloak + - middleware_automation.keycloak.attributes author: - Eike Frost (@eikef) @@ -587,6 +636,22 @@ EXAMPLES = ''' delegate_to: localhost +- name: Create or update a Keycloak client (minimal example), with x509 authentication + middleware_automation.keycloak.keycloak_client: + auth_client_id: admin-cli + auth_keycloak_url: https://auth.example.com/auth + auth_realm: master + auth_username: USERNAME + auth_password: PASSWORD + realm: master + state: present + client_id: test + client_authenticator_type: client-x509 + attributes: + x509.subjectdn: "CN=client" + x509.allow.regex.pattern.comparison: false + + - name: Create or update a Keycloak client (with all the bells and whistles) middleware_automation.keycloak.keycloak_client: auth_client_id: admin-cli @@ -637,7 +702,7 @@ EXAMPLES = ''' - test01 - test02 authentication_flow_binding_overrides: - browser: 4c90336b-bf1d-4b87-916d-3677ba4e5fbb + browser: 4c90336b-bf1d-4b87-916d-3677ba4e5fbb protocol_mappers: - config: access.token.claim: true @@ -717,11 +782,17 @@ end_state: ''' from ansible_collections.middleware_automation.keycloak.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \ - keycloak_argument_spec, get_token, KeycloakError + keycloak_argument_spec, get_token, KeycloakError, is_struct_included from ansible.module_utils.basic import AnsibleModule import copy +PROTOCOL_OPENID_CONNECT = 'openid-connect' +PROTOCOL_SAML = 'saml' +PROTOCOL_DOCKER_V2 = 'docker-v2' +CLIENT_META_DATA = ['authorizationServicesEnabled'] + + def normalise_cr(clientrep, remove_ids=False): """ Re-sorts any properties where the order so that diff's is minimised, and adds default values where appropriate so that the the change detection is more effective. @@ -737,6 +808,12 @@ def normalise_cr(clientrep, remove_ids=False): if 'attributes' in clientrep: clientrep['attributes'] = list(sorted(clientrep['attributes'])) + if 'defaultClientScopes' in clientrep: + clientrep['defaultClientScopes'] = list(sorted(clientrep['defaultClientScopes'])) + + if 'optionalClientScopes' in clientrep: + clientrep['optionalClientScopes'] = list(sorted(clientrep['optionalClientScopes'])) + if 'redirectUris' in clientrep: clientrep['redirectUris'] = list(sorted(clientrep['redirectUris'])) @@ -762,11 +839,70 @@ def sanitize_cr(clientrep): if 'secret' in result: result['secret'] = 'no_log' if 'attributes' in result: - if 'saml.signing.private.key' in result['attributes']: - result['attributes']['saml.signing.private.key'] = 'no_log' + attributes = result['attributes'] + if isinstance(attributes, dict) and 'saml.signing.private.key' in attributes: + attributes['saml.signing.private.key'] = 'no_log' return normalise_cr(result) +def get_authentication_flow_id(flow_name, realm, kc): + """ Get the authentication flow ID based on the flow name, realm, and Keycloak client. + + Args: + flow_name (str): The name of the authentication flow. + realm (str): The name of the realm. + kc (KeycloakClient): The Keycloak client instance. + + Returns: + str: The ID of the authentication flow. + + Raises: + KeycloakAPIException: If the authentication flow with the given name is not found in the realm. + """ + flow = kc.get_authentication_flow_by_alias(flow_name, realm) + if flow: + return flow["id"] + kc.module.fail_json(msg='Authentification flow %s not found in realm %s' % (flow_name, realm)) + + +def flow_binding_from_dict_to_model(newClientFlowBinding, realm, kc): + """ Convert a dictionary representing client flow bindings to a model representation. + + Args: + newClientFlowBinding (dict): A dictionary containing client flow bindings. + realm (str): The name of the realm. + kc (KeycloakClient): An instance of the KeycloakClient class. + + Returns: + dict: A dictionary representing the model flow bindings. The dictionary has two keys: + - "browser" (str or None): The ID of the browser authentication flow binding, or None if not provided. + - "direct_grant" (str or None): The ID of the direct grant authentication flow binding, or None if not provided. + + Raises: + KeycloakAPIException: If the authentication flow with the given name is not found in the realm. + + """ + + modelFlow = { + "browser": None, + "direct_grant": None + } + + for k, v in newClientFlowBinding.items(): + if not v: + continue + if k == "browser": + modelFlow["browser"] = v + elif k == "browser_name": + modelFlow["browser"] = get_authentication_flow_id(v, realm, kc) + elif k == "direct_grant": + modelFlow["direct_grant"] = v + elif k == "direct_grant_name": + modelFlow["direct_grant"] = get_authentication_flow_id(v, realm, kc) + + return modelFlow + + def main(): """ Module execution @@ -780,11 +916,18 @@ def main(): consentText=dict(type='str'), id=dict(type='str'), name=dict(type='str'), - protocol=dict(type='str', choices=['openid-connect', 'saml']), + protocol=dict(type='str', choices=[PROTOCOL_OPENID_CONNECT, PROTOCOL_SAML, PROTOCOL_DOCKER_V2]), protocolMapper=dict(type='str'), config=dict(type='dict'), ) + authentication_flow_spec = dict( + browser=dict(type='str'), + browser_name=dict(type='str', aliases=['browserName']), + direct_grant=dict(type='str', aliases=['directGrant']), + direct_grant_name=dict(type='str', aliases=['directGrantName']), + ) + meta_args = dict( state=dict(default='present', choices=['present', 'absent']), realm=dict(type='str', default='master'), @@ -798,7 +941,7 @@ def main(): base_url=dict(type='str', aliases=['baseUrl']), surrogate_auth_required=dict(type='bool', aliases=['surrogateAuthRequired']), enabled=dict(type='bool'), - client_authenticator_type=dict(type='str', choices=['client-secret', 'client-jwt'], aliases=['clientAuthenticatorType']), + client_authenticator_type=dict(type='str', choices=['client-secret', 'client-jwt', 'client-x509'], aliases=['clientAuthenticatorType']), secret=dict(type='str', no_log=True), registration_access_token=dict(type='str', aliases=['registrationAccessToken'], no_log=True), default_roles=dict(type='list', elements='str', aliases=['defaultRoles']), @@ -814,7 +957,7 @@ def main(): authorization_services_enabled=dict(type='bool', aliases=['authorizationServicesEnabled']), public_client=dict(type='bool', aliases=['publicClient']), frontchannel_logout=dict(type='bool', aliases=['frontchannelLogout']), - protocol=dict(type='str', choices=['openid-connect', 'saml']), + protocol=dict(type='str', choices=[PROTOCOL_OPENID_CONNECT, PROTOCOL_SAML, PROTOCOL_DOCKER_V2]), attributes=dict(type='dict'), full_scope_allowed=dict(type='bool', aliases=['fullScopeAllowed']), node_re_registration_timeout=dict(type='int', aliases=['nodeReRegistrationTimeout']), @@ -824,7 +967,13 @@ def main(): use_template_scope=dict(type='bool', aliases=['useTemplateScope']), use_template_mappers=dict(type='bool', aliases=['useTemplateMappers']), always_display_in_console=dict(type='bool', aliases=['alwaysDisplayInConsole']), - authentication_flow_binding_overrides=dict(type='dict', aliases=['authenticationFlowBindingOverrides']), + authentication_flow_binding_overrides=dict( + type='dict', + aliases=['authenticationFlowBindingOverrides'], + options=authentication_flow_spec, + required_one_of=[['browser', 'direct_grant', 'browser_name', 'direct_grant_name']], + mutually_exclusive=[['browser', 'browser_name'], ['direct_grant', 'direct_grant_name']], + ), protocol_mappers=dict(type='list', elements='dict', options=protmapper_spec, aliases=['protocolMappers']), authorization_settings=dict(type='dict', aliases=['authorizationSettings']), default_client_scopes=dict(type='list', elements='str', aliases=['defaultClientScopes']), @@ -885,7 +1034,9 @@ def main(): # Unfortunately, the ansible argument spec checker introduces variables with null values when # they are not specified if client_param == 'protocol_mappers': - new_param_value = [dict((k, v) for k, v in x.items() if x[k] is not None) for x in new_param_value] + new_param_value = [{k: v for k, v in x.items() if v is not None} for x in new_param_value] + elif client_param == 'authentication_flow_binding_overrides': + new_param_value = flow_binding_from_dict_to_model(new_param_value, realm, kc) changeset[camel(client_param)] = new_param_value @@ -912,6 +1063,8 @@ def main(): if 'clientId' not in desired_client: module.fail_json(msg='client_id needs to be specified when creating a new client') + if 'protocol' not in desired_client: + desired_client['protocol'] = PROTOCOL_OPENID_CONNECT if module._diff: result['diff'] = dict(before='', after=sanitize_cr(desired_client)) @@ -940,7 +1093,7 @@ def main(): if module._diff: result['diff'] = dict(before=sanitize_cr(before_norm), after=sanitize_cr(desired_norm)) - result['changed'] = (before_norm != desired_norm) + result['changed'] = not is_struct_included(desired_norm, before_norm, CLIENT_META_DATA) module.exit_json(**result) diff --git a/plugins/modules/keycloak_role.py b/plugins/modules/keycloak_role.py index 558f362..c48e9c9 100644 --- a/plugins/modules/keycloak_role.py +++ b/plugins/modules/keycloak_role.py @@ -40,8 +40,8 @@ options: state: description: - State of the role. - - On C(present), the role will be created if it does not yet exist, or updated with the parameters you provide. - - On C(absent), the role will be removed if it exists. + - On V(present), the role will be created if it does not yet exist, or updated with the parameters you provide. + - On V(absent), the role will be removed if it exists. default: 'present' type: str choices: @@ -77,6 +77,42 @@ options: description: - A dict of key/value pairs to set as custom attributes for the role. - Values may be single values (e.g. a string) or a list of strings. + composite: + description: + - If V(true), the role is a composition of other realm and/or client role. + default: false + type: bool + version_added: 7.1.0 + composites: + description: + - List of roles to include to the composite realm role. + - If the composite role is a client role, the C(clientId) (not ID of the client) must be specified. + default: [] + type: list + elements: dict + version_added: 7.1.0 + suboptions: + name: + description: + - Name of the role. This can be the name of a REALM role or a client role. + type: str + required: true + client_id: + description: + - Client ID if the role is a client role. Do not include this option for a REALM role. + - Use the client ID you can see in the Keycloak console, not the technical ID of the client. + type: str + required: false + aliases: + - clientId + state: + description: + - Create the composite if present, remove it if absent. + type: str + choices: + - present + - absent + default: present extends_documentation_fragment: - middleware_automation.keycloak.keycloak @@ -142,14 +178,14 @@ EXAMPLES = ''' auth_password: PASSWORD name: my-new-role attributes: - attrib1: value1 - attrib2: value2 - attrib3: - - with - - numerous - - individual - - list - - items + attrib1: value1 + attrib2: value2 + attrib3: + - with + - numerous + - individual + - list + - items delegate_to: localhost ''' @@ -198,8 +234,9 @@ end_state: ''' from ansible_collections.middleware_automation.keycloak.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \ - keycloak_argument_spec, get_token, KeycloakError + keycloak_argument_spec, get_token, KeycloakError, is_struct_included from ansible.module_utils.basic import AnsibleModule +import copy def main(): @@ -210,6 +247,12 @@ def main(): """ argument_spec = keycloak_argument_spec() + composites_spec = dict( + name=dict(type='str', required=True), + client_id=dict(type='str', aliases=['clientId'], required=False), + state=dict(type='str', default='present', choices=['present', 'absent']) + ) + meta_args = dict( state=dict(type='str', default='present', choices=['present', 'absent']), name=dict(type='str', required=True), @@ -217,6 +260,8 @@ def main(): realm=dict(type='str', default='master'), client_id=dict(type='str'), attributes=dict(type='dict'), + composites=dict(type='list', default=[], options=composites_spec, elements='dict'), + composite=dict(type='bool', default=False), ) argument_spec.update(meta_args) @@ -250,7 +295,7 @@ def main(): # Filter and map the parameters names that apply to the role role_params = [x for x in module.params - if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm', 'client_id', 'composites'] and + if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm', 'client_id'] and module.params.get(x) is not None] # See if it already exists in Keycloak @@ -269,10 +314,10 @@ def main(): new_param_value = module.params.get(param) old_value = before_role[param] if param in before_role else None if new_param_value != old_value: - changeset[camel(param)] = new_param_value + changeset[camel(param)] = copy.deepcopy(new_param_value) # Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis) - desired_role = before_role.copy() + desired_role = copy.deepcopy(before_role) desired_role.update(changeset) result['proposed'] = changeset @@ -309,6 +354,9 @@ def main(): kc.create_client_role(desired_role, clientid, realm) after_role = kc.get_client_role(name, clientid, realm) + if after_role['composite']: + after_role['composites'] = kc.get_role_composites(rolerep=after_role, clientid=clientid, realm=realm) + result['end_state'] = after_role result['msg'] = 'Role {name} has been created'.format(name=name) @@ -316,10 +364,25 @@ def main(): else: if state == 'present': + compare_exclude = [] + if 'composites' in desired_role and isinstance(desired_role['composites'], list) and len(desired_role['composites']) > 0: + composites = kc.get_role_composites(rolerep=before_role, clientid=clientid, realm=realm) + before_role['composites'] = [] + for composite in composites: + before_composite = {} + if composite['clientRole']: + composite_client = kc.get_client_by_id(id=composite['containerId'], realm=realm) + before_composite['client_id'] = composite_client['clientId'] + else: + before_composite['client_id'] = None + before_composite['name'] = composite['name'] + before_composite['state'] = 'present' + before_role['composites'].append(before_composite) + else: + compare_exclude.append('composites') # Process an update - # no changes - if desired_role == before_role: + if is_struct_included(desired_role, before_role, exclude=compare_exclude): result['changed'] = False result['end_state'] = desired_role result['msg'] = "No changes required to role {name}.".format(name=name) @@ -341,6 +404,8 @@ def main(): else: kc.update_client_role(desired_role, clientid, realm) after_role = kc.get_client_role(name, clientid, realm) + if after_role['composite']: + after_role['composites'] = kc.get_role_composites(rolerep=after_role, clientid=clientid, realm=realm) result['end_state'] = after_role diff --git a/plugins/modules/keycloak_user_federation.py b/plugins/modules/keycloak_user_federation.py index 36fe440..864cfbc 100644 --- a/plugins/modules/keycloak_user_federation.py +++ b/plugins/modules/keycloak_user_federation.py @@ -36,9 +36,9 @@ options: state: description: - State of the user federation. - - On C(present), the user federation will be created if it does not yet exist, or updated with + - On V(present), the user federation will be created if it does not yet exist, or updated with the parameters you provide. - - On C(absent), the user federation will be removed if it exists. + - On V(absent), the user federation will be removed if it exists. default: 'present' type: str choices: @@ -54,7 +54,7 @@ options: id: description: - The unique ID for this user federation. If left empty, the user federation will be searched - by its I(name). + by its O(name). type: str name: @@ -64,18 +64,15 @@ options: provider_id: description: - - Provider for this user federation. + - Provider for this user federation. Built-in providers are V(ldap), V(kerberos), and V(sssd). + Custom user storage providers can also be used. aliases: - providerId type: str - choices: - - ldap - - kerberos - - sssd provider_type: description: - - Component type for user federation (only supported value is C(org.keycloak.storage.UserStorageProvider)). + - Component type for user federation (only supported value is V(org.keycloak.storage.UserStorageProvider)). aliases: - providerType default: org.keycloak.storage.UserStorageProvider @@ -88,13 +85,37 @@ options: - parentId type: str + remove_unspecified_mappers: + description: + - Remove mappers that are not specified in the configuration for this federation. + - Set to V(false) to keep mappers that are not listed in O(mappers). + type: bool + default: true + + bind_credential_update_mode: + description: + - The value of the config parameter O(config.bindCredential) is redacted in the Keycloak responses. + Comparing the redacted value with the desired value always evaluates to not equal. This means + the before and desired states are never equal if the parameter is set. + - Set to V(always) to include O(config.bindCredential) in the comparison of before and desired state. + Because of the redacted value returned by Keycloak the module will always detect a change + and make an update if a O(config.bindCredential) value is set. + - Set to V(only_indirect) to exclude O(config.bindCredential) when comparing the before state with the + desired state. The value of O(config.bindCredential) will only be updated if there are other changes + to the user federation that require an update. + type: str + default: always + choices: + - always + - only_indirect + config: description: - Dict specifying the configuration options for the provider; the contents differ depending on - the value of I(provider_id). Examples are given below for C(ldap), C(kerberos) and C(sssd). + the value of O(provider_id). Examples are given below for V(ldap), V(kerberos) and V(sssd). It is easiest to obtain valid config values by dumping an already-existing user federation - configuration through check-mode in the I(existing) field. - - The value C(sssd) has been supported since middleware_automation.keycloak 1.0.0. + configuration through check-mode in the RV(existing) field. + - The value V(sssd) has been supported since middleware_automation.keycloak 2.0.0. type: dict suboptions: enabled: @@ -111,15 +132,15 @@ options: importEnabled: description: - - If C(true), LDAP users will be imported into Keycloak DB and synced by the configured + - If V(true), LDAP users will be imported into Keycloak DB and synced by the configured sync policies. default: true type: bool editMode: description: - - C(READ_ONLY) is a read-only LDAP store. C(WRITABLE) means data will be synced back to LDAP - on demand. C(UNSYNCED) means user data will be imported, but not synced back to LDAP. + - V(READ_ONLY) is a read-only LDAP store. V(WRITABLE) means data will be synced back to LDAP + on demand. V(UNSYNCED) means user data will be imported, but not synced back to LDAP. type: str choices: - READ_ONLY @@ -136,13 +157,13 @@ options: vendor: description: - LDAP vendor (provider). - - Use short name. For instance, write C(rhds) for "Red Hat Directory Server". + - Use short name. For instance, write V(rhds) for "Red Hat Directory Server". type: str usernameLDAPAttribute: description: - Name of LDAP attribute, which is mapped as Keycloak username. For many LDAP server - vendors it can be C(uid). For Active directory it can be C(sAMAccountName) or C(cn). + vendors it can be V(uid). For Active directory it can be V(sAMAccountName) or V(cn). The attribute should be filled for all LDAP user records you want to import from LDAP to Keycloak. type: str @@ -151,15 +172,15 @@ options: description: - Name of LDAP attribute, which is used as RDN (top attribute) of typical user DN. Usually it's the same as Username LDAP attribute, however it is not required. For - example for Active directory, it is common to use C(cn) as RDN attribute when - username attribute might be C(sAMAccountName). + example for Active directory, it is common to use V(cn) as RDN attribute when + username attribute might be V(sAMAccountName). type: str uuidLDAPAttribute: description: - Name of LDAP attribute, which is used as unique object identifier (UUID) for objects - in LDAP. For many LDAP server vendors, it is C(entryUUID); however some are different. - For example for Active directory it should be C(objectGUID). If your LDAP server does + in LDAP. For many LDAP server vendors, it is V(entryUUID); however some are different. + For example for Active directory it should be V(objectGUID). If your LDAP server does not support the notion of UUID, you can use any other attribute that is supposed to be unique among LDAP users in tree. type: str @@ -167,7 +188,7 @@ options: userObjectClasses: description: - All values of LDAP objectClass attribute for users in LDAP divided by comma. - For example C(inetOrgPerson, organizationalPerson). Newly created Keycloak users + For example V(inetOrgPerson, organizationalPerson). Newly created Keycloak users will be written to LDAP with all those object classes and existing LDAP user records are found just if they contain all those object classes. type: str @@ -251,8 +272,8 @@ options: useTruststoreSpi: description: - Specifies whether LDAP connection will use the truststore SPI with the truststore - configured in standalone.xml/domain.xml. C(Always) means that it will always use it. - C(Never) means that it will not use it. C(Only for ldaps) means that it will use if + configured in standalone.xml/domain.xml. V(always) means that it will always use it. + V(never) means that it will not use it. V(ldapsOnly) means that it will use if your connection URL use ldaps. Note even if standalone.xml/domain.xml is not configured, the default Java cacerts or certificate specified by C(javax.net.ssl.trustStore) property will be used. @@ -297,7 +318,7 @@ options: connectionPoolingDebug: description: - A string that indicates the level of debug output to produce. Example valid values are - C(fine) (trace connection creation and removal) and C(all) (all debugging information). + V(fine) (trace connection creation and removal) and V(all) (all debugging information). type: str connectionPoolingInitSize: @@ -321,7 +342,7 @@ options: connectionPoolingProtocol: description: - A list of space-separated protocol types of connections that may be pooled. - Valid types are C(plain) and C(ssl). + Valid types are V(plain) and V(ssl). type: str connectionPoolingTimeout: @@ -342,17 +363,26 @@ options: - Name of kerberos realm. type: str + krbPrincipalAttribute: + description: + - Name of the LDAP attribute, which refers to Kerberos principal. + This is used to lookup appropriate LDAP user after successful Kerberos/SPNEGO authentication in Keycloak. + When this is empty, the LDAP user will be looked based on LDAP username corresponding + to the first part of his Kerberos principal. For instance, for principal C(john@KEYCLOAK.ORG), + it will assume that LDAP username is V(john). + type: str + serverPrincipal: description: - Full name of server principal for HTTP service including server and domain name. For - example C(HTTP/host.foo.org@FOO.ORG). Use C(*) to accept any service principal in the + example V(HTTP/host.foo.org@FOO.ORG). Use V(*) to accept any service principal in the KeyTab file. type: str keyTab: description: - Location of Kerberos KeyTab file containing the credentials of server principal. For - example C(/etc/krb5.keytab). + example V(/etc/krb5.keytab). type: str debug: @@ -427,6 +457,16 @@ options: - Max lifespan of cache entry in milliseconds. type: int + referral: + description: + - Specifies if LDAP referrals should be followed or ignored. Please note that enabling + referrals can slow down authentication as it allows the LDAP server to decide which other + LDAP servers to use. This could potentially include untrusted servers. + type: str + choices: + - ignore + - follow + mappers: description: - A list of dicts defining mappers associated with this Identity Provider. @@ -451,7 +491,7 @@ options: providerId: description: - - The mapper type for this mapper (for instance C(user-attribute-ldap-mapper)). + - The mapper type for this mapper (for instance V(user-attribute-ldap-mapper)). type: str providerType: @@ -534,14 +574,14 @@ EXAMPLES = ''' provider_id: kerberos provider_type: org.keycloak.storage.UserStorageProvider config: - priority: 0 - enabled: true - cachePolicy: DEFAULT - kerberosRealm: EXAMPLE.COM - serverPrincipal: HTTP/host.example.com@EXAMPLE.COM - keyTab: keytab - allowPasswordAuthentication: false - updateProfileFirstLogin: false + priority: 0 + enabled: true + cachePolicy: DEFAULT + kerberosRealm: EXAMPLE.COM + serverPrincipal: HTTP/host.example.com@EXAMPLE.COM + keyTab: keytab + allowPasswordAuthentication: false + updateProfileFirstLogin: false - name: Create sssd user federation middleware_automation.keycloak.keycloak_user_federation: @@ -704,16 +744,27 @@ from ansible.module_utils.six.moves.urllib.parse import urlencode from copy import deepcopy +def normalize_kc_comp(comp): + if 'config' in comp: + # kc completely removes the parameter `krbPrincipalAttribute` if it is set to `''`; the unset kc parameter is equivalent to `''`; + # to make change detection and diff more accurate we set it again in the kc responses + if 'krbPrincipalAttribute' not in comp['config']: + comp['config']['krbPrincipalAttribute'] = [''] + + # kc stores a timestamp of the last sync in `lastSync` to time the periodic sync, it is removed to minimize diff/changes + comp['config'].pop('lastSync', None) + + def sanitize(comp): compcopy = deepcopy(comp) if 'config' in compcopy: - compcopy['config'] = dict((k, v[0]) for k, v in compcopy['config'].items()) + compcopy['config'] = {k: v[0] for k, v in compcopy['config'].items()} if 'bindCredential' in compcopy['config']: compcopy['config']['bindCredential'] = '**********' if 'mappers' in compcopy: for mapper in compcopy['mappers']: if 'config' in mapper: - mapper['config'] = dict((k, v[0]) for k, v in mapper['config'].items()) + mapper['config'] = {k: v[0] for k, v in mapper['config'].items()} return compcopy @@ -760,8 +811,10 @@ def main(): priority=dict(type='int', default=0), rdnLDAPAttribute=dict(type='str'), readTimeout=dict(type='int'), + referral=dict(type='str', choices=['ignore', 'follow']), searchScope=dict(type='str', choices=['1', '2'], default='1'), serverPrincipal=dict(type='str'), + krbPrincipalAttribute=dict(type='str'), startTls=dict(type='bool', default=False), syncRegistrations=dict(type='bool', default=False), trustEmail=dict(type='bool', default=False), @@ -792,9 +845,11 @@ def main(): realm=dict(type='str', default='master'), id=dict(type='str'), name=dict(type='str'), - provider_id=dict(type='str', aliases=['providerId'], choices=['ldap', 'kerberos', 'sssd']), + provider_id=dict(type='str', aliases=['providerId']), provider_type=dict(type='str', aliases=['providerType'], default='org.keycloak.storage.UserStorageProvider'), parent_id=dict(type='str', aliases=['parentId']), + remove_unspecified_mappers=dict(type='bool', default=True), + bind_credential_update_mode=dict(type='str', default='always', choices=['always', 'only_indirect']), mappers=dict(type='list', elements='dict', options=mapper_spec), ) @@ -825,19 +880,26 @@ def main(): # Keycloak API expects config parameters to be arrays containing a single string element if config is not None: - module.params['config'] = dict((k, [str(v).lower() if not isinstance(v, str) else v]) - for k, v in config.items() if config[k] is not None) + module.params['config'] = { + k: [str(v).lower() if not isinstance(v, str) else v] + for k, v in config.items() + if config[k] is not None + } if mappers is not None: for mapper in mappers: if mapper.get('config') is not None: - mapper['config'] = dict((k, [str(v).lower() if not isinstance(v, str) else v]) - for k, v in mapper['config'].items() if mapper['config'][k] is not None) + mapper['config'] = { + k: [str(v).lower() if not isinstance(v, str) else v] + for k, v in mapper['config'].items() + if mapper['config'][k] is not None + } # Filter and map the parameters names that apply comp_params = [x for x in module.params - if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm', 'mappers'] and - module.params.get(x) is not None] + if x not in list(keycloak_argument_spec().keys()) + + ['state', 'realm', 'mappers', 'remove_unspecified_mappers', 'bind_credential_update_mode'] + and module.params.get(x) is not None] # See if it already exists in Keycloak if cid is None: @@ -855,7 +917,9 @@ def main(): # if user federation exists, get associated mappers if cid is not None and before_comp: - before_comp['mappers'] = sorted(kc.get_components(urlencode(dict(parent=cid)), realm), key=lambda x: x.get('name')) + before_comp['mappers'] = sorted(kc.get_components(urlencode(dict(parent=cid)), realm), key=lambda x: x.get('name') or '') + + normalize_kc_comp(before_comp) # Build a proposed changeset from parameters given to this module changeset = {} @@ -864,7 +928,7 @@ def main(): new_param_value = module.params.get(param) old_value = before_comp[camel(param)] if camel(param) in before_comp else None if param == 'mappers': - new_param_value = [dict((k, v) for k, v in x.items() if x[k] is not None) for x in new_param_value] + new_param_value = [{k: v for k, v in x.items() if v is not None} for x in new_param_value] if new_param_value != old_value: changeset[camel(param)] = new_param_value @@ -873,17 +937,17 @@ def main(): if module.params['provider_id'] in ['kerberos', 'sssd']: module.fail_json(msg='Cannot configure mappers for {type} provider.'.format(type=module.params['provider_id'])) for change in module.params['mappers']: - change = dict((k, v) for k, v in change.items() if change[k] is not None) + change = {k: v for k, v in change.items() if v is not None} if change.get('id') is None and change.get('name') is None: module.fail_json(msg='Either `name` or `id` has to be specified on each mapper.') if cid is None: old_mapper = {} elif change.get('id') is not None: - old_mapper = kc.get_component(change['id'], realm) + old_mapper = next((before_mapper for before_mapper in before_comp.get('mappers', []) if before_mapper["id"] == change['id']), None) if old_mapper is None: old_mapper = {} else: - found = kc.get_components(urlencode(dict(parent=cid, name=change['name'])), realm) + found = [before_mapper for before_mapper in before_comp.get('mappers', []) if before_mapper['name'] == change['name']] if len(found) > 1: module.fail_json(msg='Found multiple mappers with name `{name}`. Cannot continue.'.format(name=change['name'])) if len(found) == 1: @@ -892,10 +956,16 @@ def main(): old_mapper = {} new_mapper = old_mapper.copy() new_mapper.update(change) - if new_mapper != old_mapper: - if changeset.get('mappers') is None: - changeset['mappers'] = list() - changeset['mappers'].append(new_mapper) + # changeset contains all desired mappers: those existing, to update or to create + if changeset.get('mappers') is None: + changeset['mappers'] = list() + changeset['mappers'].append(new_mapper) + changeset['mappers'] = sorted(changeset['mappers'], key=lambda x: x.get('name') or '') + + # to keep unspecified existing mappers we add them to the desired mappers list, unless they're already present + if not module.params['remove_unspecified_mappers'] and 'mappers' in before_comp: + changeset_mapper_ids = [mapper['id'] for mapper in changeset['mappers'] if 'id' in mapper] + changeset['mappers'].extend([mapper for mapper in before_comp['mappers'] if mapper['id'] not in changeset_mapper_ids]) # Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis) desired_comp = before_comp.copy() @@ -918,50 +988,68 @@ def main(): # Process a creation result['changed'] = True - if module._diff: - result['diff'] = dict(before='', after=sanitize(desired_comp)) - if module.check_mode: + if module._diff: + result['diff'] = dict(before='', after=sanitize(desired_comp)) module.exit_json(**result) # create it - desired_comp = desired_comp.copy() - updated_mappers = desired_comp.pop('mappers', []) + desired_mappers = desired_comp.pop('mappers', []) after_comp = kc.create_component(desired_comp, realm) - cid = after_comp['id'] + updated_mappers = [] + # when creating a user federation, keycloak automatically creates default mappers + default_mappers = kc.get_components(urlencode(dict(parent=cid)), realm) - for mapper in updated_mappers: - found = kc.get_components(urlencode(dict(parent=cid, name=mapper['name'])), realm) + # create new mappers or update existing default mappers + for desired_mapper in desired_mappers: + found = [default_mapper for default_mapper in default_mappers if default_mapper['name'] == desired_mapper['name']] if len(found) > 1: - module.fail_json(msg='Found multiple mappers with name `{name}`. Cannot continue.'.format(name=mapper['name'])) + module.fail_json(msg='Found multiple mappers with name `{name}`. Cannot continue.'.format(name=desired_mapper['name'])) if len(found) == 1: old_mapper = found[0] else: old_mapper = {} new_mapper = old_mapper.copy() - new_mapper.update(mapper) + new_mapper.update(desired_mapper) if new_mapper.get('id') is not None: kc.update_component(new_mapper, realm) + updated_mappers.append(new_mapper) else: if new_mapper.get('parentId') is None: - new_mapper['parentId'] = after_comp['id'] - mapper = kc.create_component(new_mapper, realm) + new_mapper['parentId'] = cid + updated_mappers.append(kc.create_component(new_mapper, realm)) - after_comp['mappers'] = updated_mappers + if module.params['remove_unspecified_mappers']: + # we remove all unwanted default mappers + # we use ids so we dont accidently remove one of the previously updated default mapper + for default_mapper in default_mappers: + if not default_mapper['id'] in [x['id'] for x in updated_mappers]: + kc.delete_component(default_mapper['id'], realm) + + after_comp['mappers'] = kc.get_components(urlencode(dict(parent=cid)), realm) + normalize_kc_comp(after_comp) + if module._diff: + result['diff'] = dict(before='', after=sanitize(after_comp)) result['end_state'] = sanitize(after_comp) - - result['msg'] = "User federation {id} has been created".format(id=after_comp['id']) + result['msg'] = "User federation {id} has been created".format(id=cid) module.exit_json(**result) else: if state == 'present': # Process an update + desired_copy = deepcopy(desired_comp) + before_copy = deepcopy(before_comp) + # exclude bindCredential when checking wether an update is required, therefore + # updating it only if there are other changes + if module.params['bind_credential_update_mode'] == 'only_indirect': + desired_copy.get('config', []).pop('bindCredential', None) + before_copy.get('config', []).pop('bindCredential', None) # no changes - if desired_comp == before_comp: + if desired_copy == before_copy: result['changed'] = False result['end_state'] = sanitize(desired_comp) result['msg'] = "No changes required to user federation {id}.".format(id=cid) @@ -977,22 +1065,33 @@ def main(): module.exit_json(**result) # do the update - desired_comp = desired_comp.copy() - updated_mappers = desired_comp.pop('mappers', []) + desired_mappers = desired_comp.pop('mappers', []) kc.update_component(desired_comp, realm) - after_comp = kc.get_component(cid, realm) - for mapper in updated_mappers: + for before_mapper in before_comp.get('mappers', []): + # remove unwanted existing mappers that will not be updated + if not before_mapper['id'] in [x['id'] for x in desired_mappers if 'id' in x]: + kc.delete_component(before_mapper['id'], realm) + + for mapper in desired_mappers: + if mapper in before_comp.get('mappers', []): + continue if mapper.get('id') is not None: kc.update_component(mapper, realm) else: if mapper.get('parentId') is None: mapper['parentId'] = desired_comp['id'] - mapper = kc.create_component(mapper, realm) - - after_comp['mappers'] = updated_mappers - result['end_state'] = sanitize(after_comp) + kc.create_component(mapper, realm) + after_comp = kc.get_component(cid, realm) + after_comp['mappers'] = sorted(kc.get_components(urlencode(dict(parent=cid)), realm), key=lambda x: x.get('name') or '') + normalize_kc_comp(after_comp) + after_comp_sanitized = sanitize(after_comp) + before_comp_sanitized = sanitize(before_comp) + result['end_state'] = after_comp_sanitized + if module._diff: + result['diff'] = dict(before=before_comp_sanitized, after=after_comp_sanitized) + result['changed'] = before_comp_sanitized != after_comp_sanitized result['msg'] = "User federation {id} has been updated".format(id=cid) module.exit_json(**result) From 5f1b43f37ba6dcf409a38ec4958d497c7a25578b Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 14 Oct 2024 10:34:20 +0200 Subject: [PATCH 174/205] update docs --- .github/workflows/traffic.yml | 14 ++++----- CHANGELOG.rst | 6 ++-- CONTRIBUTING.md | 34 ++++++++++++++++++++ README.md | 14 ++++----- docs/_gh_include/footer.inc | 4 +-- docs/index.rst | 16 +++------- docs/testing.md | 29 ++--------------- molecule/debian/converge.yml | 59 ++++++++++++++++++----------------- 8 files changed, 91 insertions(+), 85 deletions(-) diff --git a/.github/workflows/traffic.yml b/.github/workflows/traffic.yml index b4f245e..d997f4e 100644 --- a/.github/workflows/traffic.yml +++ b/.github/workflows/traffic.yml @@ -1,9 +1,9 @@ name: Collect traffic stats on: - schedule: + schedule: - cron: "51 23 * * 0" - workflow_dispatch: - + workflow_dispatch: + jobs: traffic: runs-on: ubuntu-latest @@ -11,12 +11,12 @@ jobs: - uses: actions/checkout@v2 with: ref: "gh-pages" - - - name: GitHub traffic + + - name: GitHub traffic uses: sangonzal/repository-traffic-action@v.0.1.6 env: - TRAFFIC_ACTION_TOKEN: ${{ secrets.TRIGGERING_PAT }} - + TRAFFIC_ACTION_TOKEN: ${{ secrets.TRIGGERING_PAT }} + - name: Commit changes uses: EndBug/add-and-commit@v4 with: diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 7283c76..aafdac2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,6 @@ -============================================= -middleware\_automation.keycloak Release Notes -============================================= +============= +Release Notes +============= .. contents:: Topics diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aee36a6..21ddc18 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,37 @@ +## Developing + +### Build and install locally + +Clone the repository, checkout the tag you want to build, or pick the main branch for the development version; then: + + ansible-galaxy collection build . + ansible-galaxy collection install middleware_automation-keycloak-*.tar.gz + + +### Development environment + +Make sure your development machine has avilable: + +* python 3.11+ +* virtualenv +* docker (or podman) + +In order to run setup the development environment and run the molecule tests locally, after cloning the repository: + +``` +# create new virtualenv using python 3 +virtualenv $PATH_TO_DEV_VIRTUALENV +# activate the virtual env +source $PATH_TO_DEV_VIRTUALENV/bin/activate +# install ansible and tools onto the virtualenv +pip install yamllint 'molecule>=6.0' 'molecule-plugins[docker]' 'ansible-core>=2.15' ansible-lint +# install collection dependencies +ansible-galaxy collection install -r requirements.yml +# install python dependencies +pip install -r requirements.txt molecule/requirements.txt +# execute the tests (replace --all with -s subdirectory to run a single test) +molecule test --all +``` ## Contributor's Guidelines diff --git a/README.md b/README.md index 3827b90..bca0270 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Build Status](https://github.com/ansible-middleware/keycloak/workflows/CI/badge.svg?branch=main)](https://github.com/ansible-middleware/keycloak/actions/workflows/ci.yml) -> **_NOTE:_ If you are Red Hat customer, install `redhat.sso` (for Red Hat Single Sign-On) or `redhat.rhbk` (for Red Hat Build of Keycloak) from [Automation Hub](https://console.redhat.com/ansible/ansible-dashboard) as the certified version of this collection.** +> **_NOTE:_ If you are Red Hat customer, install `redhat.rhbk` (for Red Hat Build of Keycloak) or `redhat.sso` (for Red Hat Single Sign-On) from [Automation Hub](https://console.redhat.com/ansible/ansible-dashboard) as the certified version of this collection.** @@ -49,9 +49,10 @@ A requirement file is provided to install: ### Included roles -* [`keycloak`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak/README.md): role for installing the service (keycloak <= 19.0). -* [`keycloak_realm`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak_realm/README.md): role for configuring a realm, user federation(s), clients and users, in an installed service. -* [`keycloak_quarkus`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak_quarkus/README.md): role for installing the quarkus variant of keycloak (>= 17.0.0). +* `keycloak_quarkus`: role for installing keycloak (>= 19.0.0, quarkus based). +* `keycloak_realm`: role for configuring a realm, user federation(s), clients and users, in an installed service. +* `keycloak`: role for installing legacy keycloak (<= 19.0, wildfly based). + ## Usage @@ -61,7 +62,7 @@ A requirement file is provided to install: * [`playbooks/keycloak.yml`](https://github.com/ansible-middleware/keycloak/blob/main/playbooks/keycloak.yml) installs keycloak legacy based on the defined variables (using most defaults). * [`playbooks/keycloak_quarkus.yml`](https://github.com/ansible-middleware/keycloak/blob/main/playbooks/keycloak_quarkus.yml) installs keycloak >= 17 based on the defined variables (using most defaults). - + Both playbooks include the `keycloak` role, with different settings, as described in the following sections. For full service configuration details, refer to the [keycloak role README](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak/README.md). @@ -92,7 +93,7 @@ Execute the following command from the source root directory ``` ansible-playbook -i -e @rhn-creds.yml playbooks/keycloak.yml -e keycloak_admin_password= -``` +``` - `keycloak_admin_password` Password for the administration console user account. - `ansible_hosts` is the inventory, below is an example inventory for deploying to localhost @@ -143,4 +144,3 @@ Apache License v2.0 or later See [LICENSE](LICENSE) to view the full text. - diff --git a/docs/_gh_include/footer.inc b/docs/_gh_include/footer.inc index 73bac34..11c1cfe 100644 --- a/docs/_gh_include/footer.inc +++ b/docs/_gh_include/footer.inc @@ -7,7 +7,7 @@
-

© Copyright 2022, Red Hat, Inc.

+

© Copyright 2024, Red Hat, Inc.

Built with Sphinx using a theme @@ -18,4 +18,4 @@ - \ No newline at end of file + diff --git a/docs/index.rst b/docs/index.rst index 38dec5b..6c46ab1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -10,31 +10,25 @@ Welcome to Keycloak Collection documentation README plugins/index roles/index + Changelog .. toctree:: :maxdepth: 2 :caption: Developer documentation - testing - developing - releasing - -.. toctree:: - :maxdepth: 2 - :caption: General - - Changelog + Developing + Testing + Releasing .. toctree:: :maxdepth: 2 :caption: Middleware collections - Infinispan / Red Hat Data Grid Keycloak / Red Hat Single Sign-On + Infinispan / Red Hat Data Grid Wildfly / Red Hat JBoss EAP Tomcat / Red Hat JWS ActiveMQ / Red Hat AMQ Broker Kafka / Red Hat AMQ Streams Ansible Middleware utilities - Red Hat CSP Download JCliff diff --git a/docs/testing.md b/docs/testing.md index 1d06d7f..8e773ea 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -4,24 +4,7 @@ The collection is tested with a [molecule](https://github.com/ansible-community/molecule) setup covering the included roles and verifying correct installation and idempotency. In order to run the molecule tests locally with python 3.9 available, after cloning the repository: - -``` -pip install yamllint 'molecule[docker]~=3.5.2' ansible-core flake8 ansible-lint voluptuous -molecule test --all -``` - - -## Integration testing - -Demo repositories which depend on the collection, and aggregate functionality with other middleware_automation collections, are automatically rebuilt -at every collection release to ensure non-breaking changes and consistent behaviour. - -The repository are: - - - [Flange demo](https://github.com/ansible-middleware/flange-demo) - A deployment of Wildfly cluster integrated with keycloak and infinispan. - - [CrossDC keycloak demo](https://github.com/ansible-middleware/cross-dc-rhsso-demo) - A clustered multi-regional installation of keycloak with infinispan remote caches. +The test scenarios are available on the source code repository each on his own subdirectory under [molecule/](https://github.com/ansible-middleware/keycloak/molecule). ## Test playbooks @@ -29,15 +12,7 @@ The repository are: Sample playbooks are provided in the `playbooks/` directory; to run the playbooks locally (requires a rhel system with python 3.9+, ansible, and systemd) the steps are as follows: ``` -# setup environment -pip install ansible-core -# clone the repository -git clone https://github.com/ansible-middleware/keycloak -cd keycloak -# install collection dependencies -ansible-galaxy collection install -r requirements.yml -# install collection python deps -pip install -r requirements.txt +# setup environment as in developing # create inventory for localhost cat << EOF > inventory [keycloak] diff --git a/molecule/debian/converge.yml b/molecule/debian/converge.yml index e6319b7..5b60408 100644 --- a/molecule/debian/converge.yml +++ b/molecule/debian/converge.yml @@ -7,36 +7,39 @@ keycloak_realm: TestRealm keycloak_quarkus_log: file keycloak_quarkus_frontend_url: 'http://localhost:8080/' - keycloak_quarkus_start_dev: True + keycloak_quarkus_start_dev: true keycloak_quarkus_proxy_mode: none - keycloak_client_default_roles: - - TestRoleAdmin - - TestRoleUser - keycloak_client_users: - - username: TestUser - password: password - client_roles: - - client: TestClient - role: TestRoleUser - - username: TestAdmin - password: password - client_roles: - - client: TestClient - role: TestRoleUser - - client: TestClient - role: TestRoleAdmin - keycloak_clients: - - name: TestClient - roles: "{{ keycloak_client_default_roles }}" - public_client: "{{ keycloak_client_public }}" - web_origins: "{{ keycloak_client_web_origins }}" - users: "{{ keycloak_client_users }}" - client_id: TestClient - attributes: - post.logout.redirect.uris: '/public/logout' roles: - role: keycloak_quarkus - role: keycloak_realm - keycloak_realm: TestRealm - keycloak_admin_password: "remembertochangeme" keycloak_context: '' + keycloak_client_default_roles: + - TestRoleAdmin + - TestRoleUser + keycloak_client_users: + - username: TestUser + password: password + client_roles: + - client: TestClient + role: TestRoleUser + realm: "{{ keycloak_realm }}" + - username: TestAdmin + password: password + client_roles: + - client: TestClient + role: TestRoleUser + realm: "{{ keycloak_realm }}" + - client: TestClient + role: TestRoleAdmin + realm: "{{ keycloak_realm }}" + keycloak_realm: TestRealm + keycloak_clients: + - name: TestClient + roles: "{{ keycloak_client_default_roles }}" + realm: "{{ keycloak_realm }}" + public_client: "{{ keycloak_client_public }}" + web_origins: "{{ keycloak_client_web_origins }}" + users: "{{ keycloak_client_users }}" + client_id: TestClient + attributes: + post.logout.redirect.uris: '/public/logout' From be19ec1289805dea625d93e5b36357e1004f0e46 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Mon, 14 Oct 2024 10:41:17 +0200 Subject: [PATCH 175/205] update tests --- README.md | 2 +- molecule/debian/converge.yml | 8 +- molecule/default/converge.yml | 6 +- plugins/modules/keycloak_realm.py | 848 +++++++++++++++++++ roles/keycloak_realm/README.md | 2 +- roles/keycloak_realm/defaults/main.yml | 2 +- roles/keycloak_realm/meta/argument_specs.yml | 2 +- roles/keycloak_realm/tasks/main.yml | 4 +- 8 files changed, 857 insertions(+), 17 deletions(-) create mode 100644 plugins/modules/keycloak_realm.py diff --git a/README.md b/README.md index bca0270..e8c289e 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,8 @@ A requirement file is provided to install: ### Install Playbook -* [`playbooks/keycloak.yml`](https://github.com/ansible-middleware/keycloak/blob/main/playbooks/keycloak.yml) installs keycloak legacy based on the defined variables (using most defaults). * [`playbooks/keycloak_quarkus.yml`](https://github.com/ansible-middleware/keycloak/blob/main/playbooks/keycloak_quarkus.yml) installs keycloak >= 17 based on the defined variables (using most defaults). +* [`playbooks/keycloak.yml`](https://github.com/ansible-middleware/keycloak/blob/main/playbooks/keycloak.yml) installs keycloak legacy based on the defined variables (using most defaults). Both playbooks include the `keycloak` role, with different settings, as described in the following sections. diff --git a/molecule/debian/converge.yml b/molecule/debian/converge.yml index 5b60408..1a7d267 100644 --- a/molecule/debian/converge.yml +++ b/molecule/debian/converge.yml @@ -4,18 +4,15 @@ vars: keycloak_quarkus_show_deprecation_warnings: false keycloak_quarkus_admin_pass: "remembertochangeme" - keycloak_realm: TestRealm + keycloak_admin_password: "remembertochangeme" + keycloak_quarkus_host: instance keycloak_quarkus_log: file - keycloak_quarkus_frontend_url: 'http://localhost:8080/' keycloak_quarkus_start_dev: true keycloak_quarkus_proxy_mode: none roles: - role: keycloak_quarkus - role: keycloak_realm keycloak_context: '' - keycloak_client_default_roles: - - TestRoleAdmin - - TestRoleUser keycloak_client_users: - username: TestUser password: password @@ -35,7 +32,6 @@ keycloak_realm: TestRealm keycloak_clients: - name: TestClient - roles: "{{ keycloak_client_default_roles }}" realm: "{{ keycloak_realm }}" public_client: "{{ keycloak_client_public }}" web_origins: "{{ keycloak_client_web_origins }}" diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index bb8c552..417713f 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -9,7 +9,7 @@ keycloak_quarkus_log: file keycloak_quarkus_log_level: debug keycloak_quarkus_log_target: /tmp/keycloak - keycloak_quarkus_start_dev: True + keycloak_quarkus_start_dev: true keycloak_quarkus_proxy_mode: none keycloak_quarkus_offline_install: true keycloak_quarkus_download_path: /tmp/keycloak/ @@ -17,9 +17,6 @@ - role: keycloak_quarkus - role: keycloak_realm keycloak_context: '' - keycloak_client_default_roles: - - TestRoleAdmin - - TestRoleUser keycloak_client_users: - username: TestUser password: password @@ -39,7 +36,6 @@ keycloak_realm: TestRealm keycloak_clients: - name: TestClient - roles: "{{ keycloak_client_default_roles }}" realm: "{{ keycloak_realm }}" public_client: "{{ keycloak_client_public }}" web_origins: "{{ keycloak_client_web_origins }}" diff --git a/plugins/modules/keycloak_realm.py b/plugins/modules/keycloak_realm.py new file mode 100644 index 0000000..a22795b --- /dev/null +++ b/plugins/modules/keycloak_realm.py @@ -0,0 +1,848 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2017, Eike Frost +# Copyright (c) 2021, Christophe Gilles +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +DOCUMENTATION = ''' +--- +module: keycloak_realm + +short_description: Allows administration of Keycloak realm via Keycloak API + +version_added: 3.0.0 + +description: + - This module allows the administration of Keycloak realm via the Keycloak REST API. It + requires access to the REST API via OpenID Connect; the user connecting and the realm being + used must have the requisite access rights. In a default Keycloak installation, admin-cli + and an admin user would work, as would a separate realm definition with the scope tailored + to your needs and a user having the expected roles. + + - The names of module options are snake_cased versions of the camelCase ones found in the + Keycloak API and its documentation at U(https://www.keycloak.org/docs-api/8.0/rest-api/index.html). + Aliases are provided so camelCased versions can be used as well. + + - The Keycloak API does not always sanity check inputs e.g. you can set + SAML-specific settings on an OpenID Connect client for instance and vice versa. Be careful. + If you do not specify a setting, usually a sensible default is chosen. + +attributes: + check_mode: + support: full + diff_mode: + support: full + +options: + state: + description: + - State of the realm. + - On V(present), the realm will be created (or updated if it exists already). + - On V(absent), the realm will be removed if it exists. + choices: ['present', 'absent'] + default: 'present' + type: str + + id: + description: + - The realm to create. + type: str + realm: + description: + - The realm name. + type: str + access_code_lifespan: + description: + - The realm access code lifespan. + aliases: + - accessCodeLifespan + type: int + access_code_lifespan_login: + description: + - The realm access code lifespan login. + aliases: + - accessCodeLifespanLogin + type: int + access_code_lifespan_user_action: + description: + - The realm access code lifespan user action. + aliases: + - accessCodeLifespanUserAction + type: int + access_token_lifespan: + description: + - The realm access token lifespan. + aliases: + - accessTokenLifespan + type: int + access_token_lifespan_for_implicit_flow: + description: + - The realm access token lifespan for implicit flow. + aliases: + - accessTokenLifespanForImplicitFlow + type: int + account_theme: + description: + - The realm account theme. + aliases: + - accountTheme + type: str + action_token_generated_by_admin_lifespan: + description: + - The realm action token generated by admin lifespan. + aliases: + - actionTokenGeneratedByAdminLifespan + type: int + action_token_generated_by_user_lifespan: + description: + - The realm action token generated by user lifespan. + aliases: + - actionTokenGeneratedByUserLifespan + type: int + admin_events_details_enabled: + description: + - The realm admin events details enabled. + aliases: + - adminEventsDetailsEnabled + type: bool + admin_events_enabled: + description: + - The realm admin events enabled. + aliases: + - adminEventsEnabled + type: bool + admin_theme: + description: + - The realm admin theme. + aliases: + - adminTheme + type: str + attributes: + description: + - The realm attributes. + type: dict + browser_flow: + description: + - The realm browser flow. + aliases: + - browserFlow + type: str + browser_security_headers: + description: + - The realm browser security headers. + aliases: + - browserSecurityHeaders + type: dict + brute_force_protected: + description: + - The realm brute force protected. + aliases: + - bruteForceProtected + type: bool + client_authentication_flow: + description: + - The realm client authentication flow. + aliases: + - clientAuthenticationFlow + type: str + client_scope_mappings: + description: + - The realm client scope mappings. + aliases: + - clientScopeMappings + type: dict + default_default_client_scopes: + description: + - The realm default default client scopes. + aliases: + - defaultDefaultClientScopes + type: list + elements: str + default_groups: + description: + - The realm default groups. + aliases: + - defaultGroups + type: list + elements: str + default_locale: + description: + - The realm default locale. + aliases: + - defaultLocale + type: str + default_optional_client_scopes: + description: + - The realm default optional client scopes. + aliases: + - defaultOptionalClientScopes + type: list + elements: str + default_roles: + description: + - The realm default roles. + aliases: + - defaultRoles + type: list + elements: str + default_signature_algorithm: + description: + - The realm default signature algorithm. + aliases: + - defaultSignatureAlgorithm + type: str + direct_grant_flow: + description: + - The realm direct grant flow. + aliases: + - directGrantFlow + type: str + display_name: + description: + - The realm display name. + aliases: + - displayName + type: str + display_name_html: + description: + - The realm display name HTML. + aliases: + - displayNameHtml + type: str + docker_authentication_flow: + description: + - The realm docker authentication flow. + aliases: + - dockerAuthenticationFlow + type: str + duplicate_emails_allowed: + description: + - The realm duplicate emails allowed option. + aliases: + - duplicateEmailsAllowed + type: bool + edit_username_allowed: + description: + - The realm edit username allowed option. + aliases: + - editUsernameAllowed + type: bool + email_theme: + description: + - The realm email theme. + aliases: + - emailTheme + type: str + enabled: + description: + - The realm enabled option. + type: bool + enabled_event_types: + description: + - The realm enabled event types. + aliases: + - enabledEventTypes + type: list + elements: str + events_enabled: + description: + - Enables or disables login events for this realm. + aliases: + - eventsEnabled + type: bool + version_added: 3.6.0 + events_expiration: + description: + - The realm events expiration. + aliases: + - eventsExpiration + type: int + events_listeners: + description: + - The realm events listeners. + aliases: + - eventsListeners + type: list + elements: str + failure_factor: + description: + - The realm failure factor. + aliases: + - failureFactor + type: int + internationalization_enabled: + description: + - The realm internationalization enabled option. + aliases: + - internationalizationEnabled + type: bool + login_theme: + description: + - The realm login theme. + aliases: + - loginTheme + type: str + login_with_email_allowed: + description: + - The realm login with email allowed option. + aliases: + - loginWithEmailAllowed + type: bool + max_delta_time_seconds: + description: + - The realm max delta time in seconds. + aliases: + - maxDeltaTimeSeconds + type: int + max_failure_wait_seconds: + description: + - The realm max failure wait in seconds. + aliases: + - maxFailureWaitSeconds + type: int + minimum_quick_login_wait_seconds: + description: + - The realm minimum quick login wait in seconds. + aliases: + - minimumQuickLoginWaitSeconds + type: int + not_before: + description: + - The realm not before. + aliases: + - notBefore + type: int + offline_session_idle_timeout: + description: + - The realm offline session idle timeout. + aliases: + - offlineSessionIdleTimeout + type: int + offline_session_max_lifespan: + description: + - The realm offline session max lifespan. + aliases: + - offlineSessionMaxLifespan + type: int + offline_session_max_lifespan_enabled: + description: + - The realm offline session max lifespan enabled option. + aliases: + - offlineSessionMaxLifespanEnabled + type: bool + otp_policy_algorithm: + description: + - The realm otp policy algorithm. + aliases: + - otpPolicyAlgorithm + type: str + otp_policy_digits: + description: + - The realm otp policy digits. + aliases: + - otpPolicyDigits + type: int + otp_policy_initial_counter: + description: + - The realm otp policy initial counter. + aliases: + - otpPolicyInitialCounter + type: int + otp_policy_look_ahead_window: + description: + - The realm otp policy look ahead window. + aliases: + - otpPolicyLookAheadWindow + type: int + otp_policy_period: + description: + - The realm otp policy period. + aliases: + - otpPolicyPeriod + type: int + otp_policy_type: + description: + - The realm otp policy type. + aliases: + - otpPolicyType + type: str + otp_supported_applications: + description: + - The realm otp supported applications. + aliases: + - otpSupportedApplications + type: list + elements: str + password_policy: + description: + - The realm password policy. + aliases: + - passwordPolicy + type: str + permanent_lockout: + description: + - The realm permanent lockout. + aliases: + - permanentLockout + type: bool + quick_login_check_milli_seconds: + description: + - The realm quick login check in milliseconds. + aliases: + - quickLoginCheckMilliSeconds + type: int + refresh_token_max_reuse: + description: + - The realm refresh token max reuse. + aliases: + - refreshTokenMaxReuse + type: int + registration_allowed: + description: + - The realm registration allowed option. + aliases: + - registrationAllowed + type: bool + registration_email_as_username: + description: + - The realm registration email as username option. + aliases: + - registrationEmailAsUsername + type: bool + registration_flow: + description: + - The realm registration flow. + aliases: + - registrationFlow + type: str + remember_me: + description: + - The realm remember me option. + aliases: + - rememberMe + type: bool + reset_credentials_flow: + description: + - The realm reset credentials flow. + aliases: + - resetCredentialsFlow + type: str + reset_password_allowed: + description: + - The realm reset password allowed option. + aliases: + - resetPasswordAllowed + type: bool + revoke_refresh_token: + description: + - The realm revoke refresh token option. + aliases: + - revokeRefreshToken + type: bool + smtp_server: + description: + - The realm smtp server. + aliases: + - smtpServer + type: dict + ssl_required: + description: + - The realm ssl required option. + choices: ['all', 'external', 'none'] + aliases: + - sslRequired + type: str + sso_session_idle_timeout: + description: + - The realm sso session idle timeout. + aliases: + - ssoSessionIdleTimeout + type: int + sso_session_idle_timeout_remember_me: + description: + - The realm sso session idle timeout remember me. + aliases: + - ssoSessionIdleTimeoutRememberMe + type: int + sso_session_max_lifespan: + description: + - The realm sso session max lifespan. + aliases: + - ssoSessionMaxLifespan + type: int + sso_session_max_lifespan_remember_me: + description: + - The realm sso session max lifespan remember me. + aliases: + - ssoSessionMaxLifespanRememberMe + type: int + supported_locales: + description: + - The realm supported locales. + aliases: + - supportedLocales + type: list + elements: str + user_managed_access_allowed: + description: + - The realm user managed access allowed option. + aliases: + - userManagedAccessAllowed + type: bool + verify_email: + description: + - The realm verify email option. + aliases: + - verifyEmail + type: bool + wait_increment_seconds: + description: + - The realm wait increment in seconds. + aliases: + - waitIncrementSeconds + type: int + +extends_documentation_fragment: + - middleware_automation.keycloak.keycloak + - middleware_automation.keycloak.attributes + +author: + - Christophe Gilles (@kris2kris) +''' + +EXAMPLES = ''' +- name: Create or update Keycloak realm (minimal example) + middleware_automation.keycloak.keycloak_realm: + auth_client_id: admin-cli + auth_keycloak_url: https://auth.example.com/auth + auth_realm: master + auth_username: USERNAME + auth_password: PASSWORD + id: realm + realm: realm + state: present + +- name: Delete a Keycloak realm + middleware_automation.keycloak.keycloak_realm: + auth_client_id: admin-cli + auth_keycloak_url: https://auth.example.com/auth + auth_realm: master + auth_username: USERNAME + auth_password: PASSWORD + id: test + state: absent +''' + +RETURN = ''' +msg: + description: Message as to what action was taken. + returned: always + type: str + sample: "Realm testrealm has been updated" + +proposed: + description: Representation of proposed realm. + returned: always + type: dict + sample: { + id: "test" + } + +existing: + description: Representation of existing realm (sample is truncated). + returned: always + type: dict + sample: { + "adminUrl": "http://www.example.com/admin_url", + "attributes": { + "request.object.signature.alg": "RS256", + } + } + +end_state: + description: Representation of realm after module execution (sample is truncated). + returned: on success + type: dict + sample: { + "adminUrl": "http://www.example.com/admin_url", + "attributes": { + "request.object.signature.alg": "RS256", + } + } +''' + +from ansible_collections.middleware_automation.keycloak.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \ + keycloak_argument_spec, get_token, KeycloakError +from ansible.module_utils.basic import AnsibleModule + + +def normalise_cr(realmrep): + """ Re-sorts any properties where the order is important so that diff's is minimised and the change detection is more effective. + + :param realmrep: the realmrep dict to be sanitized + :return: normalised realmrep dict + """ + # Avoid the dict passed in to be modified + realmrep = realmrep.copy() + + if 'enabledEventTypes' in realmrep: + realmrep['enabledEventTypes'] = list(sorted(realmrep['enabledEventTypes'])) + + if 'otpSupportedApplications' in realmrep: + realmrep['otpSupportedApplications'] = list(sorted(realmrep['otpSupportedApplications'])) + + if 'supportedLocales' in realmrep: + realmrep['supportedLocales'] = list(sorted(realmrep['supportedLocales'])) + + return realmrep + + +def sanitize_cr(realmrep): + """ Removes probably sensitive details from a realm representation. + + :param realmrep: the realmrep dict to be sanitized + :return: sanitized realmrep dict + """ + result = realmrep.copy() + if 'secret' in result: + result['secret'] = '********' + if 'attributes' in result: + if 'saml.signing.private.key' in result['attributes']: + result['attributes'] = result['attributes'].copy() + result['attributes']['saml.signing.private.key'] = '********' + return normalise_cr(result) + + +def main(): + """ + Module execution + + :return: + """ + argument_spec = keycloak_argument_spec() + + meta_args = dict( + state=dict(default='present', choices=['present', 'absent']), + + id=dict(type='str'), + realm=dict(type='str'), + access_code_lifespan=dict(type='int', aliases=['accessCodeLifespan']), + access_code_lifespan_login=dict(type='int', aliases=['accessCodeLifespanLogin']), + access_code_lifespan_user_action=dict(type='int', aliases=['accessCodeLifespanUserAction']), + access_token_lifespan=dict(type='int', aliases=['accessTokenLifespan'], no_log=False), + access_token_lifespan_for_implicit_flow=dict(type='int', aliases=['accessTokenLifespanForImplicitFlow'], no_log=False), + account_theme=dict(type='str', aliases=['accountTheme']), + action_token_generated_by_admin_lifespan=dict(type='int', aliases=['actionTokenGeneratedByAdminLifespan'], no_log=False), + action_token_generated_by_user_lifespan=dict(type='int', aliases=['actionTokenGeneratedByUserLifespan'], no_log=False), + admin_events_details_enabled=dict(type='bool', aliases=['adminEventsDetailsEnabled']), + admin_events_enabled=dict(type='bool', aliases=['adminEventsEnabled']), + admin_theme=dict(type='str', aliases=['adminTheme']), + attributes=dict(type='dict'), + browser_flow=dict(type='str', aliases=['browserFlow']), + browser_security_headers=dict(type='dict', aliases=['browserSecurityHeaders']), + brute_force_protected=dict(type='bool', aliases=['bruteForceProtected']), + client_authentication_flow=dict(type='str', aliases=['clientAuthenticationFlow']), + client_scope_mappings=dict(type='dict', aliases=['clientScopeMappings']), + default_default_client_scopes=dict(type='list', elements='str', aliases=['defaultDefaultClientScopes']), + default_groups=dict(type='list', elements='str', aliases=['defaultGroups']), + default_locale=dict(type='str', aliases=['defaultLocale']), + default_optional_client_scopes=dict(type='list', elements='str', aliases=['defaultOptionalClientScopes']), + default_roles=dict(type='list', elements='str', aliases=['defaultRoles']), + default_signature_algorithm=dict(type='str', aliases=['defaultSignatureAlgorithm']), + direct_grant_flow=dict(type='str', aliases=['directGrantFlow']), + display_name=dict(type='str', aliases=['displayName']), + display_name_html=dict(type='str', aliases=['displayNameHtml']), + docker_authentication_flow=dict(type='str', aliases=['dockerAuthenticationFlow']), + duplicate_emails_allowed=dict(type='bool', aliases=['duplicateEmailsAllowed']), + edit_username_allowed=dict(type='bool', aliases=['editUsernameAllowed']), + email_theme=dict(type='str', aliases=['emailTheme']), + enabled=dict(type='bool'), + enabled_event_types=dict(type='list', elements='str', aliases=['enabledEventTypes']), + events_enabled=dict(type='bool', aliases=['eventsEnabled']), + events_expiration=dict(type='int', aliases=['eventsExpiration']), + events_listeners=dict(type='list', elements='str', aliases=['eventsListeners']), + failure_factor=dict(type='int', aliases=['failureFactor']), + internationalization_enabled=dict(type='bool', aliases=['internationalizationEnabled']), + login_theme=dict(type='str', aliases=['loginTheme']), + login_with_email_allowed=dict(type='bool', aliases=['loginWithEmailAllowed']), + max_delta_time_seconds=dict(type='int', aliases=['maxDeltaTimeSeconds']), + max_failure_wait_seconds=dict(type='int', aliases=['maxFailureWaitSeconds']), + minimum_quick_login_wait_seconds=dict(type='int', aliases=['minimumQuickLoginWaitSeconds']), + not_before=dict(type='int', aliases=['notBefore']), + offline_session_idle_timeout=dict(type='int', aliases=['offlineSessionIdleTimeout']), + offline_session_max_lifespan=dict(type='int', aliases=['offlineSessionMaxLifespan']), + offline_session_max_lifespan_enabled=dict(type='bool', aliases=['offlineSessionMaxLifespanEnabled']), + otp_policy_algorithm=dict(type='str', aliases=['otpPolicyAlgorithm']), + otp_policy_digits=dict(type='int', aliases=['otpPolicyDigits']), + otp_policy_initial_counter=dict(type='int', aliases=['otpPolicyInitialCounter']), + otp_policy_look_ahead_window=dict(type='int', aliases=['otpPolicyLookAheadWindow']), + otp_policy_period=dict(type='int', aliases=['otpPolicyPeriod']), + otp_policy_type=dict(type='str', aliases=['otpPolicyType']), + otp_supported_applications=dict(type='list', elements='str', aliases=['otpSupportedApplications']), + password_policy=dict(type='str', aliases=['passwordPolicy'], no_log=False), + permanent_lockout=dict(type='bool', aliases=['permanentLockout']), + quick_login_check_milli_seconds=dict(type='int', aliases=['quickLoginCheckMilliSeconds']), + refresh_token_max_reuse=dict(type='int', aliases=['refreshTokenMaxReuse'], no_log=False), + registration_allowed=dict(type='bool', aliases=['registrationAllowed']), + registration_email_as_username=dict(type='bool', aliases=['registrationEmailAsUsername']), + registration_flow=dict(type='str', aliases=['registrationFlow']), + remember_me=dict(type='bool', aliases=['rememberMe']), + reset_credentials_flow=dict(type='str', aliases=['resetCredentialsFlow']), + reset_password_allowed=dict(type='bool', aliases=['resetPasswordAllowed'], no_log=False), + revoke_refresh_token=dict(type='bool', aliases=['revokeRefreshToken']), + smtp_server=dict(type='dict', aliases=['smtpServer']), + ssl_required=dict(choices=["external", "all", "none"], aliases=['sslRequired']), + sso_session_idle_timeout=dict(type='int', aliases=['ssoSessionIdleTimeout']), + sso_session_idle_timeout_remember_me=dict(type='int', aliases=['ssoSessionIdleTimeoutRememberMe']), + sso_session_max_lifespan=dict(type='int', aliases=['ssoSessionMaxLifespan']), + sso_session_max_lifespan_remember_me=dict(type='int', aliases=['ssoSessionMaxLifespanRememberMe']), + supported_locales=dict(type='list', elements='str', aliases=['supportedLocales']), + user_managed_access_allowed=dict(type='bool', aliases=['userManagedAccessAllowed']), + verify_email=dict(type='bool', aliases=['verifyEmail']), + wait_increment_seconds=dict(type='int', aliases=['waitIncrementSeconds']), + ) + + argument_spec.update(meta_args) + + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True, + required_one_of=([['id', 'realm', 'enabled'], + ['token', 'auth_realm', 'auth_username', 'auth_password']]), + required_together=([['auth_realm', 'auth_username', 'auth_password']])) + + result = dict(changed=False, msg='', diff={}, proposed={}, existing={}, end_state={}) + + # Obtain access token, initialize API + try: + connection_header = get_token(module.params) + except KeycloakError as e: + module.fail_json(msg=str(e)) + + kc = KeycloakAPI(module, connection_header) + + realm = module.params.get('realm') + state = module.params.get('state') + + # convert module parameters to realm representation parameters (if they belong in there) + params_to_ignore = list(keycloak_argument_spec().keys()) + ['state'] + + # Filter and map the parameters names that apply to the role + realm_params = [x for x in module.params + if x not in params_to_ignore and + module.params.get(x) is not None] + + # See whether the realm already exists in Keycloak + before_realm = kc.get_realm_by_id(realm=realm) + + if before_realm is None: + before_realm = {} + + # Build a proposed changeset from parameters given to this module + changeset = {} + + for realm_param in realm_params: + new_param_value = module.params.get(realm_param) + changeset[camel(realm_param)] = new_param_value + + # Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis) + desired_realm = before_realm.copy() + desired_realm.update(changeset) + + result['proposed'] = sanitize_cr(changeset) + before_realm_sanitized = sanitize_cr(before_realm) + result['existing'] = before_realm_sanitized + + # Cater for when it doesn't exist (an empty dict) + if not before_realm: + if state == 'absent': + # Do nothing and exit + if module._diff: + result['diff'] = dict(before='', after='') + result['changed'] = False + result['end_state'] = {} + result['msg'] = 'Realm does not exist, doing nothing.' + module.exit_json(**result) + + # Process a creation + result['changed'] = True + + if 'id' not in desired_realm: + module.fail_json(msg='id needs to be specified when creating a new realm') + + if module._diff: + result['diff'] = dict(before='', after=sanitize_cr(desired_realm)) + + if module.check_mode: + module.exit_json(**result) + + # create it + kc.create_realm(desired_realm) + after_realm = kc.get_realm_by_id(desired_realm['id']) + + result['end_state'] = sanitize_cr(after_realm) + + result['msg'] = 'Realm %s has been created.' % desired_realm['id'] + module.exit_json(**result) + + else: + if state == 'present': + # Process an update + + # doing an update + result['changed'] = True + if module.check_mode: + # We can only compare the current realm with the proposed updates we have + before_norm = normalise_cr(before_realm) + desired_norm = normalise_cr(desired_realm) + if module._diff: + result['diff'] = dict(before=sanitize_cr(before_norm), + after=sanitize_cr(desired_norm)) + result['changed'] = (before_norm != desired_norm) + + module.exit_json(**result) + + # do the update + kc.update_realm(desired_realm, realm=realm) + + after_realm = kc.get_realm_by_id(realm=realm) + + if before_realm == after_realm: + result['changed'] = False + + result['end_state'] = sanitize_cr(after_realm) + + if module._diff: + result['diff'] = dict(before=before_realm_sanitized, + after=sanitize_cr(after_realm)) + + result['msg'] = 'Realm %s has been updated.' % desired_realm['id'] + module.exit_json(**result) + + else: + # Process a deletion (because state was not 'present') + result['changed'] = True + + if module._diff: + result['diff'] = dict(before=before_realm_sanitized, after='') + + if module.check_mode: + module.exit_json(**result) + + # delete it + kc.delete_realm(realm=realm) + + result['proposed'] = {} + result['end_state'] = {} + + result['msg'] = 'Realm %s has been deleted.' % before_realm['id'] + + module.exit_json(**result) + + +if __name__ == '__main__': + main() diff --git a/roles/keycloak_realm/README.md b/roles/keycloak_realm/README.md index d6ce30c..179784e 100644 --- a/roles/keycloak_realm/README.md +++ b/roles/keycloak_realm/README.md @@ -19,7 +19,7 @@ Role Defaults |`keycloak_management_http_port`| Management port | `9990` | |`keycloak_auth_client`| Authentication client for configuration REST calls | `admin-cli` | |`keycloak_client_public`| Configure a public realm client | `True` | -|`keycloak_client_web_origins`| Web origins for realm client | `+` | +|`keycloak_client_web_origins`| Web origins for realm client | `/*` | |`keycloak_url`| URL for configuration rest calls | `http://{{ keycloak_host }}:{{ keycloak_http_port }}` | |`keycloak_management_url`| URL for management console rest calls | `http://{{ keycloak_host }}:{{ keycloak_management_http_port }}` | diff --git a/roles/keycloak_realm/defaults/main.yml b/roles/keycloak_realm/defaults/main.yml index e488207..b9e1e45 100644 --- a/roles/keycloak_realm/defaults/main.yml +++ b/roles/keycloak_realm/defaults/main.yml @@ -43,7 +43,7 @@ keycloak_client_default_roles: [] keycloak_client_public: true # allowed web origins for the client -keycloak_client_web_origins: '+' +keycloak_client_web_origins: '/*' # list of user and role mappings to create in the client # Each user has the form: diff --git a/roles/keycloak_realm/meta/argument_specs.yml b/roles/keycloak_realm/meta/argument_specs.yml index b124be2..7c24a7c 100644 --- a/roles/keycloak_realm/meta/argument_specs.yml +++ b/roles/keycloak_realm/meta/argument_specs.yml @@ -53,7 +53,7 @@ argument_specs: type: "bool" keycloak_client_web_origins: # line 42 of keycloak_realm/defaults/main.yml - default: "+" + default: "/*" description: "Web origins for realm client" type: "str" keycloak_client_users: diff --git a/roles/keycloak_realm/tasks/main.yml b/roles/keycloak_realm/tasks/main.yml index 016ab55..962016c 100644 --- a/roles/keycloak_realm/tasks/main.yml +++ b/roles/keycloak_realm/tasks/main.yml @@ -82,7 +82,7 @@ base_url: "{{ item.base_url | default('') }}" enabled: "{{ item.enabled | default(True) }}" redirect_uris: "{{ item.redirect_uris | default(omit) }}" - web_origins: "{{ item.web_origins | default('+') }}" + web_origins: "{{ item.web_origins | default(omit) }}" bearer_only: "{{ item.bearer_only | default(omit) }}" standard_flow_enabled: "{{ item.standard_flow_enabled | default(omit) }}" implicit_flow_enabled: "{{ item.implicit_flow_enabled | default(omit) }}" @@ -92,7 +92,7 @@ protocol: "{{ item.protocol | default(omit) }}" attributes: "{{ item.attributes | default(omit) }}" state: present - no_log: "{{ keycloak_no_log | default('True') }}" + no_log: "{{ keycloak_no_log | default('false') }}" register: create_client_result loop: "{{ keycloak_clients | flatten }}" when: (item.name is defined and item.client_id is defined) or (item.name is defined and item.id is defined) From 1279937bb0e95f0398ad04494b5f6797bd21afd6 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 16 Oct 2024 08:56:53 +0200 Subject: [PATCH 176/205] Update keycloak to 24.0.5 --- molecule/default/prepare.yml | 2 +- molecule/quarkus/converge.yml | 2 +- roles/keycloak_quarkus/README.md | 4 ++-- roles/keycloak_quarkus/defaults/main.yml | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml index a50dfa4..899dabd 100644 --- a/molecule/default/prepare.yml +++ b/molecule/default/prepare.yml @@ -22,7 +22,7 @@ - name: Download keycloak archive to controller directory ansible.builtin.get_url: # noqa risky-file-permissions delegated, uses controller host user - url: https://github.com/keycloak/keycloak/releases/download/24.0.4/keycloak-24.0.4.zip + url: https://github.com/keycloak/keycloak/releases/download/24.0.5/keycloak-24.0.5.zip dest: /tmp/keycloak mode: '0640' delegate_to: localhost diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index 7c86756..0860a42 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -37,7 +37,7 @@ repository_url: https://repo1.maven.org/maven2/ # https://mvnrepository.com/artifact/org.keycloak/keycloak-kerberos-federation/24.0.4 group_id: org.keycloak artifact_id: keycloak-kerberos-federation - version: 24.0.4 # optional + version: 24.0.5 # optional # username: myUser # optional # password: myPAT # optional # - id: my-static-theme diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 00c785f..034c021 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -33,7 +33,7 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| -|`keycloak_quarkus_version`| keycloak.org package version | `24.0.4` | +|`keycloak_quarkus_version`| keycloak.org package version | `24.0.5` | |`keycloak_quarkus_offline_install` | Perform an offline install | `False`| |`keycloak_quarkus_dest`| Installation root path | `/opt/keycloak` | |`keycloak_quarkus_download_url` | Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}` | @@ -207,7 +207,7 @@ keycloak_quarkus_providers: repository_url: https://maven.pkg.github.com/OWNER/REPOSITORY # optional, maven repo url group_id: my.group # optional, maven group id artifact_id: artifact # optional, maven artifact id - version: 24.0.4 # optional, defaults to latest + version: 24.0.5 # optional, defaults to latest username: user # optional, cf. https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry#authenticating-to-github-packages password: pat # optional, provide a PAT for accessing Github's Apache Maven registry properties: # optional, list of key-values diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index b029fee..148d84d 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -1,6 +1,6 @@ --- ### Configuration specific to keycloak -keycloak_quarkus_version: 24.0.4 +keycloak_quarkus_version: 24.0.5 keycloak_quarkus_archive: "keycloak-{{ keycloak_quarkus_version }}.zip" keycloak_quarkus_download_url: "https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}" keycloak_quarkus_installdir: "{{ keycloak_quarkus_dest }}/keycloak-{{ keycloak_quarkus_version }}" diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 34ec365..51fd6d8 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -2,7 +2,7 @@ argument_specs: main: options: keycloak_quarkus_version: - default: "24.0.4" + default: "24.0.5" description: "keycloak.org package version" type: "str" keycloak_quarkus_archive: From f6fdae4aa80283c9155f0e203efeb5f8b9d7bc22 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Wed, 16 Oct 2024 07:24:42 +0000 Subject: [PATCH 177/205] Update changelog for release 2.4.3 Signed-off-by: ansible-middleware-core --- CHANGELOG.rst | 14 +++++++++++--- changelogs/changelog.yaml | 9 +++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index aafdac2..37a3923 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,11 +1,19 @@ -============= -Release Notes -============= +============================================= +middleware\_automation.keycloak Release Notes +============================================= .. contents:: Topics This changelog describes changes after version 0.2.6. +v2.4.3 +====== + +Minor Changes +------------- + +- Update keycloak to 24.0.5 `#241 `_ + v2.4.2 ====== diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 41a4076..40a7db3 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -604,3 +604,12 @@ releases: - 237.yaml - 239.yaml release_date: '2024-09-26' + 2.4.3: + changes: + minor_changes: + - 'Update keycloak to 24.0.5 `#241 `_ + + ' + fragments: + - 241.yaml + release_date: '2024-10-16' From 333d55ad734a21018d7c8bf02d6f66cb66d46933 Mon Sep 17 00:00:00 2001 From: ansible-middleware-core Date: Wed, 16 Oct 2024 07:24:57 +0000 Subject: [PATCH 178/205] Bump version to 2.4.4 --- galaxy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy.yml b/galaxy.yml index a782353..a6511a8 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.4.3" +version: "2.4.4" readme: README.md authors: - Romain Pelisse From 68a0f8842332a82133a6e6b0b77eb6c84e73c8a0 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Fri, 22 Nov 2024 08:08:09 +0100 Subject: [PATCH 179/205] keycloak_quarkus: Rebuild config and restart service for local providers (#249) --- roles/keycloak_quarkus/README.md | 2 +- roles/keycloak_quarkus/tasks/install.yml | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 034c021..e63db68 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -200,7 +200,7 @@ keycloak_quarkus_providers: - id: http-client # required; "{{ id }}.jar" identifies the file name on RHBK spi: connections # required if neither url, local_path nor maven are specified; required for setting properties default: true # optional, whether to set default for spi, default false - restart: true # optional, whether to restart, default true + restart: true # optional, whether to rebuild config and restart the service after deploying, default true url: https://.../.../custom_spi.jar # optional, url for download via http local_path: my_theme_spi.jar # optional, path on local controller for SPI to be uploaded maven: # optional, for download using maven diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index 809e07e..d8ce657 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -218,7 +218,7 @@ become: true loop: "{{ keycloak_quarkus_providers }}" when: item.url is defined and item.url | length > 0 - notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or not item.restart else [] }}" + notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or item.restart else [] }}" # this requires the `lxml` package to be installed; we redirect this step to localhost such that we do need to install it on the remote hosts - name: "Download custom providers to localhost using maven" @@ -235,7 +235,7 @@ loop: "{{ keycloak_quarkus_providers }}" when: item.maven is defined no_log: "{{ item.maven.password is defined and item.maven.password | length > 0 | default(false) }}" - notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or not item.restart else [] }}" + notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or item.restart else [] }}" - name: "Copy maven providers" ansible.builtin.copy: @@ -249,7 +249,7 @@ when: item.maven is defined no_log: "{{ item.maven.password is defined and item.maven.password | length > 0 | default(false) }}" -- name: "Copy providers" +- name: "Copy local providers" ansible.builtin.copy: src: "{{ item.local_path }}" dest: "{{ keycloak.home }}/providers/{{ item.id }}.jar" @@ -259,6 +259,7 @@ become: true loop: "{{ keycloak_quarkus_providers }}" when: item.local_path is defined + notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or item.restart else [] }}" - name: Ensure required folder structure for policies exists ansible.builtin.file: From d1859aaff28f77312f7fc04f4fd0c37a7ace5770 Mon Sep 17 00:00:00 2001 From: Ranabir Chakraborty Date: Tue, 3 Dec 2024 22:12:36 +0530 Subject: [PATCH 180/205] Access token lifespan is too short for ansible run --- .github/workflows/ci.yml | 2 +- roles/keycloak_realm/tasks/main.yml | 3 +++ .../keycloak_realm/tasks/manage_token_lifespan.yml | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 roles/keycloak_realm/tasks/manage_token_lifespan.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3d71b46..de65d72 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,4 +16,4 @@ jobs: with: fqcn: 'middleware_automation/keycloak' molecule_tests: >- - [ "default", "overridexml", "https_revproxy", "quarkus", "quarkus-devmode", "quarkus_upgrade", "debian", "quarkus_ha" ] + [ "default", "overridexml", "https_revproxy", "quarkus", "quarkus-devmode", "quarkus_upgrade", "debian", "quarkus_ha" ] diff --git a/roles/keycloak_realm/tasks/main.yml b/roles/keycloak_realm/tasks/main.yml index 962016c..8f33fcc 100644 --- a/roles/keycloak_realm/tasks/main.yml +++ b/roles/keycloak_realm/tasks/main.yml @@ -110,3 +110,6 @@ loop_control: loop_var: client when: "'users' in client" + +- name: Provide Access token lifespan + ansible.builtin.include_tasks: manage_token_lifespan.yml diff --git a/roles/keycloak_realm/tasks/manage_token_lifespan.yml b/roles/keycloak_realm/tasks/manage_token_lifespan.yml new file mode 100644 index 0000000..f16b938 --- /dev/null +++ b/roles/keycloak_realm/tasks/manage_token_lifespan.yml @@ -0,0 +1,14 @@ +--- +- name: "Update Access token lifespan" + ansible.builtin.uri: + url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ keycloak_realm }}" + method: PUT + body: + accessTokenLifespan: 300 + validate_certs: false + body_format: json + status_code: + - 200 + - 204 + headers: + Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" From 5f534ca5669514244176c1b53bb3552b3d65fe75 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Thu, 12 Dec 2024 09:05:09 +0100 Subject: [PATCH 181/205] keycloak_quarkus: Add theme cache invalidation handler --- roles/keycloak_quarkus/handlers/main.yml | 3 +++ roles/keycloak_quarkus/tasks/install.yml | 6 +++--- .../keycloak_quarkus/tasks/invalidate_theme_cache.yml | 11 +++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 roles/keycloak_quarkus/tasks/invalidate_theme_cache.yml diff --git a/roles/keycloak_quarkus/handlers/main.yml b/roles/keycloak_quarkus/handlers/main.yml index 37d65c5..eec7789 100644 --- a/roles/keycloak_quarkus/handlers/main.yml +++ b/roles/keycloak_quarkus/handlers/main.yml @@ -1,4 +1,7 @@ --- +- name: "Invalidate {{ keycloak.service_name }} theme cache" + ansible.builtin.include_tasks: invalidate_theme_cache.yml + listen: "invalidate keycloak theme cache" # handler should be invoked anytime a [build configuration](https://www.keycloak.org/server/all-config?f=build) changes - name: "Rebuild {{ keycloak.service_name }} config" ansible.builtin.include_tasks: rebuild_config.yml diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index d8ce657..c602d8c 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -218,7 +218,7 @@ become: true loop: "{{ keycloak_quarkus_providers }}" when: item.url is defined and item.url | length > 0 - notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or item.restart else [] }}" + notify: "{{ ['invalidate keycloak theme cache', 'rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or item.restart else [] }}" # this requires the `lxml` package to be installed; we redirect this step to localhost such that we do need to install it on the remote hosts - name: "Download custom providers to localhost using maven" @@ -235,7 +235,7 @@ loop: "{{ keycloak_quarkus_providers }}" when: item.maven is defined no_log: "{{ item.maven.password is defined and item.maven.password | length > 0 | default(false) }}" - notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or item.restart else [] }}" + notify: "{{ ['invalidate keycloak theme cache', 'rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or item.restart else [] }}" - name: "Copy maven providers" ansible.builtin.copy: @@ -259,7 +259,7 @@ become: true loop: "{{ keycloak_quarkus_providers }}" when: item.local_path is defined - notify: "{{ ['rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or item.restart else [] }}" + notify: "{{ ['invalidate keycloak theme cache', 'rebuild keycloak config', 'restart keycloak'] if not item.restart is defined or item.restart else [] }}" - name: Ensure required folder structure for policies exists ansible.builtin.file: diff --git a/roles/keycloak_quarkus/tasks/invalidate_theme_cache.yml b/roles/keycloak_quarkus/tasks/invalidate_theme_cache.yml new file mode 100644 index 0000000..90ff67f --- /dev/null +++ b/roles/keycloak_quarkus/tasks/invalidate_theme_cache.yml @@ -0,0 +1,11 @@ +--- +# From https://docs.redhat.com/en/documentation/red_hat_build_of_keycloak/24.0/html/server_developer_guide/themes#creating_a_theme: +# If you want to manually delete the content of the themes cache, +# you can do so by deleting the data/tmp/kc-gzip-cache directory of the server distribution +# It can be useful for instance if you redeployed custom providers or custom themes without +# disabling themes caching in the previous server executions. +- name: "Delete {{ keycloak.service_name }} theme cache directory" + ansible.builtin.file: + path: "{{ keycloak.home }}/data/tmp/kc-gzip-cache" + state: absent + become: true From 5d15d37890ef472e65e420e4824bf83691913087 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Thu, 5 Dec 2024 13:26:10 +0100 Subject: [PATCH 182/205] RHBK v26: Raise default KC+RHBK versions to v26.x (#253) --- roles/keycloak_quarkus/README.md | 2 +- roles/keycloak_quarkus/defaults/main.yml | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index e63db68..9211b00 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -33,7 +33,7 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| -|`keycloak_quarkus_version`| keycloak.org package version | `24.0.5` | +|`keycloak_quarkus_version`| keycloak.org package version | `26.0.7` | |`keycloak_quarkus_offline_install` | Perform an offline install | `False`| |`keycloak_quarkus_dest`| Installation root path | `/opt/keycloak` | |`keycloak_quarkus_download_url` | Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 148d84d..4d158c8 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -1,6 +1,6 @@ --- ### Configuration specific to keycloak -keycloak_quarkus_version: 24.0.5 +keycloak_quarkus_version: 26.0.7 keycloak_quarkus_archive: "keycloak-{{ keycloak_quarkus_version }}.zip" keycloak_quarkus_download_url: "https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}" keycloak_quarkus_installdir: "{{ keycloak_quarkus_dest }}/keycloak-{{ keycloak_quarkus_version }}" diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 51fd6d8..d1a3a0e 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -2,7 +2,7 @@ argument_specs: main: options: keycloak_quarkus_version: - default: "24.0.5" + default: "26.0.7" description: "keycloak.org package version" type: "str" keycloak_quarkus_archive: @@ -468,7 +468,7 @@ argument_specs: downstream: options: rhbk_version: - default: "24.0.3" + default: "26.0.6" description: "Red Hat Build of Keycloak version" type: "str" rhbk_archive: From bf0bd9e1da64eb0a5a764b9275acd226da9e75bf Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Thu, 5 Dec 2024 13:26:57 +0100 Subject: [PATCH 183/205] RHBK v26: Update mssqj jdbc driver (KC/RHBK v26 Support #253) As per --- roles/keycloak_quarkus/defaults/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 4d158c8..ba9854b 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -138,9 +138,9 @@ keycloak_quarkus_default_jdbc: version: 2.7.4 mssql: url: 'jdbc:sqlserver://localhost:1433;databaseName=keycloak;' - version: 12.4.2 - driver_jar_url: "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/12.4.2.jre11/mssql-jdbc-12.4.2.jre11.jar" - # cf. https://access.redhat.com/documentation/en-us/red_hat_build_of_keycloak/24.0/html/server_guide/db-#db-installing-the-microsoft-sql-server-driver + version: 12.8.1 + driver_jar_url: "https://repo1.maven.org/maven2/com/microsoft/sqlserver/mssql-jdbc/12.8.1.jre11/mssql-jdbc-12.8.1.jre11.jar" + # cf. https://docs.redhat.com/en/documentation/red_hat_build_of_keycloak/26.0/html-single/server_configuration_guide/index#db-installing-the-microsoft-sql-server-driver ### logging configuration keycloak_quarkus_log: file keycloak_quarkus_log_level: info From 0c58ae48ff949f1c8152f8076b296e4b551db011 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 9 Dec 2024 14:48:15 +0100 Subject: [PATCH 184/205] RHBK v26: Update ispn session usages (KC/RHBK v26 Support #253) Cf. --- roles/keycloak_quarkus/templates/cache-ispn.xml.j2 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/roles/keycloak_quarkus/templates/cache-ispn.xml.j2 b/roles/keycloak_quarkus/templates/cache-ispn.xml.j2 index fb11cda..8ead247 100644 --- a/roles/keycloak_quarkus/templates/cache-ispn.xml.j2 +++ b/roles/keycloak_quarkus/templates/cache-ispn.xml.j2 @@ -18,8 +18,8 @@ + xsi:schemaLocation="urn:infinispan:config:15.0 http://www.infinispan.org/schemas/infinispan-config-15.0.xsd" + xmlns="urn:infinispan:config:15.0"> {% set stack_expression='' %} {% if keycloak_quarkus_ha_enabled and keycloak_quarkus_ha_discovery == 'TCPPING' %} @@ -55,18 +55,22 @@
+ + + + @@ -98,4 +102,4 @@
- \ No newline at end of file + From 58233549a7f99d3a534a4ae77d87884c5846f348 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 9 Dec 2024 14:54:24 +0100 Subject: [PATCH 185/205] keycloak.conf: Remove `config-keystore-type` (KC/RHBK v26 Support #253) Cf. --- roles/keycloak_quarkus/templates/keycloak.conf.j2 | 1 - 1 file changed, 1 deletion(-) diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index ab4024b..24972c3 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -21,7 +21,6 @@ hostname-strict-https=false # Config store config-keystore={{ keycloak_quarkus_config_key_store_file }} config-keystore-password={{ keycloak_quarkus_config_key_store_password }} -config-keystore-type=PKCS12 {% endif %} # Observability From 277e1336ee97318ca88ffd27e3fe0ea2bf0e8133 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 9 Dec 2024 15:47:06 +0100 Subject: [PATCH 186/205] RHBK v26: Migrate to `keycloak_quarkus_bootstrap_admin_user[_password]` (Process for creation of admin account changed #248) --- molecule/debian/converge.yml | 4 +- molecule/debian/verify.yml | 2 +- molecule/default/converge.yml | 4 +- molecule/default/verify.yml | 4 +- molecule/https_revproxy/converge.yml | 4 +- molecule/quarkus-devmode/converge.yml | 4 +- molecule/quarkus/converge.yml | 4 +- molecule/quarkus/verify.yml | 4 +- molecule/quarkus_ha/converge.yml | 4 +- molecule/quarkus_upgrade/vars.yml | 3 +- molecule/quarkus_upgrade/verify.yml | 4 +- roles/keycloak_quarkus/README.md | 8 +- roles/keycloak_quarkus/defaults/main.yml | 4 +- .../keycloak_quarkus/meta/argument_specs.yml | 8 +- roles/keycloak_quarkus/tasks/deprecations.yml | 96 +++++++++++++++++++ roles/keycloak_quarkus/tasks/main.yml | 2 +- roles/keycloak_quarkus/tasks/prereqs.yml | 4 +- .../templates/keycloak-sysconfig.j2 | 4 +- 18 files changed, 132 insertions(+), 35 deletions(-) diff --git a/molecule/debian/converge.yml b/molecule/debian/converge.yml index 1a7d267..a3ba17a 100644 --- a/molecule/debian/converge.yml +++ b/molecule/debian/converge.yml @@ -3,8 +3,8 @@ hosts: all vars: keycloak_quarkus_show_deprecation_warnings: false - keycloak_quarkus_admin_pass: "remembertochangeme" - keycloak_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_quarkus_host: instance keycloak_quarkus_log: file keycloak_quarkus_start_dev: true diff --git a/molecule/debian/verify.yml b/molecule/debian/verify.yml index 59bf483..863b820 100644 --- a/molecule/debian/verify.yml +++ b/molecule/debian/verify.yml @@ -2,7 +2,7 @@ - name: Verify hosts: all vars: - keycloak_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_uri: "http://localhost:{{ 8080 + ( keycloak_jboss_port_offset | default(0) ) }}" keycloak_management_port: "http://localhost:{{ 9990 + ( keycloak_jboss_port_offset | default(0) ) }}" keycloak_jboss_port_offset: 10 diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index 417713f..543b003 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -3,8 +3,8 @@ hosts: all vars: keycloak_quarkus_show_deprecation_warnings: false - keycloak_quarkus_admin_pass: "remembertochangeme" - keycloak_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_quarkus_host: instance keycloak_quarkus_log: file keycloak_quarkus_log_level: debug diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index b880105..eac4339 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -2,7 +2,7 @@ - name: Verify hosts: all vars: - keycloak_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_uri: "http://localhost:8080" tasks: - name: Populate service facts @@ -16,7 +16,7 @@ ansible.builtin.uri: url: "{{ keycloak_uri }}/realms/master/protocol/openid-connect/token" method: POST - body: "client_id=admin-cli&username=admin&password={{ keycloak_admin_password }}&grant_type=password" + body: "client_id=admin-cli&username=admin&password={{ keycloak_quarkus_bootstrap_admin_user }}&grant_type=password" validate_certs: no register: keycloak_auth_response until: keycloak_auth_response.status == 200 diff --git a/molecule/https_revproxy/converge.yml b/molecule/https_revproxy/converge.yml index b490721..b25d731 100644 --- a/molecule/https_revproxy/converge.yml +++ b/molecule/https_revproxy/converge.yml @@ -3,8 +3,8 @@ hosts: all vars: keycloak_quarkus_show_deprecation_warnings: false - keycloak_quarkus_admin_pass: "remembertochangeme" - keycloak_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_realm: TestRealm keycloak_quarkus_host: instance keycloak_quarkus_log: file diff --git a/molecule/quarkus-devmode/converge.yml b/molecule/quarkus-devmode/converge.yml index 2e5d351..5cd4ea1 100644 --- a/molecule/quarkus-devmode/converge.yml +++ b/molecule/quarkus-devmode/converge.yml @@ -3,8 +3,8 @@ hosts: all vars: keycloak_quarkus_show_deprecation_warnings: false - keycloak_quarkus_admin_pass: "remembertochangeme" - keycloak_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_realm: TestRealm keycloak_quarkus_log: file keycloak_quarkus_frontend_url: 'http://localhost:8080/' diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index 0860a42..d134203 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -3,8 +3,8 @@ hosts: all vars: keycloak_quarkus_show_deprecation_warnings: false - keycloak_quarkus_admin_pass: "remembertochangeme" - keycloak_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_realm: TestRealm keycloak_quarkus_host: instance keycloak_quarkus_log: file diff --git a/molecule/quarkus/verify.yml b/molecule/quarkus/verify.yml index 63769dc..1ee3b61 100644 --- a/molecule/quarkus/verify.yml +++ b/molecule/quarkus/verify.yml @@ -2,7 +2,7 @@ - name: Verify hosts: all vars: - keycloak_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" tasks: - name: Populate service facts ansible.builtin.service_facts: @@ -91,7 +91,7 @@ ansible.builtin.uri: url: "https://instance:8443/realms/master/protocol/openid-connect/token" method: POST - body: "client_id=admin-cli&username=admin&password={{ keycloak_admin_password }}&grant_type=password" + body: "client_id=admin-cli&username=admin&password={{ keycloak_quarkus_bootstrap_admin_user }}&grant_type=password" validate_certs: no register: keycloak_auth_response until: keycloak_auth_response.status == 200 diff --git a/molecule/quarkus_ha/converge.yml b/molecule/quarkus_ha/converge.yml index 00246b8..0455351 100644 --- a/molecule/quarkus_ha/converge.yml +++ b/molecule/quarkus_ha/converge.yml @@ -3,8 +3,8 @@ hosts: keycloak vars: keycloak_quarkus_show_deprecation_warnings: false - keycloak_quarkus_admin_pass: "remembertochangeme" - keycloak_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_realm: TestRealm keycloak_quarkus_host: "{{ inventory_hostname }}" keycloak_quarkus_log: file diff --git a/molecule/quarkus_upgrade/vars.yml b/molecule/quarkus_upgrade/vars.yml index 81d56b5..6a60844 100644 --- a/molecule/quarkus_upgrade/vars.yml +++ b/molecule/quarkus_upgrade/vars.yml @@ -1,7 +1,6 @@ --- keycloak_quarkus_offline_install: false -keycloak_quarkus_admin_password: "remembertochangeme" -keycloak_quarkus_admin_pass: "remembertochangeme" +keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_realm: TestRealm keycloak_quarkus_host: instance keycloak_quarkus_log: file diff --git a/molecule/quarkus_upgrade/verify.yml b/molecule/quarkus_upgrade/verify.yml index f5edfd0..3214d9f 100644 --- a/molecule/quarkus_upgrade/verify.yml +++ b/molecule/quarkus_upgrade/verify.yml @@ -2,7 +2,7 @@ - name: Verify hosts: instance vars: - keycloak_quarkus_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_port: http://localhost:8080 tasks: - name: Populate service facts @@ -24,7 +24,7 @@ ansible.builtin.uri: url: "{{ keycloak_quarkus_port }}/realms/master/protocol/openid-connect/token" method: POST - body: "client_id=admin-cli&username=admin&password={{ keycloak_quarkus_admin_password }}&grant_type=password" + body: "client_id=admin-cli&username=admin&password={{ keycloak_quarkus_bootstrap_admin_password }}&grant_type=password" validate_certs: no register: keycloak_auth_response until: keycloak_auth_response.status == 200 diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 9211b00..cf45cdf 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -44,7 +44,8 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| -|`keycloak_quarkus_admin_user`| Administration console user account | `admin` | +|`keycloak_quarkus_bootstrap_admin_user`| Administration console user account | `admin` | +|`keycloak_quarkus_admin_user`| Deprecated, use `keycloak_quarkus_bootstrap_admin_user` instead. | | |`keycloak_quarkus_bind_address`| Address for binding service ports | `0.0.0.0` | |`keycloak_quarkus_host`| Hostname for the Keycloak server | `localhost` | |`keycloak_quarkus_port`| The port used by the proxy when exposing the hostname | `-1` | @@ -243,7 +244,8 @@ Role Variables | Variable | Description | Required | |:---------|:------------|----------| -|`keycloak_quarkus_admin_pass`| Password of console admin account | `yes` | +|`keycloak_quarkus_bootstrap_admin_password`| Password of console admin account | `yes` | +|`keycloak_quarkus_admin_pass`| Deprecated, use `keycloak_quarkus_bootstrap_admin_password` instead. | | |`keycloak_quarkus_frontend_url`| Base URL for frontend URLs, including scheme, host, port and path | `no` | |`keycloak_quarkus_admin_url`| Base URL for accessing the administration console, including scheme, host, port and path | `no` | |`keycloak_quarkus_ks_vault_pass`| The password for accessing the keystore vault SPI | `no` | @@ -265,7 +267,7 @@ The role uses the following [custom facts](https://docs.ansible.com/ansible/late | Variable | Description | |:---------|:------------| -|`general.bootstrapped` | A custom fact indicating whether this role has been used for bootstrapping keycloak on the respective host before; set to `false` (e.g., when starting off with a new, empty database) ensures that the initial admin user as defined by `keycloak_quarkus_admin_user[_pass]` gets created | +|`general.bootstrapped` | A custom fact indicating whether this role has been used for bootstrapping keycloak on the respective host before; set to `false` (e.g., when starting off with a new, empty database) ensures that the initial admin user as defined by `keycloak_quarkus_bootstrap_admin_user[_password]` gets created | License ------- diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index ba9854b..f425396 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -27,8 +27,8 @@ keycloak_quarkus_configure_firewalld: false keycloak_quarkus_configure_iptables: false ### administrator console password -keycloak_quarkus_admin_user: admin -keycloak_quarkus_admin_pass: +keycloak_quarkus_bootstrap_admin_user: admin +keycloak_quarkus_bootstrap_admin_password: keycloak_quarkus_master_realm: master ### Configuration settings diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index d1a3a0e..f91bc90 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -68,13 +68,13 @@ argument_specs: default: "10s" description: "systemd RestartSec for service" type: "str" - keycloak_quarkus_admin_user: + keycloak_quarkus_bootstrap_admin_user: default: "admin" - description: "Administration console user account" + description: "Administration user account, only for bootstrapping" type: "str" - keycloak_quarkus_admin_pass: + keycloak_quarkus_bootstrap_admin_password: required: true - description: "Password of console admin account" + description: "Password of admin account, only for bootstrapping" type: "str" keycloak_quarkus_master_realm: default: "master" diff --git a/roles/keycloak_quarkus/tasks/deprecations.yml b/roles/keycloak_quarkus/tasks/deprecations.yml index 27ea6e3..fe269e9 100644 --- a/roles/keycloak_quarkus/tasks/deprecations.yml +++ b/roles/keycloak_quarkus/tasks/deprecations.yml @@ -49,5 +49,101 @@ notify: - print deprecation warning +# https://docs.redhat.com/en/documentation/red_hat_build_of_keycloak/26.0/html-single/upgrading_guide/index#new_hostname_options +- name: Check deprecation of keycloak_quarkus_frontend_url -> keycloak_quarkus_hostname + when: + - keycloak_quarkus_hostname is not defined + - keycloak_quarkus_frontend_url is defined + - keycloak_quarkus_frontend_url != '' + delegate_to: localhost + run_once: true + changed_when: keycloak_quarkus_show_deprecation_warnings + ansible.builtin.set_fact: + keycloak_quarkus_hostname: "{{ keycloak_quarkus_frontend_url }}" + deprecated_variable: "keycloak_quarkus_frontend_url" # read in deprecation handler + notify: + - print deprecation warning + +# https://docs.redhat.com/en/documentation/red_hat_build_of_keycloak/26.0/html-single/upgrading_guide/index#new_hostname_options +- name: Check deprecation of keycloak_quarkus_hostname_strict_https + keycloak_quarkus_host + keycloak_quarkus_port + keycloak_quarkus_path -> keycloak_quarkus_hostname + when: + - keycloak_quarkus_hostname is not defined + - keycloak_quarkus_hostname_strict_https is defined or keycloak_quarkus_frontend_url is defined or keycloak_quarkus_port is defined or keycloak_quarkus_path is defined + delegate_to: localhost + run_once: true + changed_when: keycloak_quarkus_show_deprecation_warnings + ansible.builtin.set_fact: + keycloak_quarkus_hostname: >- + {% set protocol = '' %} + {% if keycloak_quarkus_hostname_strict_https %} + {% set protocol = 'https://' %} + {% elif keycloak_quarkus_hostname_strict_https is defined and keycloak_quarkus_hostname_strict_https is False %} + {% set protocol = 'http://' %} + {% endif %} + {{ protocol }}{{ keycloak_quarkus_host }}:{{ keycloak_quarkus_port }}/{{ keycloak_quarkus_path }} + deprecated_variable: "keycloak_quarkus_hostname_strict_https or keycloak_quarkus_frontend_url or keycloak_quarkus_frontend_url or keycloak_quarkus_hostname" # read in deprecation handler + notify: + - print deprecation warning + +# https://docs.redhat.com/en/documentation/red_hat_build_of_keycloak/26.0/html-single/upgrading_guide/index#new_hostname_options +- name: Check deprecation of keycloak_quarkus_admin_url -> keycloak_quarkus_admin + when: + - keycloak_quarkus_admin is not defined + - keycloak_quarkus_admin_url is defined + - keycloak_quarkus_admin_url != '' + delegate_to: localhost + run_once: true + changed_when: keycloak_quarkus_show_deprecation_warnings + ansible.builtin.set_fact: + keycloak_quarkus_admin: "{{ keycloak_quarkus_admin_url }}" + deprecated_variable: "keycloak_quarkus_admin_url" # read in deprecation handler + notify: + - print deprecation warning + +# https://docs.redhat.com/en/documentation/red_hat_build_of_keycloak/26.0/html-single/upgrading_guide/index#new_hostname_options +- name: Check deprecation of keycloak_quarkus_hostname_strict_backchannel -> keycloak_quarkus_hostname_backchannel_dynamic + when: + - keycloak_quarkus_hostname_backchannel_dynamic is not defined + - keycloak_quarkus_hostname_strict_backchannel is defined + - keycloak_quarkus_hostname_strict_backchannel != '' + delegate_to: localhost + run_once: true + changed_when: keycloak_quarkus_show_deprecation_warnings + ansible.builtin.set_fact: + keycloak_quarkus_hostname_backchannel_dynamic: "{{ keycloak_quarkus_hostname_strict_backchannel == False }}" + deprecated_variable: "keycloak_quarkus_hostname_backchannel_dynamic" # read in deprecation handler + notify: + - print deprecation warning + +# https://github.com/keycloak/keycloak/issues/30009 +- name: Check deprecation of keycloak_quarkus_admin_user -> keycloak_quarkus_bootstrap_admin_user + when: + - keycloak_quarkus_bootstrap_admin_user is not defined + - keycloak_quarkus_admin_user is defined + - keycloak_quarkus_admin_user != '' + delegate_to: localhost + run_once: true + changed_when: keycloak_quarkus_show_deprecation_warnings + ansible.builtin.set_fact: + keycloak_quarkus_bootstrap_admin_user: "{{ keycloak_quarkus_admin_user }}" + deprecated_variable: "keycloak_quarkus_admin_user" # read in deprecation handler + notify: + - print deprecation warning + +# https://github.com/keycloak/keycloak/issues/30009 +- name: Check deprecation of keycloak_quarkus_admin_pass -> keycloak_quarkus_bootstrap_admin_password + when: + - keycloak_quarkus_bootstrap_admin_password is not defined + - keycloak_quarkus_admin_pass is defined + - keycloak_quarkus_admin_pass != '' + delegate_to: localhost + run_once: true + changed_when: keycloak_quarkus_show_deprecation_warnings + ansible.builtin.set_fact: + keycloak_quarkus_bootstrap_admin_user: "{{ keycloak_quarkus_admin_pass }}" + deprecated_variable: "keycloak_quarkus_admin_pass" # read in deprecation handler + notify: + - print deprecation warning + - name: Flush handlers ansible.builtin.meta: flush_handlers diff --git a/roles/keycloak_quarkus/tasks/main.yml b/roles/keycloak_quarkus/tasks/main.yml index bb86b2c..cca6764 100644 --- a/roles/keycloak_quarkus/tasks/main.yml +++ b/roles/keycloak_quarkus/tasks/main.yml @@ -91,7 +91,7 @@ register: keycloak_service_status changed_when: false -- name: "Notify to remove `keycloak_quarkus_admin_user[_pass]` env vars" +- name: "Notify to remove `keycloak_quarkus_bootstrap_admin_user[_password]` env vars" when: - not ansible_local.keycloak.general.bootstrapped | default(false) | bool # it was not bootstrapped prior to the current role's execution - keycloak_service_status.status.ActiveState == "active" # but it is now diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index 0835aab..db7555e 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -2,9 +2,9 @@ - name: Validate admin console password ansible.builtin.assert: that: - - keycloak_quarkus_admin_pass | length > 12 + - keycloak_quarkus_bootstrap_admin_password | length > 12 quiet: true - fail_msg: "The console administrator password is empty or invalid. Please set the keycloak_quarkus_admin_pass to a 12+ char long string" + fail_msg: "The console administrator password is empty or invalid. Please set the keycloak_quarkus_bootstrap_admin_password to a 12+ char long string" success_msg: "{{ 'Console administrator password OK' }}" - name: Validate relative path diff --git a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 index 2c260a3..244d9aa 100644 --- a/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 +++ b/roles/keycloak_quarkus/templates/keycloak-sysconfig.j2 @@ -1,7 +1,7 @@ {{ ansible_managed | comment }} {% if not ansible_local.keycloak.general.bootstrapped | default(false) | bool %} -KEYCLOAK_ADMIN={{ keycloak_quarkus_admin_user }} -KEYCLOAK_ADMIN_PASSWORD='{{ keycloak_quarkus_admin_pass }}' +KC_BOOTSTRAP_ADMIN_USERNAME={{ keycloak_quarkus_bootstrap_admin_user }} +KC_BOOTSTRAP_ADMIN_PASSWORD='{{ keycloak_quarkus_bootstrap_admin_password }}' {% else %} {{ keycloak.bootstrap_mnemonic }} {% endif %} From 213449ec58813bb038ceb79ce4ddc2f887c10cf7 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 9 Dec 2024 15:35:05 +0100 Subject: [PATCH 187/205] RHBK v26: Add hostname v2 (KC/RHBK v26 Support #253) Cf. https://docs.redhat.com/en/documentation/red_hat_build_of_keycloak/26.0/html-single/upgrading_guide/index#new_hostname_options - especially the removed options --- molecule/debian/converge.yml | 2 +- molecule/default/converge.yml | 2 +- molecule/https_revproxy/converge.yml | 2 +- molecule/quarkus/converge.yml | 2 +- molecule/quarkus_ha/converge.yml | 2 +- molecule/quarkus_upgrade/vars.yml | 2 +- playbooks/keycloak_quarkus.yml | 2 +- playbooks/keycloak_quarkus_dev.yml | 2 +- roles/keycloak_quarkus/README.md | 16 +++++---- roles/keycloak_quarkus/defaults/main.yml | 13 +++---- .../keycloak_quarkus/meta/argument_specs.yml | 34 +++++++++---------- .../templates/keycloak.conf.j2 | 19 ++--------- roles/keycloak_quarkus/vars/main.yml | 2 +- 13 files changed, 43 insertions(+), 57 deletions(-) diff --git a/molecule/debian/converge.yml b/molecule/debian/converge.yml index a3ba17a..7fab040 100644 --- a/molecule/debian/converge.yml +++ b/molecule/debian/converge.yml @@ -5,7 +5,7 @@ keycloak_quarkus_show_deprecation_warnings: false keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" - keycloak_quarkus_host: instance + keycloak_quarkus_hostname: http://instance keycloak_quarkus_log: file keycloak_quarkus_start_dev: true keycloak_quarkus_proxy_mode: none diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index 543b003..13a771b 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -5,7 +5,7 @@ keycloak_quarkus_show_deprecation_warnings: false keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" - keycloak_quarkus_host: instance + keycloak_quarkus_hostname: http://instance keycloak_quarkus_log: file keycloak_quarkus_log_level: debug keycloak_quarkus_log_target: /tmp/keycloak diff --git a/molecule/https_revproxy/converge.yml b/molecule/https_revproxy/converge.yml index b25d731..7245265 100644 --- a/molecule/https_revproxy/converge.yml +++ b/molecule/https_revproxy/converge.yml @@ -6,7 +6,7 @@ keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_realm: TestRealm - keycloak_quarkus_host: instance + keycloak_quarkus_hostname: http://instance keycloak_quarkus_log: file keycloak_quarkus_http_enabled: True keycloak_quarkus_http_port: 8080 diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index d134203..9b7b3a7 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -6,7 +6,7 @@ keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_realm: TestRealm - keycloak_quarkus_host: instance + keycloak_quarkus_hostname: http://instance keycloak_quarkus_log: file keycloak_quarkus_log_level: debug # needed for the verify step keycloak_quarkus_https_key_file_enabled: true diff --git a/molecule/quarkus_ha/converge.yml b/molecule/quarkus_ha/converge.yml index 0455351..238fbb5 100644 --- a/molecule/quarkus_ha/converge.yml +++ b/molecule/quarkus_ha/converge.yml @@ -6,7 +6,7 @@ keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_realm: TestRealm - keycloak_quarkus_host: "{{ inventory_hostname }}" + keycloak_quarkus_hostname: "http://{{ inventory_hostname }}" keycloak_quarkus_log: file keycloak_quarkus_log_level: info keycloak_quarkus_https_key_file_enabled: true diff --git a/molecule/quarkus_upgrade/vars.yml b/molecule/quarkus_upgrade/vars.yml index 6a60844..52ab103 100644 --- a/molecule/quarkus_upgrade/vars.yml +++ b/molecule/quarkus_upgrade/vars.yml @@ -2,7 +2,7 @@ keycloak_quarkus_offline_install: false keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_realm: TestRealm -keycloak_quarkus_host: instance +keycloak_quarkus_hostname: http://instance keycloak_quarkus_log: file keycloak_quarkus_https_key_file_enabled: true keycloak_quarkus_log_target: /tmp/keycloak diff --git a/playbooks/keycloak_quarkus.yml b/playbooks/keycloak_quarkus.yml index f2649a5..84d1774 100644 --- a/playbooks/keycloak_quarkus.yml +++ b/playbooks/keycloak_quarkus.yml @@ -3,7 +3,7 @@ hosts: all vars: keycloak_quarkus_admin_pass: "remembertochangeme" - keycloak_quarkus_host: localhost + keycloak_quarkus_hostname: http://localhost keycloak_quarkus_port: 8443 keycloak_quarkus_log: file keycloak_quarkus_proxy_mode: none diff --git a/playbooks/keycloak_quarkus_dev.yml b/playbooks/keycloak_quarkus_dev.yml index 533db79..0c74c36 100644 --- a/playbooks/keycloak_quarkus_dev.yml +++ b/playbooks/keycloak_quarkus_dev.yml @@ -3,7 +3,7 @@ hosts: all vars: keycloak_admin_password: "remembertochangeme" - keycloak_quarkus_host: localhost + keycloak_quarkus_hostname: http://localhost keycloak_quarkus_port: 8080 keycloak_quarkus_log: file keycloak_quarkus_start_dev: true diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index cf45cdf..7f0542a 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -47,9 +47,9 @@ Role Defaults |`keycloak_quarkus_bootstrap_admin_user`| Administration console user account | `admin` | |`keycloak_quarkus_admin_user`| Deprecated, use `keycloak_quarkus_bootstrap_admin_user` instead. | | |`keycloak_quarkus_bind_address`| Address for binding service ports | `0.0.0.0` | -|`keycloak_quarkus_host`| Hostname for the Keycloak server | `localhost` | -|`keycloak_quarkus_port`| The port used by the proxy when exposing the hostname | `-1` | -|`keycloak_quarkus_path`| This should be set if proxy uses a different context-path for Keycloak | | +|`keycloak_quarkus_host`| Deprecated, use `keycloak_quarkus_hostname` instead. | | +|`keycloak_quarkus_port`| Deprecated, use `keycloak_quarkus_hostname` instead. | | +|`keycloak_quarkus_path`| Deprecated, use `keycloak_quarkus_hostname` instead. | | |`keycloak_quarkus_http_port`| HTTP listening port | `8080` | |`keycloak_quarkus_https_port`| TLS HTTP listening port | `8443` | |`keycloak_quarkus_ajp_port`| AJP port | `8009` | @@ -64,8 +64,10 @@ Role Defaults |`keycloak_quarkus_java_jvm_opts`| Other JVM settings | same as keycloak | |`keycloak_quarkus_java_opts`| JVM arguments; if overridden, it takes precedence over `keycloak_quarkus_java_*` | `{{ keycloak_quarkus_java_heap_opts + ' ' + keycloak_quarkus_java_jvm_opts }}` | |`keycloak_quarkus_additional_env_vars` | List of additional env variables of { key: str, value: str} to be put in sysconfig file | `[]` | -|`keycloak_quarkus_frontend_url`| Set the base URL for frontend URLs, including scheme, host, port and path | | -|`keycloak_quarkus_admin_url`| Set the base URL for accessing the administration console, including scheme, host, port and path | | +|`keycloak_quarkus_hostname`| Address at which is the server exposed. Can be a full URL, or just a hostname. When only hostname is provided, scheme, port and context path are resolved from the request. | | +|`keycloak_quarkus_frontend_url`| Deprecated, use `keycloak_quarkus_hostname` instead. | | +|`keycloak_quarkus_admin`| Set the base URL for accessing the administration console, including scheme, host, port and path | | +|`keycloak_quarkus_admin_url`| Deprecated, use `keycloak_quarkus_admin` instead. | | |`keycloak_quarkus_http_relative_path` | Set the path relative to / for serving resources. The path must start with a / | `/` | |`keycloak_quarkus_http_enabled`| Enable listener on HTTP port | `True` | |`keycloak_quarkus_health_check_url_path`| Path to the health check endpoint; scheme, host and keycloak_quarkus_http_relative_path will be prepended automatically | `realms/master/.well-known/openid-configuration` | @@ -117,7 +119,8 @@ Role Defaults |:---------|:------------|:--------| |`keycloak_quarkus_http_relative_path`| Set the path relative to / for serving resources. The path must start with a / | `/` | |`keycloak_quarkus_hostname_strict`| Disables dynamically resolving the hostname from request headers | `true` | -|`keycloak_quarkus_hostname_strict_backchannel`| By default backchannel URLs are dynamically resolved from request headers to allow internal and external applications. If all applications use the public URL this option should be enabled. | `false` | +|`keycloak_quarkus_hostname_backchannel_dynamic`| Enables dynamic resolving of backchannel URLs, including hostname, scheme, port and context path. Set to true if your application accesses Keycloak via a private network. If set to true, hostname option needs to be specified as a full URL. | `false` | +|`keycloak_quarkus_hostname_strict_backchannel`| Deprecated, use (the inverted!)`keycloak_quarkus_hostname_backchannel_dynamic` instead. | | #### Database configuration @@ -157,7 +160,6 @@ Role Defaults |`keycloak_quarkus_master_realm` | Name for rest authentication realm | `master` | |`keycloak_auth_client` | Authentication client for configuration REST calls | `admin-cli` | |`keycloak_force_install` | Remove pre-existing versions of service | `False` | -|`keycloak_url` | URL for configuration rest calls | `http://{{ keycloak_quarkus_host }}:{{ keycloak_http_port }}` | |`keycloak_quarkus_log`| Enable one or more log handlers in a comma-separated list | `file` | |`keycloak_quarkus_log_level`| The log level of the root category or a comma-separated list of individual categories and their levels | `info` | |`keycloak_quarkus_log_file`| Set the log file path and filename relative to keycloak home | `data/log/keycloak.log` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index f425396..805b102 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -33,9 +33,6 @@ keycloak_quarkus_master_realm: master ### Configuration settings keycloak_quarkus_bind_address: 0.0.0.0 -keycloak_quarkus_host: localhost -keycloak_quarkus_port: -1 -keycloak_quarkus_path: keycloak_quarkus_http_enabled: true keycloak_quarkus_http_port: 8080 keycloak_quarkus_https_port: 8443 @@ -81,8 +78,8 @@ keycloak_quarkus_systemd_wait_for_timeout: 60 keycloak_quarkus_systemd_wait_for_delay: 10 ### keycloak frontend url -keycloak_quarkus_frontend_url: -keycloak_quarkus_admin_url: +keycloak_quarkus_hostname: +keycloak_quarkus_admin: ### Set the path relative to / for serving resources. The path must start with a / ### (set to `/auth` for retrocompatibility with pre-quarkus releases) @@ -91,9 +88,9 @@ keycloak_quarkus_http_relative_path: / # Disables dynamically resolving the hostname from request headers. # Should always be set to true in production, unless proxy verifies the Host header. keycloak_quarkus_hostname_strict: true -# By default backchannel URLs are dynamically resolved from request headers to allow internal and external applications. -# If all applications use the public URL this option should be enabled. -keycloak_quarkus_hostname_strict_backchannel: false +# Enables dynamic resolving of backchannel URLs, including hostname, scheme, port and context path. +# Set to true if your application accesses Keycloak via a private network. If set to true, keycloak_quarkus_hostname option needs to be specified as a full URL. +keycloak_quarkus_hostname_backchannel_dynamic: false # The proxy headers that should be accepted by the server. ['', 'forwarded', 'xforwarded'] keycloak_quarkus_proxy_headers: "" diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index f91bc90..b7a9ffe 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -84,17 +84,19 @@ argument_specs: default: "0.0.0.0" description: "Address for binding service ports" type: "str" + keycloak_quarkus_hostname: + description: >- + Address at which is the server exposed. + Can be a full URL, or just a hostname. When only hostname is provided, scheme, port and context path are resolved from the request. + type: "str" keycloak_quarkus_host: - default: "localhost" - description: "Hostname for the Keycloak server" + description: "Deprecated in v26, use keycloak_quarkus_hostname instead." type: "str" keycloak_quarkus_port: - default: -1 - description: "The port used by the proxy when exposing the hostname" + description: "Deprecated in v26, use keycloak_quarkus_hostname instead." type: "int" keycloak_quarkus_path: - required: false - description: "This should be set if proxy uses a different context-path for Keycloak" + description: "Deprecated in v26, use keycloak_quarkus_hostname instead." type: "str" keycloak_quarkus_http_enabled: default: true @@ -228,11 +230,15 @@ argument_specs: type: "str" keycloak_quarkus_frontend_url: required: false - description: "Service public URL" + description: "Deprecated in v26, use keycloak_quarkus_hostname instead." + type: "str" + keycloak_quarkus_admin: + required: false + description: "Service URL for the admin console" type: "str" keycloak_quarkus_admin_url: required: false - description: "Service URL for the admin console" + description: "Deprecated in v26, use keycloak_quarkus_admin instead." type: "str" keycloak_quarkus_metrics_enabled: default: false @@ -348,24 +354,18 @@ argument_specs: description: > Disables dynamically resolving the hostname from request headers. Should always be set to true in production, unless proxy verifies the Host header. - keycloak_quarkus_hostname_strict_backchannel: + keycloak_quarkus_hostname_backchannel_dynamic: default: false type: "bool" description: > - By default backchannel URLs are dynamically resolved from request headers to allow internal and external applications. If all - applications use the public URL this option should be enabled. + Enables dynamic resolving of backchannel URLs, including hostname, scheme, port and context path. + Set to true if your application accesses Keycloak via a private network. If set to true, hostname option needs to be specified as a full URL. keycloak_quarkus_spi_sticky_session_encoder_infinispan_should_attach_route: default: true type: "bool" description: > If the route should be attached to cookies to reflect the node that owns a particular session. If false, route is not attached to cookies and we rely on the session affinity capabilities from reverse proxy - keycloak_quarkus_hostname_strict_https: - type: "bool" - required: false - description: > - By default, Keycloak requires running using TLS/HTTPS. If the service MUST run without TLS/HTTPS, then set - this option to "true" keycloak_quarkus_ks_vault_enabled: default: false type: "bool" diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index 24972c3..c535738 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -10,13 +10,6 @@ db-password={{ keycloak_quarkus_db_pass }} {% endif %} {% endif %} -{% if keycloak_quarkus_hostname_strict_https is defined and keycloak_quarkus_hostname_strict_https is sameas true -%} -hostname-strict-https=true -{% endif -%} -{% if keycloak_quarkus_hostname_strict_https is defined and keycloak_quarkus_hostname_strict_https is sameas false -%} -hostname-strict-https=false -{% endif -%} - {% if keycloak.config_key_store_enabled %} # Config store config-keystore={{ keycloak_quarkus_config_key_store_file }} @@ -48,16 +41,10 @@ https-trust-store-password={{ keycloak_quarkus_https_trust_store_password }} {% endif %} # Client URL configuration -{% if keycloak_quarkus_frontend_url %} -hostname-url={{ keycloak_quarkus_frontend_url }} -{% else %} -hostname={{ keycloak_quarkus_host }} -hostname-port={{ keycloak_quarkus_port }} -hostname-path={{ keycloak_quarkus_path }} -{% endif %} -hostname-admin-url={{ keycloak_quarkus_admin_url }} +hostname={{ keycloak_quarkus_hostname }} +hostname-admin={{ keycloak_quarkus_admin }} hostname-strict={{ keycloak_quarkus_hostname_strict | lower }} -hostname-strict-backchannel={{ keycloak_quarkus_hostname_strict_backchannel | lower }} +hostname-backchannel-dynamic={{ keycloak_quarkus_hostname_backchannel_dynamic | lower }} # Cluster {% if keycloak_quarkus_ha_enabled %} diff --git a/roles/keycloak_quarkus/vars/main.yml b/roles/keycloak_quarkus/vars/main.yml index e59af55..eb654f2 100644 --- a/roles/keycloak_quarkus/vars/main.yml +++ b/roles/keycloak_quarkus/vars/main.yml @@ -4,7 +4,7 @@ keycloak: # noqa var-naming this is an internal dict of interpolated values config_dir: "{{ keycloak_quarkus_config_dir }}" bundle: "{{ keycloak_quarkus_archive }}" service_name: "keycloak" - health_url: "{{ 'https' if keycloak_quarkus_http_enabled == False else 'http' }}://{{ keycloak_quarkus_host }}:{{ keycloak_quarkus_https_port if keycloak_quarkus_http_enabled == False else keycloak_quarkus_http_port }}{{ keycloak_quarkus_http_relative_path }}{{ '/' \ + health_url: "{{ keycloak_quarkus_hostname }}{{ keycloak_quarkus_http_relative_path }}{{ '/' \ if keycloak_quarkus_http_relative_path | length > 1 else '' }}{{ keycloak_quarkus_health_check_url_path | default('realms/master/.well-known/openid-configuration') }}" cli_path: "{{ keycloak_quarkus_home }}/bin/kcadm.sh" service_user: "{{ keycloak_quarkus_service_user }}" From d0f19b59dc326951b24a7909822e1689ae9fb79e Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 10 Dec 2024 14:14:18 +0100 Subject: [PATCH 188/205] keycloak_quarkus: Add http_management_port and http_management_relative_path options RHBK v26 exposes health endpoints and metrics on this port moving forward. Note that the scheme of the MGMT interface is defined by the overall keycloak configuration: if https is enabled and configured, th MGMT interface is exposed via https and NOT via http; this might be breaking some configured load balancer health checks --- roles/keycloak_quarkus/README.md | 4 +++- roles/keycloak_quarkus/defaults/main.yml | 1 + roles/keycloak_quarkus/meta/argument_specs.yml | 12 ++++++++++-- roles/keycloak_quarkus/tasks/firewalld.yml | 13 ++++++++++++- roles/keycloak_quarkus/tasks/prereqs.yml | 11 ++++++++++- roles/keycloak_quarkus/templates/keycloak.conf.j2 | 8 ++++++++ 6 files changed, 44 insertions(+), 5 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 7f0542a..0c8aec8 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -52,6 +52,7 @@ Role Defaults |`keycloak_quarkus_path`| Deprecated, use `keycloak_quarkus_hostname` instead. | | |`keycloak_quarkus_http_port`| HTTP listening port | `8080` | |`keycloak_quarkus_https_port`| TLS HTTP listening port | `8443` | +|`keycloak_quarkus_http_management_port`| Port of the management interface. Relevant only when something is exposed on the management interface - see the guide for details. | `9000` | |`keycloak_quarkus_ajp_port`| AJP port | `8009` | |`keycloak_quarkus_service_user`| Posix account username | `keycloak` | |`keycloak_quarkus_service_group`| Posix account group | `keycloak` | @@ -69,6 +70,7 @@ Role Defaults |`keycloak_quarkus_admin`| Set the base URL for accessing the administration console, including scheme, host, port and path | | |`keycloak_quarkus_admin_url`| Deprecated, use `keycloak_quarkus_admin` instead. | | |`keycloak_quarkus_http_relative_path` | Set the path relative to / for serving resources. The path must start with a / | `/` | +|`keycloak_quarkus_http_management_relative_path` | Set the path relative to / for serving resources from management interface. The path must start with a /. If not given, the value is inherited from HTTP options. Relevant only when something is exposed on the management interface - see the guide for details. | `/` | |`keycloak_quarkus_http_enabled`| Enable listener on HTTP port | `True` | |`keycloak_quarkus_health_check_url_path`| Path to the health check endpoint; scheme, host and keycloak_quarkus_http_relative_path will be prepended automatically | `realms/master/.well-known/openid-configuration` | |`keycloak_quarkus_https_key_file_enabled`| Enable listener on HTTPS port | `False` | @@ -152,7 +154,7 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| |`keycloak_quarkus_metrics_enabled`| Whether to enable metrics | `False` | -|`keycloak_quarkus_health_enabled`| If the server should expose health check endpoints | `True` | +|`keycloak_quarkus_health_enabled`| If the server should expose health check endpoints on the management interface | `True` | |`keycloak_quarkus_archive` | keycloak install archive filename | `keycloak-{{ keycloak_quarkus_version }}.zip` | |`keycloak_quarkus_installdir` | Installation path | `{{ keycloak_quarkus_dest }}/keycloak-{{ keycloak_quarkus_version }}` | |`keycloak_quarkus_home` | Installation work directory | `{{ keycloak_quarkus_installdir }}` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 805b102..05e0455 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -36,6 +36,7 @@ keycloak_quarkus_bind_address: 0.0.0.0 keycloak_quarkus_http_enabled: true keycloak_quarkus_http_port: 8080 keycloak_quarkus_https_port: 8443 +keycloak_quarkus_http_management_port: 9000 keycloak_quarkus_ajp_port: 8009 keycloak_quarkus_jgroups_port: 7800 keycloak_quarkus_java_heap_opts: "-Xms1024m -Xmx2048m" diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index b7a9ffe..2bfbf50 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -108,7 +108,7 @@ argument_specs: type: "int" keycloak_quarkus_health_check_url_path: default: "realms/master/.well-known/openid-configuration" - description: "Path to the health check endpoint; scheme, host and keycloak_quarkus_http_relative_path will be prepended automatically" + description: "Path to the health check endpoint; scheme, hostname will be prepended automatically" type: "str" keycloak_quarkus_https_key_file_enabled: default: false @@ -184,6 +184,10 @@ argument_specs: default: 8443 description: "HTTPS port" type: "int" + keycloak_quarkus_http_management_port: + default: 9000 + description: "Port of the management interface. Relevant only when something is exposed on the management interface - see the guide for details." + type: "int" keycloak_quarkus_ajp_port: default: 8009 description: "AJP port" @@ -228,6 +232,10 @@ argument_specs: default: / description: "Set the path relative to / for serving resources. The path must start with a /" type: "str" + keycloak_quarkus_http_management_relative_path: + required: false + description: "Set the path relative to / for serving resources from management interface. The path must start with a /. If not given, the value is inherited from HTTP options. Relevant only when something is exposed on the management interface - see the guide for details." + type: "str" keycloak_quarkus_frontend_url: required: false description: "Deprecated in v26, use keycloak_quarkus_hostname instead." @@ -246,7 +254,7 @@ argument_specs: type: "bool" keycloak_quarkus_health_enabled: default: true - description: "If the server should expose health check endpoints" + description: "If the server should expose health check endpoints on the management interface" type: "bool" keycloak_quarkus_ispn_user: default: "supervisor" diff --git a/roles/keycloak_quarkus/tasks/firewalld.yml b/roles/keycloak_quarkus/tasks/firewalld.yml index 2c3ef74..2d48124 100644 --- a/roles/keycloak_quarkus/tasks/firewalld.yml +++ b/roles/keycloak_quarkus/tasks/firewalld.yml @@ -12,7 +12,7 @@ enabled: true state: started -- name: "Configure firewall for {{ keycloak.service_name }} ports" +- name: "Configure firewall for {{ keycloak.service_name }} http port" become: true ansible.posix.firewalld: port: "{{ item }}" @@ -21,5 +21,16 @@ immediate: true loop: - "{{ keycloak_quarkus_http_port }}/tcp" + when: keycloak_quarkus_http_enabled | bool + +- name: "Configure firewall for {{ keycloak.service_name }} ports" + become: true + ansible.posix.firewalld: + port: "{{ item }}" + permanent: true + state: enabled + immediate: true + loop: - "{{ keycloak_quarkus_https_port }}/tcp" + - "{{ keycloak_quarkus_http_management_port }}/tcp" - "{{ keycloak_quarkus_jgroups_port }}/tcp" diff --git a/roles/keycloak_quarkus/tasks/prereqs.yml b/roles/keycloak_quarkus/tasks/prereqs.yml index db7555e..9b633f3 100644 --- a/roles/keycloak_quarkus/tasks/prereqs.yml +++ b/roles/keycloak_quarkus/tasks/prereqs.yml @@ -7,7 +7,7 @@ fail_msg: "The console administrator password is empty or invalid. Please set the keycloak_quarkus_bootstrap_admin_password to a 12+ char long string" success_msg: "{{ 'Console administrator password OK' }}" -- name: Validate relative path +- name: Validate http_relative_path ansible.builtin.assert: that: - keycloak_quarkus_http_relative_path is regex('^/.*') @@ -15,6 +15,15 @@ fail_msg: "The relative path for keycloak_quarkus_http_relative_path must begin with /" success_msg: "{{ 'Relative path OK' }}" +- name: Validate http_management_relative_path + ansible.builtin.assert: + that: + - keycloak_quarkus_http_management_relative_path is regex('^/.*') + quiet: true + fail_msg: "The relative path for keycloak_quarkus_http_management_relative_path must begin with /" + success_msg: "{{ 'Relative mgmt path OK' }}" + when: keycloak_quarkus_http_management_relative_path is defined + - name: Validate configuration ansible.builtin.assert: that: diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index c535738..f11e3ec 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -22,9 +22,17 @@ health-enabled={{ keycloak_quarkus_health_enabled | lower }} # HTTP http-enabled={{ keycloak_quarkus_http_enabled | lower }} +{% if keycloak_quarkus_http_enabled %} http-port={{ keycloak_quarkus_http_port }} +{% endif %} http-relative-path={{ keycloak_quarkus_http_relative_path }} +# Management +http-management-port={{ keycloak_quarkus_http_management_port }} +{% if keycloak_quarkus_http_management_relative_path is defined and keycloak_quarkus_http_management_relative_path | length > 0 %} +http-management-relative-path={{ keycloak_quarkus_http_management_relative_path }} +{% endif %} + # HTTPS https-port={{ keycloak_quarkus_https_port }} {% if keycloak_quarkus_https_key_file_enabled %} From e029e1c2fd0d86d765e824d78cb6c348f28efc8e Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Fri, 13 Dec 2024 12:02:06 +0100 Subject: [PATCH 189/205] keycloak_quarkus: Introduce keycloak_quarkus_health_check_url --- roles/keycloak_quarkus/README.md | 3 ++- roles/keycloak_quarkus/meta/argument_specs.yml | 5 ++++- roles/keycloak_quarkus/vars/main.yml | 3 +-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 0c8aec8..d3abd57 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -72,7 +72,8 @@ Role Defaults |`keycloak_quarkus_http_relative_path` | Set the path relative to / for serving resources. The path must start with a / | `/` | |`keycloak_quarkus_http_management_relative_path` | Set the path relative to / for serving resources from management interface. The path must start with a /. If not given, the value is inherited from HTTP options. Relevant only when something is exposed on the management interface - see the guide for details. | `/` | |`keycloak_quarkus_http_enabled`| Enable listener on HTTP port | `True` | -|`keycloak_quarkus_health_check_url_path`| Path to the health check endpoint; scheme, host and keycloak_quarkus_http_relative_path will be prepended automatically | `realms/master/.well-known/openid-configuration` | +|`keycloak_quarkus_health_check_url`| Full URL (including scheme, host, path, fragment etc.) used for health check endpoint; keycloak_quarkus_hostname will NOT be prepended; helpful when health checks should happen against http port, but keycloak_quarkus_hostname uses https scheme per default | `` | +|`keycloak_quarkus_health_check_url_path`| Path to the health check endpoint; keycloak_quarkus_hostname will be prepended automatically; Note that keycloak_quarkus_health_check_url takes precedence over this property | `realms/master/.well-known/openid-configuration` | |`keycloak_quarkus_https_key_file_enabled`| Enable listener on HTTPS port | `False` | |`keycloak_quarkus_key_file_copy_enabled`| Enable copy of key file to target host | `False` | |`keycloak_quarkus_key_content`| Content of the TLS private key. Use `"{{ lookup('file', 'server.key.pem') }}"` to lookup a file. | `""` | diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 2bfbf50..0e4eb42 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -106,9 +106,12 @@ argument_specs: default: 8080 description: "HTTP port" type: "int" + keycloak_quarkus_health_check_url: + description: "Full URL (including scheme, host, path, fragment etc.) used for health check endpoint; keycloak_quarkus_hostname will NOT be prepended; helpful when health checks should happen against http port, but keycloak_quarkus_hostname uses https scheme per default" + type: "str" keycloak_quarkus_health_check_url_path: default: "realms/master/.well-known/openid-configuration" - description: "Path to the health check endpoint; scheme, hostname will be prepended automatically" + description: "Path to the health check endpoint; keycloak_quarkus_hostname will be prepended automatically; Note that keycloak_quarkus_health_check_url takes precedence over this property" type: "str" keycloak_quarkus_https_key_file_enabled: default: false diff --git a/roles/keycloak_quarkus/vars/main.yml b/roles/keycloak_quarkus/vars/main.yml index eb654f2..2efe5e6 100644 --- a/roles/keycloak_quarkus/vars/main.yml +++ b/roles/keycloak_quarkus/vars/main.yml @@ -4,8 +4,7 @@ keycloak: # noqa var-naming this is an internal dict of interpolated values config_dir: "{{ keycloak_quarkus_config_dir }}" bundle: "{{ keycloak_quarkus_archive }}" service_name: "keycloak" - health_url: "{{ keycloak_quarkus_hostname }}{{ keycloak_quarkus_http_relative_path }}{{ '/' \ - if keycloak_quarkus_http_relative_path | length > 1 else '' }}{{ keycloak_quarkus_health_check_url_path | default('realms/master/.well-known/openid-configuration') }}" + health_url: "{{ keycloak_quarkus_health_check_url | default(keycloak_quarkus_hostname + '/' + (keycloak_quarkus_health_check_url_path | default('realms/master/.well-known/openid-configuration'))) }}" cli_path: "{{ keycloak_quarkus_home }}/bin/kcadm.sh" service_user: "{{ keycloak_quarkus_service_user }}" service_group: "{{ keycloak_quarkus_service_group }}" From b3e93dd89b8506d3a6f283491987286d15c5185b Mon Sep 17 00:00:00 2001 From: Nils Deckert Date: Fri, 20 Dec 2024 17:21:01 +0100 Subject: [PATCH 190/205] Skip certificate checking --- roles/keycloak_realm/tasks/main.yml | 1 + roles/keycloak_realm/tasks/manage_user_client_roles.yml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/roles/keycloak_realm/tasks/main.yml b/roles/keycloak_realm/tasks/main.yml index 8f33fcc..7595ba3 100644 --- a/roles/keycloak_realm/tasks/main.yml +++ b/roles/keycloak_realm/tasks/main.yml @@ -15,6 +15,7 @@ ansible.builtin.uri: url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ keycloak_realm }}" method: GET + validate_certs: false status_code: - 200 - 404 diff --git a/roles/keycloak_realm/tasks/manage_user_client_roles.yml b/roles/keycloak_realm/tasks/manage_user_client_roles.yml index 3884f42..f9e0329 100644 --- a/roles/keycloak_realm/tasks/manage_user_client_roles.yml +++ b/roles/keycloak_realm/tasks/manage_user_client_roles.yml @@ -3,6 +3,7 @@ ansible.builtin.uri: url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm | default(keycloak_realm) }}" method: GET + validate_certs: false status_code: - 200 headers: @@ -16,6 +17,7 @@ default(keycloak_realm) }}/users/{{ (keycloak_user.json | first).id }}/role-mappings/clients/{{ (create_client_result.results | \ selectattr('end_state.clientId', 'equalto', client_role.client) | list | first).end_state.id }}/available" method: GET + validate_certs: false status_code: - 200 headers: From 86284b12c28f578910ecd3cd200cab9679b6d8ee Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Tue, 10 Dec 2024 15:10:29 +0100 Subject: [PATCH 191/205] Fix molecule tests --- molecule/debian/converge.yml | 5 ++++- molecule/debian/prepare.yml | 1 + molecule/default/converge.yml | 5 ++++- molecule/default/molecule.yml | 1 + molecule/default/prepare.yml | 2 +- molecule/default/verify.yml | 3 ++- molecule/https_revproxy/converge.yml | 5 ++--- molecule/overridexml/molecule.yml | 1 + molecule/quarkus-devmode/converge.yml | 5 ++++- molecule/quarkus-devmode/molecule.yml | 2 ++ molecule/quarkus/converge.yml | 7 +++++-- molecule/quarkus/molecule.yml | 1 + molecule/quarkus/prepare.yml | 2 +- molecule/quarkus/verify.yml | 13 +++++++------ molecule/quarkus_ha/converge.yml | 3 +-- molecule/quarkus_ha/molecule.yml | 2 ++ molecule/quarkus_upgrade/converge.yml | 2 +- molecule/quarkus_upgrade/molecule.yml | 2 ++ molecule/quarkus_upgrade/prepare.yml | 2 +- molecule/quarkus_upgrade/vars.yml | 2 +- molecule/quarkus_upgrade/verify.yml | 2 +- roles/keycloak_quarkus/README.md | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 4 ++-- roles/keycloak_quarkus/vars/redhat.yml | 2 +- 24 files changed, 49 insertions(+), 27 deletions(-) diff --git a/molecule/debian/converge.yml b/molecule/debian/converge.yml index 7fab040..e853b38 100644 --- a/molecule/debian/converge.yml +++ b/molecule/debian/converge.yml @@ -5,14 +5,17 @@ keycloak_quarkus_show_deprecation_warnings: false keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" - keycloak_quarkus_hostname: http://instance + keycloak_quarkus_hostname: http://instance:8080 keycloak_quarkus_log: file keycloak_quarkus_start_dev: true keycloak_quarkus_proxy_mode: none roles: - role: keycloak_quarkus - role: keycloak_realm + keycloak_url: "{{ keycloak_quarkus_hostname }}" keycloak_context: '' + keycloak_admin_user: "{{ keycloak_quarkus_bootstrap_admin_user }}" + keycloak_admin_password: "{{ keycloak_quarkus_bootstrap_admin_password }}" keycloak_client_users: - username: TestUser password: password diff --git a/molecule/debian/prepare.yml b/molecule/debian/prepare.yml index 6025ef9..267386e 100644 --- a/molecule/debian/prepare.yml +++ b/molecule/debian/prepare.yml @@ -7,5 +7,6 @@ ansible.builtin.apt: name: - sudo + # - openjdk-21-jdk-headless # this is not available in ghcr.io/hspaans/molecule-containers:debian-11 (neither in debian-12) since the images are using outdated package sources - openjdk-17-jdk-headless state: present diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index 13a771b..de97748 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -5,7 +5,7 @@ keycloak_quarkus_show_deprecation_warnings: false keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" - keycloak_quarkus_hostname: http://instance + keycloak_quarkus_hostname: http://instance:8080 keycloak_quarkus_log: file keycloak_quarkus_log_level: debug keycloak_quarkus_log_target: /tmp/keycloak @@ -16,7 +16,10 @@ roles: - role: keycloak_quarkus - role: keycloak_realm + keycloak_url: "{{ keycloak_quarkus_hostname }}" keycloak_context: '' + keycloak_admin_user: "{{ keycloak_quarkus_bootstrap_admin_user }}" + keycloak_admin_password: "{{ keycloak_quarkus_bootstrap_admin_password }}" keycloak_client_users: - username: TestUser password: password diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index c133eee..62fa2b7 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -11,6 +11,7 @@ platforms: - "8080/tcp" - "8443/tcp" - "8009/tcp" + - "9000/tcp" provisioner: name: ansible config_options: diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml index 899dabd..eefd5cf 100644 --- a/molecule/default/prepare.yml +++ b/molecule/default/prepare.yml @@ -22,7 +22,7 @@ - name: Download keycloak archive to controller directory ansible.builtin.get_url: # noqa risky-file-permissions delegated, uses controller host user - url: https://github.com/keycloak/keycloak/releases/download/24.0.5/keycloak-24.0.5.zip + url: https://github.com/keycloak/keycloak/releases/download/26.0.7/keycloak-26.0.7.zip dest: /tmp/keycloak mode: '0640' delegate_to: localhost diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index eac4339..ae21396 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -2,6 +2,7 @@ - name: Verify hosts: all vars: + keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_uri: "http://localhost:8080" tasks: @@ -16,7 +17,7 @@ ansible.builtin.uri: url: "{{ keycloak_uri }}/realms/master/protocol/openid-connect/token" method: POST - body: "client_id=admin-cli&username=admin&password={{ keycloak_quarkus_bootstrap_admin_user }}&grant_type=password" + body: "client_id=admin-cli&username={{ keycloak_quarkus_bootstrap_admin_user }}&password={{ keycloak_quarkus_bootstrap_admin_user }}&grant_type=password" validate_certs: no register: keycloak_auth_response until: keycloak_auth_response.status == 200 diff --git a/molecule/https_revproxy/converge.yml b/molecule/https_revproxy/converge.yml index 7245265..92994fa 100644 --- a/molecule/https_revproxy/converge.yml +++ b/molecule/https_revproxy/converge.yml @@ -5,13 +5,12 @@ keycloak_quarkus_show_deprecation_warnings: false keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" - keycloak_realm: TestRealm - keycloak_quarkus_hostname: http://instance + keycloak_quarkus_hostname: https://proxy keycloak_quarkus_log: file keycloak_quarkus_http_enabled: True keycloak_quarkus_http_port: 8080 keycloak_quarkus_proxy_mode: edge keycloak_quarkus_http_relative_path: / - keycloak_quarkus_frontend_url: https://proxy/ + keycloak_quarkus_health_check_url: http://proxy:8080/realms/master/.well-known/openid-configuration roles: - role: keycloak_quarkus diff --git a/molecule/overridexml/molecule.yml b/molecule/overridexml/molecule.yml index c133eee..62fa2b7 100644 --- a/molecule/overridexml/molecule.yml +++ b/molecule/overridexml/molecule.yml @@ -11,6 +11,7 @@ platforms: - "8080/tcp" - "8443/tcp" - "8009/tcp" + - "9000/tcp" provisioner: name: ansible config_options: diff --git a/molecule/quarkus-devmode/converge.yml b/molecule/quarkus-devmode/converge.yml index 5cd4ea1..6c0b14f 100644 --- a/molecule/quarkus-devmode/converge.yml +++ b/molecule/quarkus-devmode/converge.yml @@ -7,14 +7,17 @@ keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_realm: TestRealm keycloak_quarkus_log: file - keycloak_quarkus_frontend_url: 'http://localhost:8080/' + keycloak_quarkus_hostname: 'http://localhost:8080' keycloak_quarkus_start_dev: True keycloak_quarkus_proxy_mode: none keycloak_quarkus_java_home: /opt/openjdk/ roles: - role: keycloak_quarkus - role: keycloak_realm + keycloak_url: "{{ keycloak_quarkus_hostname }}" keycloak_context: '' + keycloak_admin_user: "{{ keycloak_quarkus_bootstrap_admin_user }}" + keycloak_admin_password: "{{ keycloak_quarkus_bootstrap_admin_password }}" keycloak_client_default_roles: - TestRoleAdmin - TestRoleUser diff --git a/molecule/quarkus-devmode/molecule.yml b/molecule/quarkus-devmode/molecule.yml index 191234d..5d22ab8 100644 --- a/molecule/quarkus-devmode/molecule.yml +++ b/molecule/quarkus-devmode/molecule.yml @@ -10,8 +10,10 @@ platforms: port_bindings: - "8080/tcp" - "8009/tcp" + - "9000/tcp" published_ports: - 0.0.0.0:8080:8080/tcp + - 0.0.0.0:9000:9000/TCP provisioner: name: ansible config_options: diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index 9b7b3a7..9bfbc0f 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -6,7 +6,7 @@ keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" keycloak_realm: TestRealm - keycloak_quarkus_hostname: http://instance + keycloak_quarkus_hostname: https://instance:8443 keycloak_quarkus_log: file keycloak_quarkus_log_level: debug # needed for the verify step keycloak_quarkus_https_key_file_enabled: true @@ -37,7 +37,7 @@ repository_url: https://repo1.maven.org/maven2/ # https://mvnrepository.com/artifact/org.keycloak/keycloak-kerberos-federation/24.0.4 group_id: org.keycloak artifact_id: keycloak-kerberos-federation - version: 24.0.5 # optional + version: 26.0.7 # optional # username: myUser # optional # password: myPAT # optional # - id: my-static-theme @@ -51,7 +51,10 @@ roles: - role: keycloak_quarkus - role: keycloak_realm + keycloak_url: "{{ keycloak_quarkus_hostname }}" keycloak_context: '' + keycloak_admin_user: "{{ keycloak_quarkus_bootstrap_admin_user }}" + keycloak_admin_password: "{{ keycloak_quarkus_bootstrap_admin_password }}" keycloak_client_default_roles: - TestRoleAdmin - TestRoleUser diff --git a/molecule/quarkus/molecule.yml b/molecule/quarkus/molecule.yml index c04e300..c083e77 100644 --- a/molecule/quarkus/molecule.yml +++ b/molecule/quarkus/molecule.yml @@ -11,6 +11,7 @@ platforms: - "8080/tcp" - "8443/tcp" - "8009/tcp" + - "9000/tcp" published_ports: - 0.0.0.0:8443:8443/tcp provisioner: diff --git a/molecule/quarkus/prepare.yml b/molecule/quarkus/prepare.yml index 21a0f30..d8ef369 100644 --- a/molecule/quarkus/prepare.yml +++ b/molecule/quarkus/prepare.yml @@ -24,7 +24,7 @@ - name: Make sure a jre is available (for keytool to prepare keystore) delegate_to: localhost ansible.builtin.package: - name: "{{ 'java-17-openjdk-headless' if hera_home | length > 0 else 'openjdk-17-jdk-headless' }}" + name: "{{ 'java-21-openjdk-headless' if hera_home | length > 0 else 'openjdk-21-jdk-headless' }}" state: present become: true failed_when: false diff --git a/molecule/quarkus/verify.yml b/molecule/quarkus/verify.yml index 1ee3b61..f041d88 100644 --- a/molecule/quarkus/verify.yml +++ b/molecule/quarkus/verify.yml @@ -2,7 +2,8 @@ - name: Verify hosts: all vars: - keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" tasks: - name: Populate service facts ansible.builtin.service_facts: @@ -35,10 +36,10 @@ - name: Verify endpoint URLs ansible.builtin.assert: that: - - (openid_config.stdout | from_json)["backchannel_authentication_endpoint"] == 'https://instance/realms/master/protocol/openid-connect/ext/ciba/auth' - - (openid_config.stdout | from_json)['issuer'] == 'https://instance/realms/master' - - (openid_config.stdout | from_json)['authorization_endpoint'] == 'https://instance/realms/master/protocol/openid-connect/auth' - - (openid_config.stdout | from_json)['token_endpoint'] == 'https://instance/realms/master/protocol/openid-connect/token' + - (openid_config.stdout | from_json)["backchannel_authentication_endpoint"] == 'https://instance:8443/realms/master/protocol/openid-connect/ext/ciba/auth' + - (openid_config.stdout | from_json)['issuer'] == 'https://instance:8443/realms/master' + - (openid_config.stdout | from_json)['authorization_endpoint'] == 'https://instance:8443/realms/master/protocol/openid-connect/auth' + - (openid_config.stdout | from_json)['token_endpoint'] == 'https://instance:8443/realms/master/protocol/openid-connect/token' delegate_to: localhost - name: Check log folder @@ -91,7 +92,7 @@ ansible.builtin.uri: url: "https://instance:8443/realms/master/protocol/openid-connect/token" method: POST - body: "client_id=admin-cli&username=admin&password={{ keycloak_quarkus_bootstrap_admin_user }}&grant_type=password" + body: "client_id=admin-cli&username={{ keycloak_quarkus_bootstrap_admin_user }}&password={{ keycloak_quarkus_bootstrap_admin_password}}&grant_type=password" validate_certs: no register: keycloak_auth_response until: keycloak_auth_response.status == 200 diff --git a/molecule/quarkus_ha/converge.yml b/molecule/quarkus_ha/converge.yml index 238fbb5..d37ad79 100644 --- a/molecule/quarkus_ha/converge.yml +++ b/molecule/quarkus_ha/converge.yml @@ -5,8 +5,7 @@ keycloak_quarkus_show_deprecation_warnings: false keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_bootstrap_admin_user: "remembertochangeme" - keycloak_realm: TestRealm - keycloak_quarkus_hostname: "http://{{ inventory_hostname }}" + keycloak_quarkus_hostname: "http://{{ inventory_hostname }}:8080" keycloak_quarkus_log: file keycloak_quarkus_log_level: info keycloak_quarkus_https_key_file_enabled: true diff --git a/molecule/quarkus_ha/molecule.yml b/molecule/quarkus_ha/molecule.yml index 8e07e0f..43a8286 100644 --- a/molecule/quarkus_ha/molecule.yml +++ b/molecule/quarkus_ha/molecule.yml @@ -14,6 +14,7 @@ platforms: port_bindings: - "8080/tcp" - "8443/tcp" + - "9000/tcp" - name: instance2 image: registry.access.redhat.com/ubi9/ubi-init:latest pre_build_image: true @@ -26,6 +27,7 @@ platforms: port_bindings: - "8080/tcp" - "8443/tcp" + - "9000/tcp" - name: postgres image: ubuntu/postgres:14-22.04_beta pre_build_image: true diff --git a/molecule/quarkus_upgrade/converge.yml b/molecule/quarkus_upgrade/converge.yml index 6025b7c..9b57436 100644 --- a/molecule/quarkus_upgrade/converge.yml +++ b/molecule/quarkus_upgrade/converge.yml @@ -5,6 +5,6 @@ - vars.yml vars: keycloak_quarkus_show_deprecation_warnings: false - keycloak_quarkus_version: 24.0.3 + keycloak_quarkus_version: 26.0.7 roles: - role: keycloak_quarkus diff --git a/molecule/quarkus_upgrade/molecule.yml b/molecule/quarkus_upgrade/molecule.yml index 77f687f..21782e8 100644 --- a/molecule/quarkus_upgrade/molecule.yml +++ b/molecule/quarkus_upgrade/molecule.yml @@ -13,8 +13,10 @@ platforms: privileged: true port_bindings: - 8080:8080 + - "9000/tcp" published_ports: - 0.0.0.0:8080:8080/TCP + - 0.0.0.0:9000:9000/TCP provisioner: name: ansible playbooks: diff --git a/molecule/quarkus_upgrade/prepare.yml b/molecule/quarkus_upgrade/prepare.yml index bebfc68..a6892e3 100644 --- a/molecule/quarkus_upgrade/prepare.yml +++ b/molecule/quarkus_upgrade/prepare.yml @@ -5,7 +5,7 @@ - vars.yml vars: sudo_pkg_name: sudo - keycloak_quarkus_version: 23.0.7 + keycloak_quarkus_version: 24.0.5 pre_tasks: - name: Install sudo ansible.builtin.apt: diff --git a/molecule/quarkus_upgrade/vars.yml b/molecule/quarkus_upgrade/vars.yml index 52ab103..1567ae4 100644 --- a/molecule/quarkus_upgrade/vars.yml +++ b/molecule/quarkus_upgrade/vars.yml @@ -2,7 +2,7 @@ keycloak_quarkus_offline_install: false keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_realm: TestRealm -keycloak_quarkus_hostname: http://instance +keycloak_quarkus_hostname: http://instance:8080 keycloak_quarkus_log: file keycloak_quarkus_https_key_file_enabled: true keycloak_quarkus_log_target: /tmp/keycloak diff --git a/molecule/quarkus_upgrade/verify.yml b/molecule/quarkus_upgrade/verify.yml index 3214d9f..1c4a0ba 100644 --- a/molecule/quarkus_upgrade/verify.yml +++ b/molecule/quarkus_upgrade/verify.yml @@ -17,7 +17,7 @@ - name: Verify we are running on requested jvm ansible.builtin.shell: | set -eo pipefail - ps -ef | grep 'etc/alternatives/.*17' | grep -v grep + ps -ef | grep 'etc/alternatives/.*21' | grep -v grep changed_when: false - name: Verify token api call diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index d3abd57..bafc150 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -59,7 +59,7 @@ Role Defaults |`keycloak_quarkus_service_restart_always`| systemd restart always behavior activation | `False` | |`keycloak_quarkus_service_restart_on_failure`| systemd restart on-failure behavior activation | `False` | |`keycloak_quarkus_service_restartsec`| systemd RestartSec | `10s` | -|`keycloak_quarkus_jvm_package`| RHEL java package runtime | `java-17-openjdk-headless` | +|`keycloak_quarkus_jvm_package`| RHEL java package runtime | `java-21-openjdk-headless` | |`keycloak_quarkus_java_home`| JAVA_HOME of installed JRE, leave empty for using specified keycloak_quarkus_jvm_package RPM path | `None` | |`keycloak_quarkus_java_heap_opts`| Heap memory JVM setting | `-Xms1024m -Xmx2048m` | |`keycloak_quarkus_java_jvm_opts`| Other JVM settings | same as keycloak | diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 0e4eb42..3eaf5d4 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -22,7 +22,7 @@ argument_specs: description: "Perform an offline install" type: "bool" keycloak_quarkus_jvm_package: - default: "java-11-openjdk-headless" + default: "java-21-openjdk-headless" description: "RHEL java package runtime" type: "str" keycloak_quarkus_java_home: @@ -479,7 +479,7 @@ argument_specs: downstream: options: rhbk_version: - default: "26.0.6" + default: "26.0.7" description: "Red Hat Build of Keycloak version" type: "str" rhbk_archive: diff --git a/roles/keycloak_quarkus/vars/redhat.yml b/roles/keycloak_quarkus/vars/redhat.yml index c311321..9af167f 100644 --- a/roles/keycloak_quarkus/vars/redhat.yml +++ b/roles/keycloak_quarkus/vars/redhat.yml @@ -1,5 +1,5 @@ --- -keycloak_quarkus_varjvm_package: "{{ keycloak_quarkus_jvm_package | default('java-17-openjdk-headless') }}" +keycloak_quarkus_varjvm_package: "{{ keycloak_quarkus_jvm_package | default('java-21-openjdk-headless') }}" keycloak_quarkus_prereq_package_list: - "{{ keycloak_quarkus_varjvm_package }}" - unzip From fa367212079a9d55e13013fba22cb64ac28fd5a2 Mon Sep 17 00:00:00 2001 From: Helmut Wolf Date: Mon, 20 Jan 2025 09:44:27 +0100 Subject: [PATCH 192/205] Improve string interpolation --- roles/keycloak_quarkus/vars/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/keycloak_quarkus/vars/main.yml b/roles/keycloak_quarkus/vars/main.yml index 2efe5e6..997d7dc 100644 --- a/roles/keycloak_quarkus/vars/main.yml +++ b/roles/keycloak_quarkus/vars/main.yml @@ -4,7 +4,7 @@ keycloak: # noqa var-naming this is an internal dict of interpolated values config_dir: "{{ keycloak_quarkus_config_dir }}" bundle: "{{ keycloak_quarkus_archive }}" service_name: "keycloak" - health_url: "{{ keycloak_quarkus_health_check_url | default(keycloak_quarkus_hostname + '/' + (keycloak_quarkus_health_check_url_path | default('realms/master/.well-known/openid-configuration'))) }}" + health_url: "{{ keycloak_quarkus_health_check_url | default(keycloak_quarkus_hostname ~ '/' ~ (keycloak_quarkus_health_check_url_path | default('realms/master/.well-known/openid-configuration'))) }}" cli_path: "{{ keycloak_quarkus_home }}/bin/kcadm.sh" service_user: "{{ keycloak_quarkus_service_user }}" service_group: "{{ keycloak_quarkus_service_group }}" From 5db96afa56a589b445fc2481c08b1fad57e0fdb6 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 1 Apr 2025 15:20:37 +0200 Subject: [PATCH 193/205] Variables names must not be Ansible reserved names --- roles/keycloak/tasks/rhsso_cli.yml | 6 +++--- roles/keycloak/tasks/rhsso_patch.yml | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/roles/keycloak/tasks/rhsso_cli.yml b/roles/keycloak/tasks/rhsso_cli.yml index fd41dd6..e40dec8 100644 --- a/roles/keycloak/tasks/rhsso_cli.yml +++ b/roles/keycloak/tasks/rhsso_cli.yml @@ -2,12 +2,12 @@ - name: Ensure required params for CLI have been provided ansible.builtin.assert: that: - - query is defined + - cli_query is defined fail_msg: "Missing required parameters to execute CLI." quiet: true -- name: "Execute CLI query: {{ query }}" +- name: "Execute CLI query: {{ cli_query }}" ansible.builtin.command: > - {{ keycloak.cli_path }} --connect --command='{{ query }}' --controller={{ keycloak_host }}:{{ keycloak_management_http_port }} + {{ keycloak.cli_path }} --connect --command='{{ cli_query }}' --controller={{ keycloak_host }}:{{ keycloak_management_http_port }} changed_when: false register: cli_result diff --git a/roles/keycloak/tasks/rhsso_patch.yml b/roles/keycloak/tasks/rhsso_patch.yml index e7ac3f0..23d75bf 100644 --- a/roles/keycloak/tasks/rhsso_patch.yml +++ b/roles/keycloak/tasks/rhsso_patch.yml @@ -106,7 +106,7 @@ - name: "Check installed patches" ansible.builtin.include_tasks: rhsso_cli.yml vars: - query: "patch info" + cli_query: "patch info" args: apply: become: true @@ -121,7 +121,7 @@ - name: "Apply patch {{ patch_version }} to server" ansible.builtin.include_tasks: rhsso_cli.yml vars: - query: "patch apply {{ patch_archive }}" + cli_query: "patch apply {{ patch_archive }}" args: apply: become: true @@ -130,7 +130,7 @@ - name: "Restart server to ensure patch content is running" ansible.builtin.include_tasks: rhsso_cli.yml vars: - query: "shutdown --restart" + cli_query: "shutdown --restart" when: - cli_result.rc == 0 args: @@ -149,7 +149,7 @@ - name: "Query installed patch after restart" ansible.builtin.include_tasks: rhsso_cli.yml vars: - query: "patch info" + cli_query: "patch info" args: apply: become: true From 7f980c44d287971c1cc4d9c899518549d2c82fa6 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 8 Apr 2025 11:58:47 +0200 Subject: [PATCH 194/205] Bump major and ansible-core versions --- CONTRIBUTING.md | 2 +- README.md | 2 +- galaxy.yml | 2 +- meta/runtime.yml | 2 +- roles/keycloak/meta/main.yml | 2 +- roles/keycloak_quarkus/meta/main.yml | 2 +- roles/keycloak_realm/meta/main.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 21ddc18..95b60ed 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,7 @@ virtualenv $PATH_TO_DEV_VIRTUALENV # activate the virtual env source $PATH_TO_DEV_VIRTUALENV/bin/activate # install ansible and tools onto the virtualenv -pip install yamllint 'molecule>=6.0' 'molecule-plugins[docker]' 'ansible-core>=2.15' ansible-lint +pip install yamllint 'molecule>=6.0' 'molecule-plugins[docker]' 'ansible-core>=2.16' ansible-lint # install collection dependencies ansible-galaxy collection install -r requirements.yml # install python dependencies diff --git a/README.md b/README.md index e8c289e..9e9867d 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Collection to install and configure [Keycloak](https://www.keycloak.org/) or [Re ## Ansible version compatibility -This collection has been tested against following Ansible versions: **>=2.15.0**. +This collection has been tested against following Ansible versions: **>=2.16.0**. Plugins and modules within a collection may be tested with only specific Ansible versions. A collection may contain metadata that identifies these versions. diff --git a/galaxy.yml b/galaxy.yml index a6511a8..76c46c4 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: middleware_automation name: keycloak -version: "2.4.4" +version: "3.0.0" readme: README.md authors: - Romain Pelisse diff --git a/meta/runtime.yml b/meta/runtime.yml index 1e85b01..49c7554 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -1,2 +1,2 @@ --- -requires_ansible: ">=2.15.0" +requires_ansible: ">=2.16.0" diff --git a/roles/keycloak/meta/main.yml b/roles/keycloak/meta/main.yml index a27afb8..59499e6 100644 --- a/roles/keycloak/meta/main.yml +++ b/roles/keycloak/meta/main.yml @@ -12,7 +12,7 @@ galaxy_info: license: Apache License 2.0 - min_ansible_version: "2.15" + min_ansible_version: "2.16" platforms: - name: EL diff --git a/roles/keycloak_quarkus/meta/main.yml b/roles/keycloak_quarkus/meta/main.yml index 40a487f..65b5e50 100644 --- a/roles/keycloak_quarkus/meta/main.yml +++ b/roles/keycloak_quarkus/meta/main.yml @@ -8,7 +8,7 @@ galaxy_info: license: Apache License 2.0 - min_ansible_version: "2.15" + min_ansible_version: "2.16" platforms: - name: EL diff --git a/roles/keycloak_realm/meta/main.yml b/roles/keycloak_realm/meta/main.yml index ab861ed..97c69d2 100644 --- a/roles/keycloak_realm/meta/main.yml +++ b/roles/keycloak_realm/meta/main.yml @@ -8,7 +8,7 @@ galaxy_info: license: Apache License 2.0 - min_ansible_version: "2.15" + min_ansible_version: "2.16" platforms: - name: EL From 744766fe3bc52a50d9e0b4729179e11c149327f1 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Tue, 8 Apr 2025 15:36:38 +0200 Subject: [PATCH 195/205] update doc generation to 2.16 --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index c8f8e2d..303f3a6 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,7 +1,7 @@ antsibull>=0.17.0 antsibull-docs antsibull-changelog -ansible-core>=2.14.1 +ansible-core>=2.16.0 ansible-pygments sphinx-rtd-theme git+https://github.com/felixfontein/ansible-basic-sphinx-ext From ac0ceca35f46fbfce135648fea88deacc0b7d45b Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 9 Apr 2025 09:45:22 +0200 Subject: [PATCH 196/205] Update to ubi9 --- molecule/default/molecule.yml | 2 +- molecule/https_revproxy/molecule.yml | 4 ++-- molecule/overridexml/molecule.yml | 2 +- molecule/quarkus-devmode/molecule.yml | 2 +- molecule/quarkus/molecule.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index 62fa2b7..011c08e 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -3,7 +3,7 @@ driver: name: docker platforms: - name: instance - image: registry.access.redhat.com/ubi8/ubi-init:latest + image: registry.access.redhat.com/ubi9/ubi-init:latest pre_build_image: true privileged: true command: "/usr/sbin/init" diff --git a/molecule/https_revproxy/molecule.yml b/molecule/https_revproxy/molecule.yml index 48bf375..7ad8db8 100644 --- a/molecule/https_revproxy/molecule.yml +++ b/molecule/https_revproxy/molecule.yml @@ -3,7 +3,7 @@ driver: name: docker platforms: - name: instance - image: registry.access.redhat.com/ubi8/ubi-init:latest + image: registry.access.redhat.com/ubi9/ubi-init:latest pre_build_image: true privileged: true command: "/usr/sbin/init" @@ -14,7 +14,7 @@ platforms: published_ports: - 0.0.0.0:8080:8080/tcp - name: proxy - image: registry.access.redhat.com/ubi8/ubi-init:latest + image: registry.access.redhat.com/ubi9/ubi-init:latest pre_build_image: true privileged: true command: "/usr/sbin/init" diff --git a/molecule/overridexml/molecule.yml b/molecule/overridexml/molecule.yml index 62fa2b7..011c08e 100644 --- a/molecule/overridexml/molecule.yml +++ b/molecule/overridexml/molecule.yml @@ -3,7 +3,7 @@ driver: name: docker platforms: - name: instance - image: registry.access.redhat.com/ubi8/ubi-init:latest + image: registry.access.redhat.com/ubi9/ubi-init:latest pre_build_image: true privileged: true command: "/usr/sbin/init" diff --git a/molecule/quarkus-devmode/molecule.yml b/molecule/quarkus-devmode/molecule.yml index 5d22ab8..2da7e01 100644 --- a/molecule/quarkus-devmode/molecule.yml +++ b/molecule/quarkus-devmode/molecule.yml @@ -3,7 +3,7 @@ driver: name: docker platforms: - name: instance - image: registry.access.redhat.com/ubi8/ubi-init:latest + image: registry.access.redhat.com/ubi9/ubi-init:latest pre_build_image: true privileged: true command: "/usr/sbin/init" diff --git a/molecule/quarkus/molecule.yml b/molecule/quarkus/molecule.yml index c083e77..60995cc 100644 --- a/molecule/quarkus/molecule.yml +++ b/molecule/quarkus/molecule.yml @@ -3,7 +3,7 @@ driver: name: docker platforms: - name: instance - image: registry.access.redhat.com/ubi8/ubi-init:latest + image: registry.access.redhat.com/ubi9/ubi-init:latest pre_build_image: true privileged: true command: "/usr/sbin/init" From f628b84fb0287942c5cbd40a7776d61acfb21ea5 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 9 Apr 2025 17:21:49 +0200 Subject: [PATCH 197/205] disable restart health check because of selfsigned cert --- molecule/quarkus/converge.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index 9bfbc0f..db30473 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -22,6 +22,7 @@ keycloak_quarkus_systemd_wait_for_timeout: 20 keycloak_quarkus_systemd_wait_for_delay: 2 keycloak_quarkus_systemd_wait_for_log: true + keycloak_quarkus_restart_health_check: false # would fail because of self-signed cert keycloak_quarkus_providers: - id: http-client spi: connections From 314e2f26b27d264960d72c4e235ba6c0b69f4e58 Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 9 Apr 2025 17:22:22 +0200 Subject: [PATCH 198/205] Fix spell in parameter name --- molecule/quarkus/converge.yml | 2 +- molecule/quarkus/molecule.yml | 1 + molecule/quarkus/verify.yml | 8 ++++---- molecule/quarkus_ha/molecule.yml | 1 + roles/keycloak_quarkus/README.md | 2 +- roles/keycloak_quarkus/defaults/main.yml | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 2 +- roles/keycloak_quarkus/tasks/restart.yml | 2 +- roles/keycloak_quarkus/tasks/start.yml | 1 + 9 files changed, 12 insertions(+), 9 deletions(-) diff --git a/molecule/quarkus/converge.yml b/molecule/quarkus/converge.yml index db30473..b7c15e1 100644 --- a/molecule/quarkus/converge.yml +++ b/molecule/quarkus/converge.yml @@ -52,7 +52,7 @@ roles: - role: keycloak_quarkus - role: keycloak_realm - keycloak_url: "{{ keycloak_quarkus_hostname }}" + keycloak_url: http://instance:8080 keycloak_context: '' keycloak_admin_user: "{{ keycloak_quarkus_bootstrap_admin_user }}" keycloak_admin_password: "{{ keycloak_quarkus_bootstrap_admin_password }}" diff --git a/molecule/quarkus/molecule.yml b/molecule/quarkus/molecule.yml index 60995cc..cf975e5 100644 --- a/molecule/quarkus/molecule.yml +++ b/molecule/quarkus/molecule.yml @@ -31,6 +31,7 @@ provisioner: ansible_python_interpreter: "{{ ansible_playbook_python }}" env: ANSIBLE_FORCE_COLOR: "true" + PYTHONHTTPSVERIFY: 0 verifier: name: ansible scenario: diff --git a/molecule/quarkus/verify.yml b/molecule/quarkus/verify.yml index f041d88..1d9d2c3 100644 --- a/molecule/quarkus/verify.yml +++ b/molecule/quarkus/verify.yml @@ -102,8 +102,8 @@ - name: "Get Clients" ansible.builtin.uri: url: "https://instance:8443/admin/realms/TestRealm/clients" + validate_certs: false headers: - validate_certs: false Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" register: keycloak_clients @@ -114,15 +114,15 @@ - name: "Get Client {{ keycloak_client_uuid }}" ansible.builtin.uri: url: "https://instance:8443/admin/realms/TestRealm/clients/{{ keycloak_client_uuid }}" + validate_certs: false headers: - validate_certs: false Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" register: keycloak_test_client - name: "Get Client roles" ansible.builtin.uri: url: "https://instance:8443/admin/realms/TestRealm/clients/{{ keycloak_client_uuid }}/roles" + validate_certs: false headers: - validate_certs: false Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" - register: keycloak_test_client_roles \ No newline at end of file + register: keycloak_test_client_roles diff --git a/molecule/quarkus_ha/molecule.yml b/molecule/quarkus_ha/molecule.yml index 43a8286..ed09971 100644 --- a/molecule/quarkus_ha/molecule.yml +++ b/molecule/quarkus_ha/molecule.yml @@ -65,6 +65,7 @@ provisioner: ansible_python_interpreter: "{{ ansible_playbook_python }}" env: ANSIBLE_FORCE_COLOR: "true" + PYTHONHTTPSVERIFY: 0 verifier: name: ansible scenario: diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index bafc150..fb30ce9 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -112,7 +112,7 @@ Role Defaults |`keycloak_quarkus_restart_strategy`| Strategy task file for restarting in HA (one of provided restart/['serial.yml','none.yml','serial_then_parallel.yml']) or path to file when providing custom strategy | `restart/serial.yml` | |`keycloak_quarkus_restart_health_check`| Whether to wait for successful health check after restart | `true` | |`keycloak_quarkus_restart_health_check_delay`| Seconds to let pass before starting healch checks | `10` | -|`keycloak_quarkus_restart_health_check_reries`| Number of attempts for successful health check before failing | `25` | +|`keycloak_quarkus_restart_health_check_retries`| Number of attempts for successful health check before failing | `25` | |`keycloak_quarkus_restart_pause`| Seconds to wait between restarts in HA strategy | `15` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 05e0455..0512960 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -163,5 +163,5 @@ keycloak_quarkus_supported_policy_types: ['password-blacklists'] keycloak_quarkus_restart_strategy: restart/serial.yml keycloak_quarkus_restart_health_check: true keycloak_quarkus_restart_health_check_delay: 10 -keycloak_quarkus_restart_health_check_reries: 25 +keycloak_quarkus_restart_health_check_retries: 25 keycloak_quarkus_restart_pause: 15 diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 3eaf5d4..4a3b7c4 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -464,7 +464,7 @@ argument_specs: description: "Seconds to let pass before starting healch checks" default: 10 type: 'int' - keycloak_quarkus_restart_health_check_reries: + keycloak_quarkus_restart_health_check_retries: description: "Number of attempts for successful health check before failing" default: 25 type: 'int' diff --git a/roles/keycloak_quarkus/tasks/restart.yml b/roles/keycloak_quarkus/tasks/restart.yml index 61356d5..3aa97f6 100644 --- a/roles/keycloak_quarkus/tasks/restart.yml +++ b/roles/keycloak_quarkus/tasks/restart.yml @@ -12,7 +12,7 @@ url: "{{ keycloak.health_url }}" register: keycloak_status until: keycloak_status.status == 200 - retries: "{{ keycloak_quarkus_restart_health_check_reries }}" + retries: "{{ keycloak_quarkus_restart_health_check_retries }}" delay: "{{ keycloak_quarkus_restart_health_check_delay }}" when: internal_force_health_check | default(keycloak_quarkus_restart_health_check) diff --git a/roles/keycloak_quarkus/tasks/start.yml b/roles/keycloak_quarkus/tasks/start.yml index a640e89..5a3ad5f 100644 --- a/roles/keycloak_quarkus/tasks/start.yml +++ b/roles/keycloak_quarkus/tasks/start.yml @@ -14,3 +14,4 @@ until: keycloak_status.status == 200 retries: 25 delay: 10 + when: internal_force_health_check | default(keycloak_quarkus_restart_health_check) From f146eb5fda5f9444c1eb071701eed5a9f14d1ddc Mon Sep 17 00:00:00 2001 From: Ranabir Chakraborty Date: Fri, 11 Apr 2025 20:52:08 +0530 Subject: [PATCH 199/205] AMW-384 Keycloak realm variable keycloak_url with hard-coded http --- roles/keycloak/defaults/main.yml | 4 ++++ roles/keycloak/vars/main.yml | 3 --- roles/keycloak_realm/defaults/main.yml | 4 ++++ roles/keycloak_realm/vars/main.yml | 4 ---- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/roles/keycloak/defaults/main.yml b/roles/keycloak/defaults/main.yml index cfa9a3f..137111f 100644 --- a/roles/keycloak/defaults/main.yml +++ b/roles/keycloak/defaults/main.yml @@ -118,3 +118,7 @@ keycloak_no_log: true ### logging configuration keycloak_log_target: /var/log/keycloak + +# locations +keycloak_url: "http://{{ keycloak_host }}:{{ keycloak_http_port + keycloak_jboss_port_offset }}" +keycloak_management_url: "http://{{ keycloak_host }}:{{ keycloak_management_http_port + keycloak_jboss_port_offset }}" diff --git a/roles/keycloak/vars/main.yml b/roles/keycloak/vars/main.yml index 7f7dfd1..fe706db 100644 --- a/roles/keycloak/vars/main.yml +++ b/roles/keycloak/vars/main.yml @@ -1,9 +1,6 @@ --- # internal variables below -# locations -keycloak_url: "http://{{ keycloak_host }}:{{ keycloak_http_port + keycloak_jboss_port_offset }}" -keycloak_management_url: "http://{{ keycloak_host }}:{{ keycloak_management_http_port + keycloak_jboss_port_offset }}" keycloak: diff --git a/roles/keycloak_realm/defaults/main.yml b/roles/keycloak_realm/defaults/main.yml index b9e1e45..a294cbe 100644 --- a/roles/keycloak_realm/defaults/main.yml +++ b/roles/keycloak_realm/defaults/main.yml @@ -54,3 +54,7 @@ keycloak_client_users: [] ### List of Keycloak User Federation keycloak_user_federation: [] + +# other settings +keycloak_url: "http://{{ keycloak_host }}:{{ keycloak_http_port + (keycloak_jboss_port_offset | default(0)) }}" +keycloak_management_url: "http://{{ keycloak_host }}:{{ keycloak_management_http_port + (keycloak_jboss_port_offset | default(0)) }}" diff --git a/roles/keycloak_realm/vars/main.yml b/roles/keycloak_realm/vars/main.yml index 7664f8c..ad9bd8e 100644 --- a/roles/keycloak_realm/vars/main.yml +++ b/roles/keycloak_realm/vars/main.yml @@ -3,7 +3,3 @@ # name of the realm to create, this is a required variable keycloak_realm: - -# other settings -keycloak_url: "http://{{ keycloak_host }}:{{ keycloak_http_port + (keycloak_jboss_port_offset | default(0)) }}" -keycloak_management_url: "http://{{ keycloak_host }}:{{ keycloak_management_http_port + (keycloak_jboss_port_offset | default(0)) }}" From 671cf4eb537a49f1cf0f67e75517ba4808705e24 Mon Sep 17 00:00:00 2001 From: Preston Doster Date: Sun, 13 Apr 2025 10:17:22 -0500 Subject: [PATCH 200/205] Updating example playbooks to use `bootstrap` admin password It looks like the underlying `quarkus` provider has changed to use `keycloak_quarkus_bootstrap_admin_password`. --- playbooks/keycloak_quarkus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playbooks/keycloak_quarkus.yml b/playbooks/keycloak_quarkus.yml index 84d1774..b8aedf2 100644 --- a/playbooks/keycloak_quarkus.yml +++ b/playbooks/keycloak_quarkus.yml @@ -2,7 +2,7 @@ - name: Playbook for Keycloak X Hosts with HTTPS enabled hosts: all vars: - keycloak_quarkus_admin_pass: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_hostname: http://localhost keycloak_quarkus_port: 8443 keycloak_quarkus_log: file From 7738e0feb1e70b6a6a68a38871c396d9e64dc097 Mon Sep 17 00:00:00 2001 From: Preston Doster Date: Sun, 13 Apr 2025 10:18:27 -0500 Subject: [PATCH 201/205] Update keycloak_quarkus_dev.yml --- playbooks/keycloak_quarkus_dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playbooks/keycloak_quarkus_dev.yml b/playbooks/keycloak_quarkus_dev.yml index 0c74c36..c8bb54e 100644 --- a/playbooks/keycloak_quarkus_dev.yml +++ b/playbooks/keycloak_quarkus_dev.yml @@ -2,7 +2,7 @@ - name: Playbook for Keycloak X Hosts in develop mode hosts: all vars: - keycloak_admin_password: "remembertochangeme" + keycloak_quarkus_bootstrap_admin_password: "remembertochangeme" keycloak_quarkus_hostname: http://localhost keycloak_quarkus_port: 8080 keycloak_quarkus_log: file From e9061b29efced4c721fee7926494f779808bcb5f Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 16 Apr 2025 10:31:48 +0200 Subject: [PATCH 202/205] Rename parameters from jdbc to db --- molecule/quarkus_ha/converge.yml | 2 +- roles/keycloak_quarkus/README.md | 8 ++++---- roles/keycloak_quarkus/defaults/main.yml | 6 +++--- roles/keycloak_quarkus/meta/argument_specs.yml | 10 +++++----- roles/keycloak_quarkus/tasks/install.yml | 4 ++-- roles/keycloak_quarkus/tasks/jdbc_driver.yml | 4 ++-- roles/keycloak_quarkus/templates/keycloak.conf.j2 | 4 ++-- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/molecule/quarkus_ha/converge.yml b/molecule/quarkus_ha/converge.yml index d37ad79..fa5314f 100644 --- a/molecule/quarkus_ha/converge.yml +++ b/molecule/quarkus_ha/converge.yml @@ -24,6 +24,6 @@ keycloak_quarkus_restart_strategy: restart/serial.yml keycloak_quarkus_db_user: keycloak keycloak_quarkus_db_pass: mysecretpass - keycloak_quarkus_jdbc_url: jdbc:postgresql://postgres:5432/keycloak + keycloak_quarkus_db_url: jdbc:postgresql://postgres:5432/keycloak roles: - role: keycloak_quarkus diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index fb30ce9..03a5a7a 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -130,14 +130,14 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| -|`keycloak_quarkus_jdbc_engine` | Database engine [mariadb,postres,mssql] | `postgres` | +|`keycloak_quarkus_db_engine` | Database engine [mariadb,postres,mssql] | `postgres` | |`keycloak_quarkus_db_user` | User for database connection | `keycloak-user` | |`keycloak_quarkus_db_pass` | Password for database connection | `keycloak-pass` | -|`keycloak_quarkus_jdbc_url` | JDBC URL for connecting to database | `jdbc:postgresql://localhost:5432/keycloak` | -|`keycloak_quarkus_jdbc_driver_version` | Version for JDBC driver | `9.4.1212` | +|`keycloak_quarkus_db_url` | JDBC URL for connecting to database | `jdbc:postgresql://localhost:5432/keycloak` | +|`keycloak_quarkus_db_driver_version` | Version for JDBC engine driver | `9.4.1212` | -#### Remote caches configuration +#### Cache configuration | Variable | Description | Default | |:---------|:------------|:--------| diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 0512960..14f9fc9 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -120,12 +120,12 @@ keycloak_quarkus_ispn_trust_store_path: /etc/pki/java/cacerts keycloak_quarkus_ispn_trust_store_password: changeit ### database backend engine: values [ 'postgres', 'mariadb' ] -keycloak_quarkus_jdbc_engine: postgres +keycloak_quarkus_db_engine: postgres ### database backend credentials keycloak_quarkus_db_user: keycloak-user keycloak_quarkus_db_pass: keycloak-pass -keycloak_quarkus_jdbc_url: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].url }}" -keycloak_quarkus_jdbc_driver_version: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].version }}" +keycloak_quarkus_db_url: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_db_engine].url }}" +keycloak_quarkus_db_driver_version: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_db_engine].version }}" # override the variables above, following defaults show minimum supported versions keycloak_quarkus_default_jdbc: postgres: diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 4a3b7c4..c793e5f 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -287,7 +287,7 @@ argument_specs: default: "changeit" description: "Password for infinispan certificate keystore" type: "str" - keycloak_quarkus_jdbc_engine: + keycloak_quarkus_db_engine: default: "postgres" description: "Database engine [mariadb,postres,mssql]" type: "str" @@ -299,12 +299,12 @@ argument_specs: default: "keycloak-pass" description: "Password for database connection" type: "str" - keycloak_quarkus_jdbc_url: - default: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].url }}" + keycloak_quarkus_db_url: + default: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_db_engine].url }}" description: "JDBC URL for connecting to database" type: "str" - keycloak_quarkus_jdbc_driver_version: - default: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].version }}" + keycloak_quarkus_db_driver_version: + default: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_db_engine].version }}" description: "Version for JDBC driver" type: "str" keycloak_quarkus_log: diff --git a/roles/keycloak_quarkus/tasks/install.yml b/roles/keycloak_quarkus/tasks/install.yml index c602d8c..c664d05 100644 --- a/roles/keycloak_quarkus/tasks/install.yml +++ b/roles/keycloak_quarkus/tasks/install.yml @@ -202,11 +202,11 @@ - keycloak_quarkus_cert_file_copy_enabled is defined and keycloak_quarkus_cert_file_copy_enabled - keycloak_quarkus_cert_file_src | length > 0 -- name: "Install {{ keycloak_quarkus_jdbc_engine }} JDBC driver" +- name: "Install {{ keycloak_quarkus_db_engine }} JDBC driver" ansible.builtin.include_tasks: jdbc_driver.yml when: - rhbk_enable is defined and rhbk_enable - - keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url is defined + - keycloak_quarkus_default_jdbc[keycloak_quarkus_db_engine].driver_jar_url is defined - name: "Download custom providers via http" ansible.builtin.get_url: diff --git a/roles/keycloak_quarkus/tasks/jdbc_driver.yml b/roles/keycloak_quarkus/tasks/jdbc_driver.yml index 880a915..ba3f4b8 100644 --- a/roles/keycloak_quarkus/tasks/jdbc_driver.yml +++ b/roles/keycloak_quarkus/tasks/jdbc_driver.yml @@ -7,9 +7,9 @@ (keycloak_quarkus_jdbc_download_user is undefined and keycloak_quarkus_jdbc_download_pass is not undefined) or (keycloak_quarkus_jdbc_download_pass is undefined and keycloak_quarkus_jdbc_download_user is not undefined) -- name: "Retrieve JDBC Driver from {{ keycloak_jdbc_download_url | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" +- name: "Retrieve JDBC Driver from {{ keycloak_jdbc_download_url | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_db_engine].driver_jar_url) }}" ansible.builtin.get_url: - url: "{{ keycloak_quarkus_jdbc_download_url | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].driver_jar_url) }}" + url: "{{ keycloak_quarkus_jdbc_download_url | default(keycloak_quarkus_default_jdbc[keycloak_quarkus_db_engine].driver_jar_url) }}" dest: "{{ keycloak.home }}/providers" owner: "{{ keycloak.service_user }}" group: "{{ keycloak.service_group }}" diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index f11e3ec..6a4a6c1 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -2,8 +2,8 @@ {% if keycloak_quarkus_db_enabled %} # Database -db={{ keycloak_quarkus_jdbc_engine }} -db-url={{ keycloak_quarkus_jdbc_url }} +db={{ keycloak_quarkus_db_engine }} +db-url={{ keycloak_quarkus_db_url }} db-username={{ keycloak_quarkus_db_user }} {% if not keycloak.config_key_store_enabled %} db-password={{ keycloak_quarkus_db_pass }} From c7ce7be6c4fc0cc99d3acf5600cdfc8c28d1637f Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 16 Apr 2025 10:42:07 +0200 Subject: [PATCH 203/205] drop ajp port parameter --- roles/keycloak_quarkus/README.md | 1 - roles/keycloak_quarkus/defaults/main.yml | 1 - roles/keycloak_quarkus/meta/argument_specs.yml | 4 ---- 3 files changed, 6 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 03a5a7a..dc7ced7 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -53,7 +53,6 @@ Role Defaults |`keycloak_quarkus_http_port`| HTTP listening port | `8080` | |`keycloak_quarkus_https_port`| TLS HTTP listening port | `8443` | |`keycloak_quarkus_http_management_port`| Port of the management interface. Relevant only when something is exposed on the management interface - see the guide for details. | `9000` | -|`keycloak_quarkus_ajp_port`| AJP port | `8009` | |`keycloak_quarkus_service_user`| Posix account username | `keycloak` | |`keycloak_quarkus_service_group`| Posix account group | `keycloak` | |`keycloak_quarkus_service_restart_always`| systemd restart always behavior activation | `False` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 14f9fc9..996d950 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -37,7 +37,6 @@ keycloak_quarkus_http_enabled: true keycloak_quarkus_http_port: 8080 keycloak_quarkus_https_port: 8443 keycloak_quarkus_http_management_port: 9000 -keycloak_quarkus_ajp_port: 8009 keycloak_quarkus_jgroups_port: 7800 keycloak_quarkus_java_heap_opts: "-Xms1024m -Xmx2048m" keycloak_quarkus_java_jvm_opts: "-XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index c793e5f..d42bec3 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -191,10 +191,6 @@ argument_specs: default: 9000 description: "Port of the management interface. Relevant only when something is exposed on the management interface - see the guide for details." type: "int" - keycloak_quarkus_ajp_port: - default: 8009 - description: "AJP port" - type: "int" keycloak_quarkus_jgroups_port: default: 7800 description: "jgroups cluster tcp port" From 69a947c0b6961b35d541c141786c80d0d2ecfc9f Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 16 Apr 2025 11:34:12 +0200 Subject: [PATCH 204/205] rename _admin to _hostname_admin --- roles/keycloak_quarkus/README.md | 16 ++++++++++------ roles/keycloak_quarkus/defaults/main.yml | 2 +- roles/keycloak_quarkus/meta/argument_specs.yml | 4 ++-- roles/keycloak_quarkus/tasks/deprecations.yml | 6 +++--- .../keycloak_quarkus/templates/keycloak.conf.j2 | 2 +- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index dc7ced7..6427209 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -64,10 +64,8 @@ Role Defaults |`keycloak_quarkus_java_jvm_opts`| Other JVM settings | same as keycloak | |`keycloak_quarkus_java_opts`| JVM arguments; if overridden, it takes precedence over `keycloak_quarkus_java_*` | `{{ keycloak_quarkus_java_heap_opts + ' ' + keycloak_quarkus_java_jvm_opts }}` | |`keycloak_quarkus_additional_env_vars` | List of additional env variables of { key: str, value: str} to be put in sysconfig file | `[]` | -|`keycloak_quarkus_hostname`| Address at which is the server exposed. Can be a full URL, or just a hostname. When only hostname is provided, scheme, port and context path are resolved from the request. | | |`keycloak_quarkus_frontend_url`| Deprecated, use `keycloak_quarkus_hostname` instead. | | -|`keycloak_quarkus_admin`| Set the base URL for accessing the administration console, including scheme, host, port and path | | -|`keycloak_quarkus_admin_url`| Deprecated, use `keycloak_quarkus_admin` instead. | | +|`keycloak_quarkus_admin_url`| Deprecated, use `keycloak_quarkus_hostname_admin` instead. | | |`keycloak_quarkus_http_relative_path` | Set the path relative to / for serving resources. The path must start with a / | `/` | |`keycloak_quarkus_http_management_relative_path` | Set the path relative to / for serving resources from management interface. The path must start with a /. If not given, the value is inherited from HTTP options. Relevant only when something is exposed on the management interface - see the guide for details. | `/` | |`keycloak_quarkus_http_enabled`| Enable listener on HTTP port | `True` | @@ -119,12 +117,20 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| -|`keycloak_quarkus_http_relative_path`| Set the path relative to / for serving resources. The path must start with a / | `/` | +|`keycloak_quarkus_hostname`| Address at which is the server exposed. Can be a full URL, or just a hostname. When only hostname is provided, scheme, port and context path are resolved from the request. | | +|`keycloak_quarkus_hostname_admin`| Set the base URL for accessing the administration console, including scheme, host, port and path | | |`keycloak_quarkus_hostname_strict`| Disables dynamically resolving the hostname from request headers | `true` | |`keycloak_quarkus_hostname_backchannel_dynamic`| Enables dynamic resolving of backchannel URLs, including hostname, scheme, port and context path. Set to true if your application accesses Keycloak via a private network. If set to true, hostname option needs to be specified as a full URL. | `false` | |`keycloak_quarkus_hostname_strict_backchannel`| Deprecated, use (the inverted!)`keycloak_quarkus_hostname_backchannel_dynamic` instead. | | +#### HTTP(S) configuration +| Variable | Description | Default | +|:---------|:------------|:--------| +|`keycloak_quarkus_http_relative_path`| Set the path relative to / for serving resources. The path must start with a / | `/` | + + + #### Database configuration | Variable | Description | Default | @@ -250,8 +256,6 @@ Role Variables |:---------|:------------|----------| |`keycloak_quarkus_bootstrap_admin_password`| Password of console admin account | `yes` | |`keycloak_quarkus_admin_pass`| Deprecated, use `keycloak_quarkus_bootstrap_admin_password` instead. | | -|`keycloak_quarkus_frontend_url`| Base URL for frontend URLs, including scheme, host, port and path | `no` | -|`keycloak_quarkus_admin_url`| Base URL for accessing the administration console, including scheme, host, port and path | `no` | |`keycloak_quarkus_ks_vault_pass`| The password for accessing the keystore vault SPI | `no` | |`keycloak_quarkus_alternate_download_url`| Alternate location with optional authentication for downloading RHBK | `no` | |`keycloak_quarkus_download_user`| Optional username for http authentication | `no*` | diff --git a/roles/keycloak_quarkus/defaults/main.yml b/roles/keycloak_quarkus/defaults/main.yml index 996d950..ed3dfab 100644 --- a/roles/keycloak_quarkus/defaults/main.yml +++ b/roles/keycloak_quarkus/defaults/main.yml @@ -79,7 +79,7 @@ keycloak_quarkus_systemd_wait_for_delay: 10 ### keycloak frontend url keycloak_quarkus_hostname: -keycloak_quarkus_admin: +keycloak_quarkus_hostname_admin: ### Set the path relative to / for serving resources. The path must start with a / ### (set to `/auth` for retrocompatibility with pre-quarkus releases) diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index d42bec3..901e774 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -239,13 +239,13 @@ argument_specs: required: false description: "Deprecated in v26, use keycloak_quarkus_hostname instead." type: "str" - keycloak_quarkus_admin: + keycloak_quarkus_hostname_admin: required: false description: "Service URL for the admin console" type: "str" keycloak_quarkus_admin_url: required: false - description: "Deprecated in v26, use keycloak_quarkus_admin instead." + description: "Deprecated in v26, use keycloak_quarkus_hostname_admin instead." type: "str" keycloak_quarkus_metrics_enabled: default: false diff --git a/roles/keycloak_quarkus/tasks/deprecations.yml b/roles/keycloak_quarkus/tasks/deprecations.yml index fe269e9..3d1b9d7 100644 --- a/roles/keycloak_quarkus/tasks/deprecations.yml +++ b/roles/keycloak_quarkus/tasks/deprecations.yml @@ -86,16 +86,16 @@ - print deprecation warning # https://docs.redhat.com/en/documentation/red_hat_build_of_keycloak/26.0/html-single/upgrading_guide/index#new_hostname_options -- name: Check deprecation of keycloak_quarkus_admin_url -> keycloak_quarkus_admin +- name: Check deprecation of keycloak_quarkus_admin_url -> keycloak_quarkus_hostname_admin when: - - keycloak_quarkus_admin is not defined + - keycloak_quarkus_hostname_admin is not defined - keycloak_quarkus_admin_url is defined - keycloak_quarkus_admin_url != '' delegate_to: localhost run_once: true changed_when: keycloak_quarkus_show_deprecation_warnings ansible.builtin.set_fact: - keycloak_quarkus_admin: "{{ keycloak_quarkus_admin_url }}" + keycloak_quarkus_hostname_admin: "{{ keycloak_quarkus_admin_url }}" deprecated_variable: "keycloak_quarkus_admin_url" # read in deprecation handler notify: - print deprecation warning diff --git a/roles/keycloak_quarkus/templates/keycloak.conf.j2 b/roles/keycloak_quarkus/templates/keycloak.conf.j2 index 6a4a6c1..f15bbd8 100644 --- a/roles/keycloak_quarkus/templates/keycloak.conf.j2 +++ b/roles/keycloak_quarkus/templates/keycloak.conf.j2 @@ -50,7 +50,7 @@ https-trust-store-password={{ keycloak_quarkus_https_trust_store_password }} # Client URL configuration hostname={{ keycloak_quarkus_hostname }} -hostname-admin={{ keycloak_quarkus_admin }} +hostname-admin={{ keycloak_quarkus_hostname_admin }} hostname-strict={{ keycloak_quarkus_hostname_strict | lower }} hostname-backchannel-dynamic={{ keycloak_quarkus_hostname_backchannel_dynamic | lower }} From 70d61ce8dee578858f8803251b58ca8cafab520d Mon Sep 17 00:00:00 2001 From: Guido Grazioli Date: Wed, 16 Apr 2025 11:58:04 +0200 Subject: [PATCH 205/205] rename ispn parameters --- roles/keycloak_quarkus/README.md | 79 ++++++++++--------- .../keycloak_quarkus/meta/argument_specs.yml | 18 ++--- 2 files changed, 46 insertions(+), 51 deletions(-) diff --git a/roles/keycloak_quarkus/README.md b/roles/keycloak_quarkus/README.md index 6427209..dac1dd2 100644 --- a/roles/keycloak_quarkus/README.md +++ b/roles/keycloak_quarkus/README.md @@ -50,9 +50,6 @@ Role Defaults |`keycloak_quarkus_host`| Deprecated, use `keycloak_quarkus_hostname` instead. | | |`keycloak_quarkus_port`| Deprecated, use `keycloak_quarkus_hostname` instead. | | |`keycloak_quarkus_path`| Deprecated, use `keycloak_quarkus_hostname` instead. | | -|`keycloak_quarkus_http_port`| HTTP listening port | `8080` | -|`keycloak_quarkus_https_port`| TLS HTTP listening port | `8443` | -|`keycloak_quarkus_http_management_port`| Port of the management interface. Relevant only when something is exposed on the management interface - see the guide for details. | `9000` | |`keycloak_quarkus_service_user`| Posix account username | `keycloak` | |`keycloak_quarkus_service_group`| Posix account group | `keycloak` | |`keycloak_quarkus_service_restart_always`| systemd restart always behavior activation | `False` | @@ -66,26 +63,8 @@ Role Defaults |`keycloak_quarkus_additional_env_vars` | List of additional env variables of { key: str, value: str} to be put in sysconfig file | `[]` | |`keycloak_quarkus_frontend_url`| Deprecated, use `keycloak_quarkus_hostname` instead. | | |`keycloak_quarkus_admin_url`| Deprecated, use `keycloak_quarkus_hostname_admin` instead. | | -|`keycloak_quarkus_http_relative_path` | Set the path relative to / for serving resources. The path must start with a / | `/` | -|`keycloak_quarkus_http_management_relative_path` | Set the path relative to / for serving resources from management interface. The path must start with a /. If not given, the value is inherited from HTTP options. Relevant only when something is exposed on the management interface - see the guide for details. | `/` | -|`keycloak_quarkus_http_enabled`| Enable listener on HTTP port | `True` | |`keycloak_quarkus_health_check_url`| Full URL (including scheme, host, path, fragment etc.) used for health check endpoint; keycloak_quarkus_hostname will NOT be prepended; helpful when health checks should happen against http port, but keycloak_quarkus_hostname uses https scheme per default | `` | |`keycloak_quarkus_health_check_url_path`| Path to the health check endpoint; keycloak_quarkus_hostname will be prepended automatically; Note that keycloak_quarkus_health_check_url takes precedence over this property | `realms/master/.well-known/openid-configuration` | -|`keycloak_quarkus_https_key_file_enabled`| Enable listener on HTTPS port | `False` | -|`keycloak_quarkus_key_file_copy_enabled`| Enable copy of key file to target host | `False` | -|`keycloak_quarkus_key_content`| Content of the TLS private key. Use `"{{ lookup('file', 'server.key.pem') }}"` to lookup a file. | `""` | -|`keycloak_quarkus_key_file`| The file path to a private key in PEM format | `/etc/pki/tls/private/server.key.pem` | -|`keycloak_quarkus_cert_file_copy_enabled`| Enable copy of cert file to target host | `False`| -|`keycloak_quarkus_cert_file_src`| Set the source file path | `""` | -|`keycloak_quarkus_cert_file`| The file path to a server certificate or certificate chain in PEM format | `/etc/pki/tls/certs/server.crt.pem` | -|`keycloak_quarkus_https_key_store_enabled`| Enable configuration of HTTPS via a key store | `False` | -|`keycloak_quarkus_key_store_file`| Deprecated, use `keycloak_quarkus_https_key_store_file` instead. || -|`keycloak_quarkus_key_store_password`| Deprecated, use `keycloak_quarkus_https_key_store_password` instead.|| -|`keycloak_quarkus_https_key_store_file`| The file path to the key store | `{{ keycloak.home }}/conf/key_store.p12` | -|`keycloak_quarkus_https_key_store_password`| Password for the key store | `""` | -|`keycloak_quarkus_https_trust_store_enabled`| Enable configuration of the https trust store | `False` | -|`keycloak_quarkus_https_trust_store_file`| The file path to the trust store | `{{ keycloak.home }}/conf/trust_store.p12` | -|`keycloak_quarkus_https_trust_store_password`| Password for the trust store | `""` | |`keycloak_quarkus_proxy_headers`| Parse reverse proxy headers (`forwarded` or `xforwarded`) | `""` | |`keycloak_quarkus_config_key_store_file`| Path to the configuration key store; only used if `keycloak_quarkus_keystore_password` is not empty | `{{ keycloak.home }}/conf/conf_store.p12` if `keycloak_quarkus_keystore_password != ''`, else `''` | |`keycloak_quarkus_config_key_store_password`| Password of the configuration keystore; if non-empty, `keycloak_quarkus_db_pass` will be saved to the keystore at `keycloak_quarkus_config_key_store_file` instead of being written to the configuration file in clear text | `""` | @@ -128,7 +107,27 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| |`keycloak_quarkus_http_relative_path`| Set the path relative to / for serving resources. The path must start with a / | `/` | - +|`keycloak_quarkus_http_port`| HTTP listening port | `8080` | +|`keycloak_quarkus_https_port`| TLS HTTP listening port | `8443` | +|`keycloak_quarkus_http_management_port`| Port of the management interface. Relevant only when something is exposed on the management interface - see the guide for details. | `9000` | +|`keycloak_quarkus_https_key_store_file`| The file path to the key store | `{{ keycloak.home }}/conf/key_store.p12` | +|`keycloak_quarkus_https_key_store_password`| Password for the key store | `""` | +|`keycloak_quarkus_https_trust_store_enabled`| Enable configuration of the https trust store | `False` | +|`keycloak_quarkus_https_trust_store_file`| The file path to the trust store | `{{ keycloak.home }}/conf/trust_store.p12` | +|`keycloak_quarkus_https_trust_store_password`| Password for the trust store | `""` | +|`keycloak_quarkus_https_key_file_enabled`| Enable listener on HTTPS port | `False` | +|`keycloak_quarkus_key_file_copy_enabled`| Enable copy of key file to target host | `False` | +|`keycloak_quarkus_key_content`| Content of the TLS private key. Use `"{{ lookup('file', 'server.key.pem') }}"` to lookup a file. | `""` | +|`keycloak_quarkus_key_file`| The file path to a private key in PEM format | `/etc/pki/tls/private/server.key.pem` | +|`keycloak_quarkus_cert_file_copy_enabled`| Enable copy of cert file to target host | `False`| +|`keycloak_quarkus_cert_file_src`| Set the source file path | `""` | +|`keycloak_quarkus_cert_file`| The file path to a server certificate or certificate chain in PEM format | `/etc/pki/tls/certs/server.crt.pem` | +|`keycloak_quarkus_https_key_store_enabled`| Enable configuration of HTTPS via a key store | `False` | +|`keycloak_quarkus_key_store_file`| Deprecated, use `keycloak_quarkus_https_key_store_file` instead. || +|`keycloak_quarkus_key_store_password`| Deprecated, use `keycloak_quarkus_https_key_store_password` instead.|| +|`keycloak_quarkus_http_relative_path` | Set the path relative to / for serving resources. The path must start with a / | `/` | +|`keycloak_quarkus_http_management_relative_path` | Set the path relative to / for serving resources from management interface. The path must start with a /. If not given, the value is inherited from HTTP options. Relevant only when something is exposed on the management interface - see the guide for details. | `/` | +|`keycloak_quarkus_http_enabled`| Enable listener on HTTP port | `True` | #### Database configuration @@ -146,13 +145,25 @@ Role Defaults | Variable | Description | Default | |:---------|:------------|:--------| -|`keycloak_quarkus_ispn_user` | Username for connecting to infinispan | `supervisor` | -|`keycloak_quarkus_ispn_pass` | Password for connecting to infinispan | `supervisor` | -|`keycloak_quarkus_ispn_hosts` | host name/port for connecting to infinispan, eg. host1:11222;host2:11222 | `localhost:11222` | -|`keycloak_quarkus_ispn_sasl_mechanism` | Infinispan auth mechanism | `SCRAM-SHA-512` | -|`keycloak_quarkus_ispn_use_ssl` | Whether infinispan uses TLS connection | `false` | -|`keycloak_quarkus_ispn_trust_store_path` | Path to infinispan server trust certificate | `/etc/pki/java/cacerts` | -|`keycloak_quarkus_ispn_trust_store_password` | Password for infinispan certificate keystore | `changeit` | +|`keycloak_quarkus_cache_remote_username` | Username for connecting to infinispan | `supervisor` | +|`keycloak_quarkus_cache_remote_password` | Password for connecting to infinispan | `supervisor` | +|`keycloak_quarkus_cache_remote_host` | host name/port for connecting to infinispan, eg. host1:11222;host2:11222 | `localhost:11222` | +|`keycloak_quarkus_cache_remote_sasl_mechanism` | Infinispan auth mechanism | `SCRAM-SHA-512` | +|`keycloak_quarkus_cache_remote_tls_enabled` | Whether infinispan uses TLS connection | `false` | + + +#### Logging configuration + +| Variable | Description | Default | +|:---------|:------------|:--------| +|`keycloak_quarkus_log`| Enable one or more log handlers in a comma-separated list | `file` | +|`keycloak_quarkus_log_level`| The log level of the root category or a comma-separated list of individual categories and their levels | `info` | +|`keycloak_quarkus_log_file`| Set the log file path and filename relative to keycloak home | `data/log/keycloak.log` | +|`keycloak_quarkus_log_format`| Set a format specific to file log entries | `%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n` | +|`keycloak_quarkus_log_target`| Set the destination of the keycloak log folder link | `/var/log/keycloak` | +|`keycloak_quarkus_log_max_file_size`| Set the maximum log file size before a log rotation happens; A size configuration option recognises string in this format (shown as a regular expression): `[0-9]+[KkMmGgTtPpEeZzYy]?`. If no suffix is given, assume bytes. | `10M` | +|`keycloak_quarkus_log_max_backup_index`| Set the maximum number of archived log files to keep" | `10` | +|`keycloak_quarkus_log_file_suffix`| Set the log file handler rotation file suffix. When used, the file will be rotated based on its suffix; Note: If the suffix ends with `.zip` or `.gz`, the rotation file will also be compressed. | `.yyyy-MM-dd.zip` | #### Miscellaneous configuration @@ -168,14 +179,6 @@ Role Defaults |`keycloak_quarkus_master_realm` | Name for rest authentication realm | `master` | |`keycloak_auth_client` | Authentication client for configuration REST calls | `admin-cli` | |`keycloak_force_install` | Remove pre-existing versions of service | `False` | -|`keycloak_quarkus_log`| Enable one or more log handlers in a comma-separated list | `file` | -|`keycloak_quarkus_log_level`| The log level of the root category or a comma-separated list of individual categories and their levels | `info` | -|`keycloak_quarkus_log_file`| Set the log file path and filename relative to keycloak home | `data/log/keycloak.log` | -|`keycloak_quarkus_log_format`| Set a format specific to file log entries | `%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n` | -|`keycloak_quarkus_log_target`| Set the destination of the keycloak log folder link | `/var/log/keycloak` | -|`keycloak_quarkus_log_max_file_size`| Set the maximum log file size before a log rotation happens; A size configuration option recognises string in this format (shown as a regular expression): `[0-9]+[KkMmGgTtPpEeZzYy]?`. If no suffix is given, assume bytes. | `10M` | -|`keycloak_quarkus_log_max_backup_index`| Set the maximum number of archived log files to keep" | `10` | -|`keycloak_quarkus_log_file_suffix`| Set the log file handler rotation file suffix. When used, the file will be rotated based on its suffix; Note: If the suffix ends with `.zip` or `.gz`, the rotation file will also be compressed. | `.yyyy-MM-dd.zip` | |`keycloak_quarkus_proxy_mode`| The proxy address forwarding mode if the server is behind a reverse proxy | `edge` | |`keycloak_quarkus_start_dev`| Whether to start the service in development mode (start-dev) | `False` | |`keycloak_quarkus_transaction_xa_enabled`| Whether to use XA transactions | `True` | @@ -183,7 +186,7 @@ Role Defaults |`keycloak_quarkus_show_deprecation_warnings`| Whether deprecation warnings should be shown | `True` | -#### Vault SPI +#### Vault configuration | Variable | Description | Default | |:---------|:------------|:--------| diff --git a/roles/keycloak_quarkus/meta/argument_specs.yml b/roles/keycloak_quarkus/meta/argument_specs.yml index 901e774..1c995db 100644 --- a/roles/keycloak_quarkus/meta/argument_specs.yml +++ b/roles/keycloak_quarkus/meta/argument_specs.yml @@ -255,34 +255,26 @@ argument_specs: default: true description: "If the server should expose health check endpoints on the management interface" type: "bool" - keycloak_quarkus_ispn_user: + keycloak_quarkus_cache_remote_username: default: "supervisor" description: "Username for connecting to infinispan" type: "str" - keycloak_quarkus_ispn_pass: + keycloak_quarkus_cache_remote_password: default: "supervisor" description: "Password for connecting to infinispan" type: "str" - keycloak_quarkus_ispn_hosts: + keycloak_quarkus_cache_remote_host: default: "localhost:11222" description: "host name/port for connecting to infinispan, eg. host1:11222;host2:11222" type: "str" - keycloak_quarkus_ispn_sasl_mechanism: + keycloak_quarkus_cache_remote_sasl_mechanism: default: "SCRAM-SHA-512" description: "Infinispan auth mechanism" type: "str" - keycloak_quarkus_ispn_use_ssl: + keycloak_quarkus_cache_remote_tls_enabled: default: false description: "Whether infinispan uses TLS connection" type: "bool" - keycloak_quarkus_ispn_trust_store_path: - default: "/etc/pki/java/cacerts" - description: "Path to infinispan server trust certificate" - type: "str" - keycloak_quarkus_ispn_trust_store_password: - default: "changeit" - description: "Password for infinispan certificate keystore" - type: "str" keycloak_quarkus_db_engine: default: "postgres" description: "Database engine [mariadb,postres,mssql]"