Compare commits

...

463 commits
1.2.0 ... main

Author SHA1 Message Date
Guido Grazioli
a10bc95bfc
Merge pull request #266 from guidograzioli/major_bump_3
Some checks failed
CI / ci (push) Has been cancelled
Documentation / docs (push) Has been cancelled
Bump major and ansible-core versions
2025-04-09 20:28:52 +02:00
Guido Grazioli
314e2f26b2 Fix spell in parameter name 2025-04-09 18:08:18 +02:00
Guido Grazioli
f628b84fb0 disable restart health check because of selfsigned cert 2025-04-09 17:21:49 +02:00
Guido Grazioli
ac0ceca35f Update to ubi9 2025-04-09 09:45:22 +02:00
Guido Grazioli
744766fe3b update doc generation to 2.16 2025-04-08 15:36:38 +02:00
Guido Grazioli
7f980c44d2 Bump major and ansible-core versions 2025-04-08 11:58:47 +02:00
Guido Grazioli
532dc12a60
Merge pull request #254 from world-direct/feature/253_rhbk_v26
Some checks failed
CI / ci (push) Has been cancelled
Documentation / docs (push) Has been cancelled
Role support for keycloak/RHBK v26
2025-04-08 11:47:35 +02:00
Guido Grazioli
173a85638f
Merge pull request #257 from NilsDeckert/main
Some checks failed
CI / ci (push) Has been cancelled
Documentation / docs (push) Has been cancelled
Skip certificate checking
2025-04-01 15:27:39 +02:00
Guido Grazioli
81f019f8b5
Merge pull request #264 from guidograzioli/linter_reserved_words
Variables names must not be Ansible reserved names
2025-04-01 15:25:10 +02:00
Guido Grazioli
5db96afa56 Variables names must not be Ansible reserved names 2025-04-01 15:20:37 +02:00
Helmut Wolf
fa36721207 Improve string interpolation 2025-01-20 09:44:27 +01:00
Helmut Wolf
86284b12c2 Fix molecule tests 2025-01-09 12:17:07 +01:00
Nils Deckert
b3e93dd89b Skip certificate checking 2024-12-20 17:21:49 +01:00
Helmut Wolf
e029e1c2fd keycloak_quarkus: Introduce keycloak_quarkus_health_check_url 2024-12-13 12:12:02 +01:00
Helmut Wolf
d0f19b59dc 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
2024-12-13 12:11:35 +01:00
Helmut Wolf
213449ec58 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
2024-12-13 12:11:35 +01:00
Helmut Wolf
277e1336ee RHBK v26: Migrate to keycloak_quarkus_bootstrap_admin_user[_password] (Process for creation of admin account changed #248) 2024-12-13 12:11:35 +01:00
Helmut Wolf
58233549a7 keycloak.conf: Remove config-keystore-type (KC/RHBK v26 Support #253)
Cf. <https://docs.redhat.com/en/documentation/red_hat_build_of_keycloak/26.0/html-single/upgrading_guide/index#keystore_and_trust_store_default_format_change>
2024-12-13 12:11:35 +01:00
Helmut Wolf
0c58ae48ff RHBK v26: Update ispn session usages (KC/RHBK v26 Support #253)
Cf. <https://docs.redhat.com/en/documentation/red_hat_build_of_keycloak/26.0/html-single/upgrading_guide/index#restricting_the_size_of_session_caches>
2024-12-13 12:11:35 +01:00
Helmut Wolf
bf0bd9e1da RHBK v26: Update mssqj jdbc driver (KC/RHBK v26 Support #253)
As per <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>
2024-12-13 12:11:35 +01:00
Helmut Wolf
5d15d37890 RHBK v26: Raise default KC+RHBK versions to v26.x (#253) 2024-12-13 12:11:35 +01:00
Guido Grazioli
910a2aa5d4
Merge pull request #252 from world-direct/feature/cache_buster
Add theme cache invalidation handler
2024-12-12 09:36:18 +01:00
Helmut Wolf
5f534ca566 keycloak_quarkus: Add theme cache invalidation handler 2024-12-12 09:05:09 +01:00
Guido Grazioli
692fb59797
Merge pull request #251 from RanabirChakraborty/increase_access_token_lifespan
Access token lifespan is too short for ansible run
2024-12-11 16:19:13 +01:00
Ranabir Chakraborty
d1859aaff2 Access token lifespan is too short for ansible run 2024-12-03 22:40:25 +05:30
Guido Grazioli
0d0e52f9ff
Merge pull request #250 from world-direct/feature/249
Rebuild config and restart service for local providers
2024-11-25 08:40:54 +01:00
Helmut Wolf
68a0f88423 keycloak_quarkus: Rebuild config and restart service for local providers (#249) 2024-11-22 08:08:09 +01:00
ansible-middleware-core
333d55ad73 Bump version to 2.4.4 2024-10-16 07:24:57 +00:00
ansible-middleware-core
f6fdae4aa8 Update changelog for release 2.4.3
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2024-10-16 07:24:42 +00:00
Guido Grazioli
b8c11f3ca8
Merge pull request #241 from guidograzioli/update_24_0_5
Update keycloak to 24.0.5
2024-10-16 09:02:43 +02:00
Guido Grazioli
1279937bb0 Update keycloak to 24.0.5 2024-10-16 08:56:53 +02:00
Guido Grazioli
c57753f608
Merge pull request #240 from guidograzioli/update_modules
update keycloak modules
2024-10-14 15:12:44 +02:00
Guido Grazioli
be19ec1289 update tests 2024-10-14 14:36:58 +02:00
Guido Grazioli
5f1b43f37b update docs 2024-10-14 10:34:20 +02:00
Guido Grazioli
c6bb815979 update keycloak modules 2024-10-14 10:22:10 +02:00
ansible-middleware-core
ac4511bea9 Bump version to 2.4.3 2024-09-26 08:52:17 +00:00
ansible-middleware-core
c8021f3102 Update changelog for release 2.4.2
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2024-09-26 08:52:04 +00:00
Guido Grazioli
0386254073
Merge pull request #239 from guidograzioli/238_controller_download_path
New parameter `keycloak_quarkus_download_path`
2024-09-26 10:35:18 +02:00
Guido Grazioli
b2edea8777 linter 2024-09-26 10:22:54 +02:00
Guido Grazioli
fc0ee5a896 refactor default test for keycloak-quarkus offline 2024-09-26 10:22:42 +02:00
Guido Grazioli
eb66d4a412 update prereqs validation 2024-09-26 10:22:28 +02:00
Guido Grazioli
f170257205 Add local download path 2024-09-24 09:21:10 +02:00
Guido Grazioli
3f4617c32c
Merge pull request #237 from guidograzioli/236_waitfor_port_number
Add wait_for_port number parameter
2024-07-31 17:30:35 +02:00
Guido Grazioli
34caf6a490
add wait_for_port number parameter 2024-07-31 17:18:30 +02:00
Guido Grazioli
fa6ac99b34
Merge pull request #235 from guidograzioli/keycloak_realm_test
add verify steps for quarkus/keycloak_realm
2024-07-31 15:04:35 +02:00
Guido Grazioli
a35c963a65
add verify steps for quarkus/keycloak_realm 2024-07-18 13:01:01 +02:00
Guido Grazioli
11aab0f5e2
add verify steps for quarkus/keycloak_realm 2024-07-18 12:53:49 +02:00
ansible-middleware-core
fa2319d5da Bump version to 2.4.2 2024-07-02 14:23:53 +00:00
ansible-middleware-core
7c520dcdd2 Update changelog for release 2.4.1
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2024-07-02 14:23:37 +00:00
Guido Grazioli
35b3b090f6
ci: update READMEs 2024-07-02 15:59:16 +02:00
Guido Grazioli
94f1b8b355
ci: update README 2024-07-02 15:46:05 +02:00
Guido Grazioli
e40f554936 ci: add traffic wf 2024-06-27 11:02:32 +02:00
Guido Grazioli
64e2a95685 ci: add traffic wf 2024-06-27 11:01:38 +02:00
Guido Grazioli
c6fac7bb70 ci: add traffic wf 2024-06-27 11:00:29 +02:00
ansible-middleware-core
5f059e8d63 Bump version to 2.4.1 2024-06-04 15:44:35 +00:00
ansible-middleware-core
e927ddbb6c Update changelog for release 2.4.0
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2024-06-04 15:44:20 +00:00
Guido Grazioli
a82bdfbbb6 Bump to 2.4.0 2024-06-04 17:36:20 +02:00
Guido Grazioli
c850484e67
Merge pull request #234 from gionn/fix-restart-health-check-default
Enable by default health check on restart
2024-06-04 17:25:52 +02:00
Giovanni Toraldo
a4deaa005a
Enable by default health check on restart 2024-06-04 17:00:11 +02:00
Guido Grazioli
4fb44091d6 ci: fix missing symlink 2024-05-30 08:44:04 +02:00
Guido Grazioli
883127d280
Merge pull request #232 from guidograzioli/linter_ansible_215
Update minimum ansible-core version > 2.15
2024-05-22 10:04:41 +02:00
Guido Grazioli
e69e5b7ba4 readme 2024-05-21 12:41:31 +02:00
Guido Grazioli
bf1871182b linter 2024-05-21 12:35:33 +02:00
Guido Grazioli
adfee5f6e1 ci 2024-05-21 12:34:11 +02:00
Guido Grazioli
ef53ca545a update yamllint 2024-05-21 12:31:40 +02:00
Guido Grazioli
2092c2d23a Update minimum ansible-core version > 2.15 2024-05-21 12:27:45 +02:00
ansible-middleware-core
8ca73364e9 Bump version to 2.3.1 2024-05-20 10:22:09 +00:00
ansible-middleware-core
df1939e387 Update changelog for release 2.3.0
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2024-05-20 10:21:55 +00:00
Guido Grazioli
0de0b654ee
Merge pull request #227 from world-direct/feature/226
`proxy-header` enhancement
2024-05-16 16:49:06 +02:00
Helmut Wolf
62cbaa3596 Introduce keycloak_quarkus_show_deprecation_warnings, disabled in molecule tests 2024-05-16 16:30:57 +02:00
Helmut Wolf
92c24e49e7 #226: add proper default value for proxy-headers 2024-05-16 12:45:24 +02:00
Helmut Wolf
cc012767a4 #226 - add deprecation warning 2024-05-16 12:45:24 +02:00
Helmut Wolf
4d31117c16 Fix RHBK version 2024-05-16 12:45:24 +02:00
Helmut Wolf
0fd8eb52d2 #226: CR changes 2024-05-16 12:45:24 +02:00
Helmut Wolf
6f2ed4d53b Fix #226 - minor proxy-header enhancement 2024-05-16 12:45:24 +02:00
Guido Grazioli
1519d46f0e
Merge pull request #231 from ansible-middleware/feature/182_restart_handler
Restart handler strategy behaviour
2024-05-16 11:25:02 +02:00
Guido Grazioli
4b21569f36 parameterize health check; refactor serial_then_parallel 2024-05-16 11:16:20 +02:00
Guido Grazioli
f63b20b9d4 Update verify steps 2024-05-15 20:01:58 +02:00
Guido Grazioli
fdcf1b2ed2 Add molecule scenario for HA restart 2024-05-15 19:53:33 +02:00
Guido Grazioli
c22389c86f address review reqs 2024-05-15 15:58:21 +02:00
Guido Grazioli
2d573c2b62 Add restart strategies, and allow custom task include
Co-authored-by: Helmut Wolf <hwo@world-direct.at>
Co-authored-by: Guido Grazioli <ggraziol@redhat.com>
2024-05-15 13:48:00 +02:00
Helmut Wolf
1e9a669dea #221 - add keycloak_quarkus_health_check_url_path config option 2024-05-15 10:28:46 +02:00
Helmut Wolf
db831fa339 #182 - CR changes 2024-05-15 10:17:32 +02:00
Helmut Wolf
d57be1f188 Close #182, #221: improve restart handler logic 2024-05-15 09:47:03 +02:00
Guido Grazioli
5adb28dcd8 Bump to 2.3.0 2024-05-15 09:22:45 +02:00
Guido Grazioli
477ce5eaa3
Merge pull request #223 from world-direct/feature/222_mvn_providers
Feature/222  keycloak_quarkus: Add support for custom providers hosted on MVN
2024-05-15 09:17:23 +02:00
Helmut Wolf
d2ece93c12 #222 Migrate to middleware_automation.common.maven_artifact 2024-05-14 20:33:29 +02:00
Guido Grazioli
1a23350a8f
Merge pull request #229 from world-direct/feature/228_sysconfig_custom_env_variables
Allow to add extra custom env vars in sysconfig file
2024-05-14 17:06:49 +02:00
Helmut Wolf
26316ddc50 #222: add support for local providers to be uploaded 2024-05-14 11:59:16 +02:00
Helmut Wolf
6d01ffbb77 Close #228: add support for custom env vars in sysconfig file 2024-05-14 11:10:38 +02:00
Helmut Wolf
d87c8ca8ac wip 2024-05-14 10:14:43 +02:00
Helmut Wolf
d8e9620a8a #222: Molecule tests 2024-05-14 10:14:43 +02:00
Helmut Wolf
4b902adc8d #222: Add support for maven providers 2024-05-14 10:14:15 +02:00
Guido Grazioli
1b69191a6e
Merge pull request #225 from world-direct/feature/224_policy_files
#224:  keycloak_quarkus: Add support for policy files
2024-05-14 09:11:51 +02:00
Helmut Wolf
6682853a2d #224: Add missing argument specs 2024-05-14 08:58:57 +02:00
Helmut Wolf
9f4623b05a #224: keycloak_quarkus: Add support for policy files 2024-05-14 08:36:55 +02:00
Guido Grazioli
599ce0179c
Merge pull request #220 from guidograzioli/rhbk_alternate_download_location
Download from alternate URL with optional http authentication
2024-05-10 15:33:51 +02:00
Guido Grazioli
8f14be37d7 add functionality 2024-05-10 10:17:37 +02:00
Guido Grazioli
3076c3d5ce
Merge pull request #218 from Footur/update-keycloak-v24.0.4
Update Keycloak to version 24.0.4
2024-05-09 11:08:47 +02:00
Guido Grazioli
6610a310ff
Merge pull request #217 from guidograzioli/major_upgrade_test
Port downstream upgrade
2024-05-09 11:08:23 +02:00
Footur
fcf629d05e Update Keycloak to version 24.0.4 2024-05-09 09:24:47 +02:00
Guido Grazioli
4bbc8e0256 update systemd service name in verify 2024-05-08 19:14:04 +02:00
Guido Grazioli
4c96cbe7f6 use sane version to be upgraded 2024-05-08 19:09:59 +02:00
Guido Grazioli
22f5ad902f add test to github actions 2024-05-08 19:05:24 +02:00
Guido Grazioli
3c22417674 Port downstream upgrade 2024-05-08 19:03:30 +02:00
Guido Grazioli
cd36eacb07
Merge pull request #215 from world-direct/feature/214_sqlserver_jdbc_version
Close #214: RHBK 24.*: Update sqlserver JDBC version
2024-05-08 18:45:03 +02:00
Helmut Wolf
a019823871 Close #214: RHBK 24.*: Update sqlserver JDBC version 2024-05-08 17:15:50 +02:00
Guido Grazioli
3863508df5
Merge pull request #213 from guidograzioli/2_2_3_linter
Linter warnings fix pass
2024-05-07 10:30:16 +02:00
Guido Grazioli
1115ee409a Linter warnings fix pass 2024-05-07 10:18:43 +02:00
Guido Grazioli
b497e946cc Bump tp 2.2.3 2024-05-07 09:47:12 +02:00
Guido Grazioli
5067c03201
Merge pull request #211 from guidograzioli/keycloak_rebuild_java_home
`kc.sh build` uses configured jdk
2024-05-06 13:13:20 +02:00
Guido Grazioli
a45b18dc85 kc.sh build uses configured jdk 2024-05-06 13:08:41 +02:00
Guido Grazioli
70834ccf13 downstream: remove problematic owner of downloaded zipfile 2024-05-06 12:03:44 +02:00
Guido Grazioli
2a7395c444 downstream: update default to rhbk 24.0.3 2024-05-06 11:20:00 +02:00
ansible-middleware-core
4da0e83ae9 Bump version to 2.2.3 2024-05-06 08:11:28 +00:00
ansible-middleware-core
b427cb8a24 Update changelog for release 2.2.2
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2024-05-06 08:11:11 +00:00
Guido Grazioli
fa39e9b824
Merge pull request #210 from Footur/copy-key-material
Enable copying of key material
2024-05-06 08:28:09 +02:00
Footur
320a5f0d9a 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.
2024-05-05 13:58:19 +02:00
Footur
7141e1c9b2 Test: Installation of key material via Ansible role 2024-05-05 12:11:51 +02:00
Footur
9bc1ae69e9 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.
2024-05-03 16:34:57 +02:00
Guido Grazioli
bfbbacc72b
Merge pull request #209 from guidograzioli/205_controller_become
controller priv escalation
2024-05-03 14:45:55 +02:00
Guido Grazioli
feec4d9f8b controller priv escalation 2024-05-03 13:03:18 +02:00
Guido Grazioli
ba127153ff
Merge pull request #207 from InfoSec812/Issue_206-_-fix-misnamed-params-and-allow-invalid-certs
jdbc_download and validate_certs params update
2024-05-03 08:47:38 +02:00
Deven Phillips
b14d75dfab 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
2024-05-02 14:33:36 -04:00
ansible-middleware-core
1d6a6eb7ee Bump version to 2.2.2 2024-05-02 17:00:01 +00:00
ansible-middleware-core
1ab3ebc2a4 Update changelog for release 2.2.1
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2024-05-02 16:59:47 +00:00
Guido Grazioli
d16c23faf9
Merge pull request #204 from InfoSec812/Issue_203-_-fix-input-validation-when-clause
Fix logic in when clause
2024-05-02 18:46:05 +02:00
Deven Phillips
978494524f Fix errors introduced 2024-05-02 12:31:16 -04:00
Deven Phillips
1a73c39a91 Fix logic in when clause 2024-05-02 12:09:36 -04:00
ansible-middleware-core
9e6a6f6076 Bump version to 2.2.1 2024-05-01 14:44:15 +00:00
ansible-middleware-core
55f6881b2f Update changelog for release 2.2.0
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2024-05-01 14:44:01 +00:00
Guido Grazioli
41cbcc41e8
Merge pull request #202 from InfoSec812/Issue_200-_-customize-jdbc-driver-downloads
Customize jdbc driver downloads, optional authentication
2024-05-01 10:01:32 +02:00
Deven Phillips
c2904bf20d Use FQCN for fail module 2024-04-30 14:48:10 -04:00
Deven Phillips
e76b33e1db Merge remote-tracking branch 'upstream/main' into Issue_200-_-customize-jdbc-driver-downloads 2024-04-30 14:29:26 -04:00
Deven Phillips
a7b9f0ef97 Add option to override JDBC download parameters 2024-04-30 14:27:42 -04:00
Guido Grazioli
eafc4586d6 ci: turn historicized docs off 2024-04-30 13:09:27 +02:00
Guido Grazioli
8493adc5c8
Merge pull request #201 from guidograzioli/custom_providers
Providers config and custom providers
2024-04-30 12:47:53 +02:00
Guido Grazioli
43b9ffcb64 Providers config and custom providers 2024-04-30 10:45:20 +02:00
Guido Grazioli
a33393a477 ci: downstream molecule fixes 2024-04-25 14:11:05 +02:00
Guido Grazioli
278a70d627 ci: downstream molecule fixes 2024-04-25 13:57:31 +02:00
Guido Grazioli
6967385c7f ci: downstream molecule fixes 2024-04-25 13:03:03 +02:00
Guido Grazioli
ac23e04d6a ci: downstream molecule fixes 2024-04-25 08:16:56 +02:00
Guido Grazioli
4c056d886e ci: downstream molecule fixes 2024-04-24 21:20:16 +02:00
Guido Grazioli
213a9a0766 ci: downstream molecule fixes 2024-04-24 17:56:15 +02:00
Guido Grazioli
2925ea8cf1 Add wait_for systemd logic 2024-04-24 16:17:05 +02:00
Guido Grazioli
82498ab3f5
Merge pull request #195 from InfoSec812/Issue-193_-_add-option-for-hostname-strict-https
Added hostname-strict-https option
2024-04-19 16:05:46 +02:00
Guido Grazioli
16accd5e30
Merge branch 'main' into Issue-193_-_add-option-for-hostname-strict-https 2024-04-19 16:00:09 +02:00
Deven Phillips
04bb465992 Added argument specs 2024-04-19 09:55:08 -04:00
Guido Grazioli
b978e8bb88
Merge pull request #197 from world-direct/feature/190_remove_KEYCLOAK_ADMIN_envs
#190: remove `keycloak_quarkus_admin_user[_pass]` once keycloak is bootstrapped
2024-04-19 14:44:05 +02:00
Helmut Wolf
289b4767e0 #190: remove keycloak_quarkus_admin_user[_pass] once keycloak is bootstrapped 2024-04-19 13:42:28 +02:00
Guido Grazioli
9a961f743b
Merge pull request #196 from guidograzioli/172_vaults
Keystore based vault SPI
2024-04-19 09:06:38 +02:00
Deven Phillips
b8cba487ac Add better error trapping for booleans 2024-04-18 13:15:46 -04:00
Guido Grazioli
ff198bcd3e workaround debug logfile too long for slurp 2024-04-18 11:06:14 +02:00
Guido Grazioli
d06dcea998 Add argument specs, update README 2024-04-18 10:49:38 +02:00
Guido Grazioli
89db3fa36f Implement vault config 2024-04-18 10:44:17 +02:00
Guido Grazioli
cd8d61afc3 Update molecule test for keystore vault 2024-04-18 10:43:48 +02:00
Deven Phillips
47e6644fdd Ensure that value for keycloak_quarkus_hostname_strict_https is boolean, otherwise ignore it 2024-04-17 16:57:52 -04:00
Deven Phillips
3e28b3f4f7 Added hostname-strict-https option 2024-04-17 16:52:18 -04:00
Guido Grazioli
f7bcac79d0
Merge pull request #194 from guidograzioli/keycloak_24_update
Update keycloak to 24.0
2024-04-17 18:16:34 +02:00
Guido Grazioli
10057262bc 'fix' changelog 2024-04-17 18:07:42 +02:00
Guido Grazioli
5808d055ae Update keycloak to 24.0 2024-04-17 17:53:13 +02:00
Guido Grazioli
8060dd7fb8 Bump minor and start 2.2 2024-04-17 17:51:33 +02:00
Guido Grazioli
4f8ed5194c
Merge pull request #189 from world-direct/feature/188_config_keystore
#188: add support for configuration key store
2024-04-17 17:50:30 +02:00
ansible-middleware-core
462389cf0f Bump version to 2.1.3 2024-04-17 15:49:15 +00:00
ansible-middleware-core
903938ca16 Update changelog for release 2.1.2
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2024-04-17 15:49:00 +00:00
Guido Grazioli
74636e8629 ci: final round of linting 2024-04-17 17:29:38 +02:00
Guido Grazioli
6706fd9bf5 ci: bump and fix final linter warnings 2024-04-17 17:24:57 +02:00
Helmut Wolf
e991bd32c8 Fix typos 2024-04-17 17:09:44 +02:00
Helmut Wolf
d469d389f3 Fix linter issues 2024-04-17 17:09:44 +02:00
Helmut Wolf
c38642e0cd #188: fail early when no keytool installed 2024-04-17 17:09:44 +02:00
Helmut Wolf
0ee29eb483 #188: keycloak_quarkus: allow setting "sensitive options" using a Java KeyStore file #188 2024-04-17 17:09:44 +02:00
Helmut Wolf
60ca798e1a Rename keycloak_quarkus_*_store_* attributes 2024-04-17 17:09:44 +02:00
Helmut Wolf
921364b451 Fix docs 2024-04-17 17:09:44 +02:00
Guido Grazioli
50d189ee14 ci: more linter fixes 2024-04-17 16:56:56 +02:00
Guido Grazioli
5b459f3dde ci: more linter fixes 2024-04-17 16:48:24 +02:00
Guido Grazioli
f0318b2ecf
Merge pull request #192 from guidograzioli/xxx_linter_1
Comprehensive linter warning fixes
2024-04-17 16:26:18 +02:00
Guido Grazioli
1f910bd400 Comprehensive linter warning fixes 2024-04-17 16:19:34 +02:00
Guido Grazioli
d17c364257 downstream: ci sudo workaround 2024-04-17 12:14:25 +02:00
Guido Grazioli
1ff6f237a9 Bump 2.1.1 2024-04-17 11:58:11 +02:00
Guido Grazioli
0c0c4e19ea downstream: update rhbk to 2.0.10 2024-04-17 11:57:44 +02:00
Guido Grazioli
7bedb08f6e ci: update release wf params 2024-04-17 11:14:38 +02:00
Guido Grazioli
5464a01a62 ci: update doc links, test triggers 2024-04-17 11:08:04 +02:00
ansible-middleware-core
2cf3e2470d Bump version to 2.1.2 2024-04-17 08:58:56 +00:00
ansible-middleware-core
ad6021c29a Update changelog for release 2.1.1
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2024-04-17 08:58:43 +00:00
Guido Grazioli
05ebd90121
Merge pull request #191 from guidograzioli/190_sysconfig_worldreadable
Unrelax configuration file permissions
2024-04-17 10:51:45 +02:00
Guido Grazioli
1229a0b023 Unrelax configuration file permissions 2024-04-17 10:46:23 +02:00
Guido Grazioli
4ba9014edb
Merge pull request #187 from roumano/parse_proxy_headers
Permit parse reverse proxy headers
2024-04-17 10:36:50 +02:00
Christian Iuga
ea57f8b689 remove unwanted extra code 2024-04-16 13:41:09 +02:00
Christian Iuga
3fbae4882e move keycloak_quarkus_proxy_headers into keycloak.conf 2024-04-16 13:39:33 +02:00
Christian Iuga
27717d7b4e Avoid cmd-line arguments
Fix https://github.com/ansible-middleware/keycloak/pull/187#discussion_r1565779164
2024-04-15 15:50:55 +02:00
Christian Iuga
4aa862101c Add new variable keycloak_quarkus_proxy_headers into meta/argument_specs.yml
Fix comment https://github.com/ansible-middleware/keycloak/pull/187#discussion_r1565772058
2024-04-15 15:48:02 +02:00
Christian Iuga
8e2f3eb77f 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
2024-04-15 14:41:56 +02:00
Guido Grazioli
10d4cb8db7
Merge pull request #186 from guidograzioli/185_java_heap_options
JVM arguments go in JAVA_OPTS
2024-04-09 17:16:17 +02:00
Guido Grazioli
8f8de33350 JVM arguments go IN JAVA_OPTS 2024-04-08 16:47:49 +02:00
Guido Grazioli
7dceb7f819
Merge pull request #184 from avskor/issue-125
Fix permissions on controller-side downloaded artifacts
2024-04-08 09:15:52 +02:00
avskor
c2e456e1d5 Fix #125. Permission error when the become variable is set to true in the playbook 2024-04-04 11:22:18 +03:00
Guido Grazioli
4421375dd5
Merge pull request #181 from guidograzioli/multi_distro_refactor
Multi distro refactor
2024-03-25 16:42:29 +01:00
Guido Grazioli
2bbf7d9cc4 revert JVM var that cannot be overridden 2024-03-25 16:30:13 +01:00
Guido Grazioli
467cfda0f7 same changes for keycloak-legacy 2024-03-25 16:00:18 +01:00
Guido Grazioli
e17505fe42 update molecule for debian container 2024-03-25 15:37:02 +01:00
Guido Grazioli
0e4df659f4 add test 2024-03-25 14:35:28 +01:00
Guido Grazioli
3400b64b10 add to ci 2024-03-25 14:34:25 +01:00
Guido Grazioli
3b1534d700 refactor 2024-03-25 10:19:28 +01:00
Guido Grazioli
dd6171f024 Add ansible_family based vars loading 2024-03-25 10:19:08 +01:00
Guido Grazioli
c1da6ea38d
Merge pull request #180 from guidograzioli/keycloak_realm_default
Use `keycloak_realm` as default for sub-entities
2024-03-25 09:40:30 +01:00
Guido Grazioli
56e4a43cf9 add keycloak_realm default to sub entities 2024-03-25 09:30:25 +01:00
Guido Grazioli
7a0a99a31c
Merge pull request #178 from Aeyk/ubuntu
Ubuntu compatibility
2024-03-18 09:09:07 +01:00
aeyk
fdce0bd922
Merge branch 'main' into ubuntu 2024-03-17 05:35:09 -04:00
Malik Kennedy
b9d9874a00
feat: ubuntu compatibility 2024-03-17 09:15:38 +00:00
Guido Grazioli
1cecf51f37 downstream: more updates to custom xml 2024-03-14 11:41:52 +01:00
Guido Grazioli
0cea03dfc0 downstream: simplify overridexml test 2024-03-14 10:37:09 +01:00
Guido Grazioli
0c079740e1 downstream: molecule custom xml that works with rhsso 2024-03-14 10:13:46 +01:00
Guido Grazioli
96804d8086 downstream: rhsso has new patch filename pattern 2024-03-13 17:55:30 +01:00
Guido Grazioli
a875166fe0
Merge pull request #176 from growi/templates_comment_filter
Utilize comment filter for `ansible_managed` annotations
2024-03-13 14:24:19 +01:00
Björn Großewinkelmann
a97c349f41
Utilize comment filter for {{ ansible_maanged }} annotations
Signed-off-by: Björn Großewinkelmann <bgrossew@redhat.com>
2024-03-13 00:19:42 +01:00
Romain Pelisse
a59a1fb8dd Rework Molecule prepare phase to install sudo only if root on target 2024-03-12 12:48:46 +01:00
Guido Grazioli
d74820190f ci: rename keycloak_quarkus infinispan jinja2 template 2024-02-28 17:10:02 +01:00
ansible-middleware-core
6541b5e386 Bump version to 2.1.1 2024-02-28 15:58:47 +00:00
ansible-middleware-core
1e1665adb0 Update changelog for release 2.1.0
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2024-02-28 15:58:33 +00:00
Guido Grazioli
33a839fec6
Merge pull request #171 from guidograzioli/170_quarkus_java_home_typo
keycloak_quarkus: fix custom JAVA_HOME parameter name
2024-02-27 19:35:31 +01:00
Guido Grazioli
d97ddbde3c add test 2024-02-27 19:27:07 +01:00
Guido Grazioli
7f021a849e Linter 2024-02-27 17:17:24 +01:00
Guido Grazioli
167bf512c5 fix typo in variable name 2024-02-27 17:17:14 +01:00
Guido Grazioli
beee25dec2
Merge pull request #169 from ansible-middleware/mol_sudo
Adapt molecule tests to work with none root user on target (sudo)
2024-02-26 18:39:42 +01:00
Romain Pelisse
5bd39a0d0e molecule: use block to skip assets download entirely if needed 2024-02-26 16:46:30 +01:00
Romain Pelisse
7324f48e8d molecule: cleanup prepare to use one play 2024-02-26 16:46:30 +01:00
Romain Pelisse
b3ca517583 molecule: adapt sudo setup to work when ansible is not connecting as root on the target 2024-02-26 16:46:26 +01:00
Guido Grazioli
b1848046dc
Merge pull request #168 from Footur/update-keycloak-v23.0.7
Update Keycloak to version 23.0.7
2024-02-26 10:19:54 +01:00
Guido Grazioli
983a1fb8f2
Merge pull request #167 from guidograzioli/xa_enable_recovery
Set enable-recovery when xa transactions are enabled
2024-02-26 10:19:44 +01:00
Footur
d4fb20b230 Update Keycloak to version 23.0.7 2024-02-22 17:10:22 +01:00
Guido Grazioli
f7bef0a956 set enable-recovery when xa transactions are enabled 2024-02-22 16:28:24 +01:00
Guido Grazioli
f62a97709a
Merge pull request #163 from world-direct/feature/162_keycloak_quarkus_sticky-session-encoder
keycloak_quarkus: `sticky-session`s for infinispan routes
2024-02-08 21:31:12 +01:00
Guido Grazioli
9593752e62
Merge pull request #161 from world-direct/feature/160_keycloak_quarkus_logging
keycloak_quarkus: Allow configuring log rotate options in quarkus configuration
2024-02-08 21:27:48 +01:00
Guido Grazioli
d6c29ed4fc
Merge pull request #159 from world-direct/feature/inifinispan_ha
#158: Feature/inifinispan TCPPING
2024-02-08 21:24:53 +01:00
Helmut Wolf
df81dc5497 #158: move TCPPING config to ispn config file 2024-02-08 16:26:48 +01:00
Helmut Wolf
4adab64dc0 #158: support for TCPPING 2024-02-08 16:26:48 +01:00
Helmut Wolf
e0d4920a49 feature/162: keycloak_quarkus: make spi-sticky-session-encoder-infinispan-should-attach-route configurable in keycloak.conf 2024-02-08 16:19:14 +01:00
Helmut Wolf
c2009a0a12 feature/160: CR changes 2024-02-08 16:10:32 +01:00
Helmut Wolf
0c5047bcc1 feature/160: keycloak_quarkus: Allow easier log setting configuration 2024-01-22 13:53:28 +01:00
Helmut Wolf
63f83d7744 add initial support for templating cache-ispn.xml 2024-01-22 12:38:29 +01:00
Guido Grazioli
64fa8bb788
Merge pull request #157 from world-direct/fix/156_infinispan
keycloak_quarkus: renamed infinispan host list configuration
2024-01-22 08:14:36 +01:00
Helmut Wolf
688ec956fc fix #156: quarkus 3 ispn config renamings 2024-01-19 09:54:54 +01:00
ansible-middleware-core
e866d1f4e4 Bump version to 2.0.3 2024-01-17 08:50:31 +00:00
ansible-middleware-core
2985f808ea Update changelog for release 2.0.2
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2024-01-17 08:50:24 +00:00
Guido Grazioli
30309582f3
Update README.md 2024-01-16 09:17:47 +01:00
Guido Grazioli
40229631e6
Merge pull request #150 from world-direct/fix/149
keycloak_quarkus: allow ports <1024 (e.g. :443) in systemd unit
2024-01-16 09:04:54 +01:00
Helmut Wolf
8adc018cb3 fix/#149: keycloak_quarkus: Allow ports <1024 (e.g., :443) 2024-01-16 08:33:34 +01:00
Guido Grazioli
053d0f9873
Merge pull request #152 from world-direct/fix/151
keycloak_quarkus: allow configuration of `hostname-strict-backchannel`
2024-01-16 00:42:12 +01:00
Guido Grazioli
eb80ed0bd4
Merge pull request #148 from world-direct/feature/rhbk_mssql_driver
keycloak_quarkus: Add support for sqlserver jdbc driver
2024-01-16 00:41:47 +01:00
Guido Grazioli
d138b4b2ff
Merge pull request #145 from world-direct/feature/keycloak_quarkus_systemd
keycloak_quarkus: systemd restart behavior
2024-01-16 00:41:35 +01:00
Helmut Wolf
922e4c10f5 #145 - CR changes 2024-01-15 14:40:46 +01:00
Guido Grazioli
313bd8452a
Merge pull request #154 from world-direct/fix/#153
fix/#153: keycloak_quarkus: Use `keycloak_quarkus_java_opts`
2024-01-15 09:57:34 +01:00
Helmut Wolf
b1b31427d5 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 <https://stackoverflow.com/a/26727332>:

> java -Xmx1G -XX:+PrintFlagsFinal -Xmx2G 2>/dev/null | grep MaxHeapSize
2024-01-10 16:30:02 +01:00
Helmut Wolf
b057f0297a fix/#151: keycloak_quarkus: allow configuration of hostname-strict-backchannel 2024-01-09 08:46:11 +01:00
Helmut Wolf
bfd9db6703 fix/147: keycloak_quarkus: RBKC: Add support for sqlserver jdbc driver 2024-01-08 17:51:11 +01:00
Helmut Wolf
1d5ce87c16 keycloak_quarkus: Remove legacy (?) keycloak_management_url 2023-12-19 09:55:02 +01:00
Helmut Wolf
83bcb6712a keycloak_quarkus: add systemd control options
* keycloak_quarkus_service_restart_always
* keycloak_quarkus_service_restart_on_failure
* keycloak_quarkus_service_restartsec
2023-12-19 09:30:30 +01:00
Guido Grazioli
dab388d744
Merge pull request #142 from RanabirChakraborty/AMW-170
AMW-170 Ansible Hub links for rhbk are broken
2023-12-12 15:32:00 +01:00
Ranabir Chakraborty
ed6dbd60fb AMW-170 Ansible Hub links for rhbk are broken 2023-12-11 22:12:39 +05:30
ansible-middleware-core
db19fd5d19 Bump version to 2.0.2 2023-12-07 14:30:27 +00:00
ansible-middleware-core
473fb212c3 Update changelog for release 2.0.1
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2023-12-07 14:30:17 +00:00
Guido Grazioli
98b82ccb4f ci: runner playbook no keypair 2023-12-07 11:15:12 +01:00
Guido Grazioli
0fbf454279 ci: test alternate certs dir 2023-12-07 11:00:28 +01:00
Guido Grazioli
d469d5df8b ci: downstream update sample playbooks 2023-12-06 18:52:46 +01:00
Guido Grazioli
a23bf4c540 ci: downstream use correct version 2023-12-06 18:24:29 +01:00
Guido Grazioli
ac0b421456 downstream: fix rhbk install path 2023-12-06 16:34:55 +01:00
Guido Grazioli
5b8fcb67dc ci: update sample quarkus playbook 2023-12-06 16:03:37 +01:00
Guido Grazioli
acdee7fa63 ci: downstream arg specs for realm role 2023-12-06 15:40:28 +01:00
Guido Grazioli
86576de6e8
Merge pull request #141 from guidograzioli/rhbk_arg_specs
downstream: add rhbk bits
2023-12-06 10:16:05 +01:00
Guido Grazioli
89944a6cd1 downstream: add rhbk bits 2023-12-06 09:57:33 +01:00
Guido Grazioli
33e6d428b5
Merge pull request #140 from guidograzioli/molecule_jbcs_to_nginx
use nginx instead of jbcs for https_revproxy test
2023-12-05 20:09:08 +01:00
Guido Grazioli
f365351abf use nginx instead of jbcs for https_revproxy test 2023-12-05 19:53:26 +01:00
Guido Grazioli
75899dfa77
Merge pull request #139 from guidograzioli/128_hostname_strict
keycloak_quarkus: add hostname-strict parameter
2023-12-05 12:44:02 +01:00
Guido Grazioli
593c4df861 keycloak_quarkus: add hostname-strict parameter 2023-12-05 10:48:48 +01:00
Guido Grazioli
4a72e3818c
Merge pull request #138 from guidograzioli/fix_keycloak_23_booleans
Update template to lowercase booleans
2023-12-05 10:39:38 +01:00
Guido Grazioli
72ca9f5dfa switch pull_req_target to pull_req 2023-12-05 10:26:20 +01:00
Guido Grazioli
842e61c43e Update template to lowercase booleans 2023-12-05 10:13:12 +01:00
Guido Grazioli
1728b20cd3
Merge pull request #133 from Footur/update-keycloak
Update Keycloak to version 23.0.1
2023-12-01 14:11:04 +01:00
Footur
c01ffed113
Merge branch 'ansible-middleware:main' into update-keycloak 2023-12-01 14:02:45 +01:00
Guido Grazioli
fea7ae0c6f
Merge pull request #134 from guidograzioli/linter_yaml_2
Linter yaml 2
2023-12-01 12:42:10 +01:00
Guido Grazioli
94530640c1 update wf 2023-12-01 12:37:20 +01:00
Guido Grazioli
d6f020ab44 linter fixes 2023-12-01 12:36:20 +01:00
Footur
55c02d7fc5 Update Keycloak to version 23.0.1 2023-12-01 10:34:04 +01:00
Guido Grazioli
5e8e8c67e8
Merge pull request #132 from saadsb20/patch-1
Add prefix check for keycloak_quarkus_http_relative_path
2023-11-30 12:52:18 +01:00
Saâd Bouryaln
88935abb62
Validate relative path
validate the relative path ... must begin with /
2023-11-30 12:26:22 +01:00
Saâd Bouryaln
3a1d9099a7
reverte change 2023-11-30 12:01:49 +01:00
Saâd Bouryaln
a439ccab5e
fix health_url 2023-11-29 15:36:00 +01:00
ansible-middleware-core
e086ee8d29 Bump version to 2.0.1 2023-11-20 17:10:52 +00:00
ansible-middleware-core
2841c7a951 Update changelog for release 2.0.0
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2023-11-20 17:10:43 +00:00
Guido Grazioli
d947e85745
Merge pull request #129 from JMuff22/patch-1
Update admin password variable in keycloak_quarkus.yml
2023-11-17 16:55:35 +01:00
Jake Muff
143084d726
Update admin password variable in keycloak_quarkus.yml 2023-11-16 10:19:47 +02:00
Guido Grazioli
23bda1b4c5
Merge pull request #127 from RanabirChakraborty/AMWSUP-17
AMWSUP-17 keycloak Ansible Hub documentation link broken
2023-11-13 18:27:55 +01:00
Guido Grazioli
efc3e547fe ci: https_revproxy molecule verify step 2023-11-13 18:24:06 +01:00
Guido Grazioli
8af5d6e556 ci: https_revproxy molecule verify step 2023-11-13 18:10:40 +01:00
Guido Grazioli
a0f6a4931f ci: https_revproxy molecule verify step 2023-11-13 16:47:03 +01:00
Guido Grazioli
49c5071733 ci: fix envvars 2023-11-13 16:38:11 +01:00
Ranabir Chakraborty
7a1eeec6b6 AMWSUP-17 keycloak Ansible Hub documentation link broken 2023-11-13 18:18:52 +05:30
Guido Grazioli
69bd5b6ca8
Merge pull request #119 from guidograzioli/min_ansible_version
Update minimum ansible-core version > 2.14
2023-11-13 11:37:53 +01:00
Guido Grazioli
cee02cfd36
Merge pull request #116 from Footur/keystore
[keycloak_quarkus] Enable config of a key store and trust store
2023-11-13 11:37:36 +01:00
Guido Grazioli
ea086e8a62 ci: add missing header to molecule test 2023-11-13 11:37:18 +01:00
Guido Grazioli
24787e4607
Merge pull request #115 from gionn/114-add-more-configs
Add support for more http-related configs
2023-11-13 11:36:50 +01:00
Giovanni Toraldo
0e510c093a
Set default keycloak_quarkus_http_relative_path as per upstream docs 2023-11-13 10:07:01 +01:00
Giovanni Toraldo
880d70ffb9
enable https_revproxy test 2023-11-07 10:21:05 +01:00
Giovanni Toraldo
c8f968a587
cleanup vars 2023-11-07 10:20:01 +01:00
Giovanni Toraldo
8eb5185287
use relative path to build health url 2023-11-07 10:20:01 +01:00
Giovanni Toraldo
316cde4759
Add support for more http-related configs
* keycloak_quarkus_http_relative_path var now populate http-relative-path config [breaking change]
* http-relative-path defaults to / [breaking change]
* enable configuration of hostname-url and hostname-admin-url
2023-11-07 10:20:01 +01:00
Guido Grazioli
92639e40cb
Merge pull request #124 from jacobdotcosta/issue-57
feat: jboss port offset configuration
2023-11-06 16:03:02 +01:00
A.C
027ac1a78e
Merge branch 'main' into issue-57 2023-11-06 15:10:05 +01:00
Antonio Costa
5543217c6a rebase for changes made in PR 120 2023-11-06 15:02:28 +01:00
Guido Grazioli
61730b981b ddisable new test 2023-11-06 15:02:28 +01:00
Guido Grazioli
03175e283b molecule test for keycloakx with proxy 2023-11-06 15:02:28 +01:00
Footur
62e5380d38 Update Keycloak to version 22.0.5 2023-11-06 15:02:28 +01:00
Antonio Costa
a538828f0d feat: add a destination variable for the log link
docs: argument specs for the keycloak_quarkus_log_target

docs: added parameter to the roles README

fix: role variable is keycloak_log_target and not keycloak_quarkus_log_target
2023-11-06 15:02:25 +01:00
Guido Grazioli
12147b4769 linter 2023-11-06 15:01:39 +01:00
Guido Grazioli
cad87557d6
Merge pull request #121 from guidograzioli/quarkus_rev_proxy_test
internal: molecule test for keycloakx with proxy
2023-11-03 11:16:10 +01:00
Guido Grazioli
363c5d9f9e ddisable new test 2023-11-03 10:58:25 +01:00
Guido Grazioli
19a2013fa8
Merge pull request #122 from Footur/update-keycloak
Update Keycloak to version 22.0.5
2023-11-03 10:56:18 +01:00
Guido Grazioli
b819c98ab3
Merge pull request #120 from jacobdotcosta/issue-79
feat: add a destination variable for the log link
2023-11-03 10:55:21 +01:00
Antonio Costa
9ddd6d7d5e feat: jboss port offset configuration 2023-10-30 09:27:30 +01:00
Footur
6f26fa3da4 Update Keycloak to version 22.0.5 2023-10-27 15:32:15 +02:00
Antonio Costa
6970236201 feat: add a destination variable for the log link
docs: argument specs for the keycloak_quarkus_log_target

docs: added parameter to the roles README

fix: role variable is keycloak_log_target and not keycloak_quarkus_log_target
2023-10-26 09:18:07 +02:00
Guido Grazioli
e5f0a3efe1 molecule test for keycloakx with proxy 2023-10-25 18:51:49 +02:00
Guido Grazioli
41c1306602 linter 2023-10-25 18:20:03 +02:00
Guido Grazioli
c67b301f97
Merge pull request #118 from gionn/fixup-molecule-hera
Do not require hosts edit for running quarkus molecule suite locally
2023-10-16 16:41:07 +02:00
Giovanni Toraldo
d945c51172
apply review suggestions 2023-10-16 15:52:04 +02:00
Guido Grazioli
d6c57a17a8
Merge pull request #117 from Footur/update-keycloak
Update Keycloak to version 22.0.4
2023-10-16 15:29:29 +02:00
Guido Grazioli
bf1cb3695e Update minimum ansible-core version > 2.14 2023-10-16 15:27:24 +02:00
Giovanni Toraldo
307eee771f
Do not require hosts edit for running quarkus molecule suite 2023-10-16 12:59:44 +02:00
Footur
e842462a22 Enable config of a key store and trust store 2023-10-13 16:30:58 +02:00
Footur
0f7bbc7ef9 Update Keycloak to version 22.0.4 2023-10-13 16:24:46 +02:00
ansible-middleware-core
00e6cb6b0e Bump version to 1.3.1 2023-09-25 10:57:25 +00:00
ansible-middleware-core
dded412bd0 Update changelog for release 1.3.0
Signed-off-by: ansible-middleware-core <ansible-middleware-core@redhat.com>
2023-09-25 10:56:54 +00:00
Guido Grazioli
5b70d3db2a
Merge pull request #113 from gionn/fix-port-restart
Fix validation failure upon port configuration change
2023-09-25 11:56:11 +02:00
Giovanni Toraldo
e3ce4bd574
fixup linter 2023-09-23 18:38:49 +02:00
Guido Grazioli
af0dc3c5f1
Merge pull request #112 from Footur/keycloak-update-22.0.3
keycloak_quarkus: Update Keycloak to version 22.0.3
2023-09-22 18:38:53 +02:00
Giovanni Toraldo
f3104285bc
Enforce service restart when needed before service checking 2023-09-22 16:30:16 +02:00
footur
cb25c28bb8 Update Keycloak to version 22.0.3 2023-09-22 15:42:06 +02:00
Guido Grazioli
3bb32ed075 ci: update release wf 2023-09-21 12:33:29 +02:00
Guido Grazioli
80e4df8dce
Merge pull request #111 from gionn/fix-108
Fix admin login redirect when running locally
2023-09-19 19:23:39 +02:00
Giovanni Toraldo
194101f010
add new playbook example for localhost quarkus 2023-09-19 17:14:17 +02:00
Giovanni Toraldo
f0f90b8930
apply review suggestions 2023-09-19 17:05:00 +02:00
Giovanni Toraldo
38ff519624
update arguments 2023-09-19 14:00:15 +02:00
Giovanni Toraldo
9c361c9628
add in README 2023-09-19 13:56:51 +02:00
Giovanni Toraldo
9a46b455f6
Fix admin login redirect when running locally 2023-09-19 13:53:32 +02:00
Guido Grazioli
aa7902b9c3
Merge pull request #110 from guidograzioli/molecule_quarkus_devmod
Add molecule quarkus keycloak in dev-mode test
2023-09-19 12:39:25 +02:00
Guido Grazioli
0f17e09731 add new test to CI 2023-09-19 12:25:38 +02:00
Guido Grazioli
942b5fce0f add molecule quarkus keycloak in dev-mode test 2023-09-19 12:23:34 +02:00
Guido Grazioli
bef20b6a57
Merge pull request #109 from msherman13/feature/msherman/quarkus_none_proxy
keycloak_quarkus: skip proxy config if `keycloak_quarkus_proxy_mode` is `none`
2023-09-19 10:46:24 +02:00
Miles Sherman
d673fcf48a update documentation for change to keycloak_quarkus_proxy_mode handling 2023-09-18 17:21:45 +00:00
Miles Sherman
b72460e464 quarkus role: do not populate proxy to config if keycloak_quarkus_proxy_mode is undefined or set to 'none' 2023-09-18 14:46:56 +00:00
Guido Grazioli
6c65fadf31 Bump version to 1.3.0 2023-08-30 11:13:17 +02:00
Guido Grazioli
d12f62b89d
Merge pull request #106 from schmaxit/main
Run service as `keycloak_service_user`
2023-08-30 11:07:25 +02:00
Guido Grazioli
7bb9647d0d update systemd unit to use standalone.sh directly 2023-08-30 10:58:37 +02:00
Guido Grazioli
0199e554b5 overridexml test uses runas feature 2023-08-30 10:16:41 +02:00
Massimo Schiavon
276444ce0e
Add default for keycloak_service_runas 2023-08-29 22:02:18 +02:00
Massimo Schiavon
40c015d3e1
always create pidfile folder
add keycloak_service_runas feature flag
fix previous installs permissions
2023-08-29 21:41:38 +02:00
github-actions
df7fab8f41 Bump version to 1.2.9 2023-08-28 15:56:38 +00:00
github-actions
6330f08b28 Update changelog for release 1.2.8
Signed-off-by: github-actions <ggraziol@redhat.com>
2023-08-28 15:55:52 +00:00
Guido Grazioli
5c8d7d9554 ci: update release workflow 2023-08-28 17:45:52 +02:00
Guido Grazioli
2513ac2c43
Merge pull request #107 from Footur/keycloak-update-22.0.1
Update Keycloak to version 22.0.1
2023-08-28 08:59:53 +02:00
footur
6e6bf2ff71 Fix JRE version in README 2023-08-27 21:57:25 +02:00
Guido Grazioli
11621516e3 update workflows 2023-08-25 11:40:27 +02:00
footur
7c05ee5239 Update Keycloak to version 22.0.1 2023-08-25 11:38:45 +02:00
Guido Grazioli
5251826477 ci: update workflows 2023-08-24 13:57:38 +02:00
Guido Grazioli
0783000849 ci: update workflows 2023-08-24 13:53:22 +02:00
Guido Grazioli
ca2dbe78c2 ci: update workflows 2023-08-24 13:46:50 +02:00
Guido Grazioli
52d9286ea3 ci: update workflows 2023-08-24 13:20:49 +02:00
Massimo Schiavon
c8ebbe72d2
change default pidfile location
Signed-off-by: Massimo Schiavon <schmaxit@users.noreply.github.com>
2023-08-09 09:31:47 +02:00
Massimo Schiavon
91ec411699
create pidfile folder if needed 2023-08-08 17:49:43 +02:00
Massimo Schiavon
07b1c514bb
Add User and Group directives in systemd unit file 2023-08-08 16:52:23 +02:00
Guido Grazioli
345c50fb85
Merge pull request #105 from JoelKle/JoelKle-patch-1
Update bindep.txt package python3-devel to support RHEL9
2023-08-08 15:30:30 +02:00
Joel
db0aafd465
Update bindep.txt to support RHEL9
On RHEL9 the rpm package `python39-devel` doesn't exists. The real name is `python3-devel`.
2023-08-08 11:05:25 +02:00
Guido Grazioli
b950cdb8b4
Merge pull request #103 from guidograzioli/quarkus_java_17
keycloak_quarkus: set openjdk 17 as default
2023-07-31 10:48:26 +02:00
Guido Grazioli
5b01123846 fix verify for molecule default scenario 2023-07-31 10:39:47 +02:00
Guido Grazioli
84d6e7baca set java-17 for keycloak_quarkus 2023-07-31 10:29:28 +02:00
Guido Grazioli
ea735ea79e
Merge pull request #100 from Footur/keycloak-update-22.0.0
Update keycloak_quarkus to Keycloak version 22.0.0
2023-07-31 09:50:38 +02:00
Guido Grazioli
9db1cbd564
Merge pull request #91 from schmaxit/main
Undefine `keycloak_db_valid_conn_sql` default
2023-07-31 09:22:01 +02:00
Guido Grazioli
7933592725
Revert README.md 2023-07-31 09:19:47 +02:00
Guido Grazioli
3170af8b2b
Merge pull request #102 from guidograzioli/bugzilla_2224411
fix_java_11_tzdata
2023-07-31 09:17:34 +02:00
Guido Grazioli
f400a5bbf8 fix_java_11_tzdata 2023-07-31 09:01:54 +02:00
Guido Grazioli
5385fbb8e9 ci: update molecule 2023-07-31 08:40:17 +02:00
Guido Grazioli
7fea211639 ci: update molecule 2023-07-31 08:38:36 +02:00
Guido Grazioli
8738240a24 docs: add missing param in defaults comment 2023-07-28 09:57:37 +02:00
footur
f195d164d1 Enable Ansible verbosity in the CI test 2023-07-14 13:21:27 +02:00
footur
7c4d420fea Update Keycloak to version 22.0.0 2023-07-14 11:36:54 +02:00
Massimo Schiavon
d45071bf58
Merge branch 'ansible-middleware:main' into main 2023-07-03 09:54:47 +02:00
Guido Grazioli
10876ba615
Merge pull request #99 from Footur/update-keycloak
Update the Keycloakx version in the README
2023-06-23 15:20:36 +02:00
Guido Grazioli
f3815403c8
Merge pull request #98 from world-direct/fix/missing_if
Fix #97 - proper checks for keycloak_jgroups_subnet
2023-06-23 15:18:20 +02:00
Footur
18d686b43a
Merge branch 'ansible-middleware:main' into update-keycloak 2023-06-23 12:36:16 +02:00
footur
26a9249d07 Update the Keycloakx version in the README 2023-06-23 12:32:35 +02:00
Helmut Wolf
fae3079751 Fix #97 - proper checks for keycloak_jgroups_subnet 2023-06-23 11:40:15 +02:00
Guido Grazioli
a82e654cc4 Bump to 1.2.8 2023-06-19 17:26:15 +02:00
github-actions
cebec9c717 Update changelog for release 1.2.7 2023-06-19 15:23:06 +00:00
Guido Grazioli
ad59cd8cb3
Merge pull request #95 from guidograzioli/aap_11169
add certified collection notice
2023-06-19 17:05:12 +02:00
Guido Grazioli
926353f395 add certified collection notice 2023-06-19 16:41:35 +02:00
Guido Grazioli
fed86ac0c3
Merge pull request #92 from Footur/update-keycloak
Update keycloakx to v21.1.1
2023-06-19 11:15:16 +02:00
footur
5f1f8b5762 [CI] Use ansible-lint in v6.17.0 2023-06-17 13:16:10 +02:00
Footur
bab3069712
Merge branch 'ansible-middleware:main' into update-keycloak 2023-06-16 10:20:56 +02:00
footur
fc6e00974d Define the varbosity of Ansible in Molecule 2023-06-16 10:19:31 +02:00
footur
83525dbed0 Update the Keycloakx version in Molecule 2023-06-16 10:15:59 +02:00
Guido Grazioli
7ec695ee15 Fix wrong task message 2023-06-10 19:27:48 +02:00
Guido Grazioli
14e7b402b7 fix typo in templates 2023-06-10 18:37:58 +02:00
Guido Grazioli
832432b86c
Merge pull request #93 from guidograzioli/override_jgroups_subnet_match
Allow to override jgroups subnet
2023-06-10 16:47:36 +02:00
Guido Grazioli
8f697f6a53 Bump to 1.2.7 2023-06-10 16:45:13 +02:00
Guido Grazioli
1dd579a6d1 Allow to override jgroups subnet 2023-06-10 16:31:19 +02:00
footur
3340428194 Remove the "--auto-build" flag – it's deprecated
Signed-off-by: footur <3769085+Footur@users.noreply.github.com>
2023-06-10 15:18:31 +02:00
footur
18e60daa93 Update Keycloakx to v21.1.1
Signed-off-by: footur <3769085+Footur@users.noreply.github.com>
2023-06-10 15:16:58 +02:00
Massimo Schiavon
874215a592
remove empty string default for keycloak_db_valid_conn_sql
rely on defaults set in keycloak_jdbc dict
2023-06-09 10:51:13 +02:00
github-actions
97bea7ba39 Update changelog for release 1.2.6 2023-06-07 12:29:15 +00:00
Guido Grazioli
e99a0db174 Add missing type conversion in templates 2023-06-07 12:25:58 +02:00
Guido Grazioli
3b03c54fed
Merge pull request #90 from guidograzioli/background-validation-millis
handle WFLYCTL0117 when validation_millis is 0
2023-06-07 11:56:55 +02:00
Guido Grazioli
ced4ce7828 handle WFLYCTL0117 when validation_millis is 0 2023-06-07 11:56:12 +02:00
Guido Grazioli
6986190159 Bumo to v1.2.6 2023-06-01 10:27:46 +02:00
Guido Grazioli
db480d0bc9
Merge pull request #88 from world-direct/feature/improve_service_restart_behavior
Improve service restart behavior configuration
2023-06-01 10:18:26 +02:00
Helmut Wolf
bc4cb5c52a Introduce keycloak_service_restart_always alongside keycloak_service_restart_on_failure 2023-05-31 20:29:24 +02:00
Guido Grazioli
8f042d3e29
Merge pull request #89 from schmaxit/main
Change xa_datasource_class value for mariadb jdbc configuration
2023-05-31 17:24:53 +02:00
Guido Grazioli
24eaacc1ac
Merge pull request #87 from world-direct/feature/profiles
Keycloak: add feature enabling/disabling
2023-05-31 17:19:08 +02:00
Helmut Wolf
623db426e0 Keycloak: add feature enabling/disabling 2023-05-31 16:41:57 +02:00
Massimo Schiavon
b77c166945
change xa_datasource_class for mariadb jdbc configuration 2023-05-31 11:12:24 +02:00
github-actions
b7eef6a720 Update changelog for release 1.2.5 2023-05-26 21:00:15 +00:00
Guido Grazioli
203e6c06ac
Merge pull request #86 from guidograzioli/admin_url
Allow to configure administration endpoint URL
2023-05-26 19:46:59 +02:00
Guido Grazioli
aaae1d1129 Allow to configure admin_url 2023-05-26 16:31:13 +02:00
Guido Grazioli
cca20a067d
Merge pull request #85 from guidograzioli/datasource_validation
Add configuration for database connection pool validation
2023-05-26 16:09:51 +02:00
Guido Grazioli
2be35f9a67 typo in readme 2023-05-26 14:28:52 +02:00
Guido Grazioli
19f1750a33 Add db pool validation configuration 2023-05-25 11:47:19 +02:00
Guido Grazioli
c3d8bbc94e
Merge pull request #84 from guidograzioli/hostname_spi
Allow to force backend URLs to frontend URLs
2023-05-25 11:34:37 +02:00
Guido Grazioli
c4b4be3c3b add variable for force_frontend_url 2023-05-25 11:10:18 +02:00
Guido Grazioli
98e1633c43 ci: new linter rules take 2 2023-05-22 16:24:28 +02:00
Guido Grazioli
fd375a141d ci: update linter settings, fix new linter issues 2023-05-22 16:12:25 +02:00
Guido Grazioli
0cf7b3ac49
Merge pull request #81 from world-direct/fix/80
Close #80 - introduce systemd restart behavior
2023-05-22 15:41:30 +02:00
Helmut Wolf
370d424b24 Close #80 - introduce systemd restart behavior 2023-05-22 11:30:11 +02:00
Guido Grazioli
01fd2cc4fd Bump to 1.2.5 2023-05-09 16:44:16 +02:00
github-actions
7471e07921 Update changelog for release 1.2.4 2023-05-09 13:49:15 +00:00
Guido Grazioli
e8e0f6718b
Merge pull request #78 from world-direct/fix/74
Close #74 - add `sqlserver` support to keycloak role
2023-05-09 15:31:01 +02:00
Guido Grazioli
e4811221be ci: fix release wf, bump to 1.2.4 2023-05-09 15:25:41 +02:00
Guido Grazioli
6cb4aac556
Merge pull request #77 from world-direct/fix/76
Close #76 - Keycloak role: fix deprecation warning for `ipaddr`
2023-05-09 15:14:07 +02:00
Helmut Wolf
aad373a8e9 Close #74 - add sqlserver support to keycloak role 2023-05-09 13:14:42 +02:00
Helmut Wolf
fd0a4e4492 Close #76 - Keycloak role: fix deprecation warning for ipaddr 2023-05-09 11:45:25 +02:00
Guido Grazioli
706677910b ci: update apt before installing hub 2023-05-05 11:07:42 +02:00
Guido Grazioli
a3bffe9401 Bump to 1.2.3 2023-05-03 15:23:46 +02:00
Guido Grazioli
f566917bc2 ci: rename galaxy tag 2023-05-03 08:54:20 +02:00
Guido Grazioli
44ad3b8e6d add galaxy tag 2023-05-02 18:05:12 +02:00
Guido Grazioli
1a450ea1d7 ci: add galaxy tags 2023-05-02 17:00:26 +02:00
Guido Grazioli
b0a01a8e46
Merge pull request #73 from jonathanspw/main
add configurability for XA transactions
2023-04-24 16:48:20 +02:00
Jonathan Wright
020bc86955
document keycloak_quarkus_transaction_xa_enabled 2023-04-24 08:52:36 -05:00
Jonathan Wright
d72d46c945
fix typo 2023-04-24 08:50:16 -05:00
Jonathan Wright
c7d2bdcee3 add configurability for XA transactions 2023-04-21 15:12:59 -05:00
Guido Grazioli
43d978370d
bump to 1.2.2 2023-04-14 15:50:48 +02:00
Guido Grazioli
3d37def38d
Merge pull request #71 from guidograzioli/downstream_offline_patching_fix
Fix undefined facts when offline patching sso
2023-04-14 15:31:13 +02:00
Guido Grazioli
8d16e241c1
fix undefined facts when offline patching sso 2023-04-14 14:58:40 +02:00
Guido Grazioli
6ac0c18842
fix: drop xml element not available in 7.6 2023-04-12 11:12:32 +02:00
Guido Grazioli
6334daf244
ci: fix typo and indent for TCPPING discovery 2023-04-12 10:59:21 +02:00
github-actions
87ad97d57f Update changelog for release 1.2.1 2023-04-11 07:07:07 +00:00
Guido Grazioli
242b1cea0a
version bump to 1.2.1 2023-04-01 12:20:29 +02:00
Guido Grazioli
c0b72b6890
Merge pull request #69 from guidograzioli/keycloak_realm_attrs
Pass attributes to realm clients
2023-04-01 12:20:06 +02:00
Guido Grazioli
1cfa229a5f
Pass attributes to realm clients 2023-04-01 11:45:40 +02:00
Guido Grazioli
f013a99832
Merge pull request #68 from guidograzioli/ha_internal_infinispan
Allow to setup keycloak HA cluster without remote cache store
2023-04-01 10:34:00 +02:00
Guido Grazioli
6bfe046f5e
fix templates path 2023-04-01 10:13:01 +02:00
Guido Grazioli
526f64e5eb
standalone ha without remote store 2023-04-01 10:06:03 +02:00
Guido Grazioli
a2c17f545e
docs: downstream hide build status 2023-03-29 10:32:14 +02:00
Guido Grazioli
40c29d07b8
ci: update main README.md 2023-03-24 15:19:28 +01:00
Guido Grazioli
91a18bf571
ci: downstream test offline/online handling 2023-03-17 11:43:34 +01:00
Guido Grazioli
ecb6cbb9bf
ci: downstream test asset management 2023-03-17 11:25:40 +01:00
156 changed files with 8586 additions and 1593 deletions

View file

@ -21,19 +21,23 @@ warn_list:
- experimental
- ignore-errors
- no-handler
- fqcn-builtins
- no-log-password
- jinja[spacing]
- jinja[invalid]
- meta-no-tags
- name[template]
- name[casing]
- fqcn[action]
- schema[meta]
- key-order[task]
- blocked_modules
- run-once[task]
skip_list:
- vars_should_not_be_used
- file_is_small_enough
- file_has_valid_name
- name[template]
- var-naming[no-role-prefix]
use_default_rules: true
parseable: true

View file

@ -5,53 +5,15 @@ on:
branches:
- main
pull_request:
env:
COLORTERM: 'yes'
TERM: 'xterm-256color'
PYTEST_ADDOPTS: '--color=yes'
workflow_dispatch:
schedule:
- cron: '15 6 * * *'
jobs:
ci:
runs-on: ubuntu-latest
strategy:
matrix:
python_version: ["3.9"]
steps:
- name: Check out code
uses: actions/checkout@v2
with:
path: ansible_collections/middleware_automation/keycloak
- name: Set up Python ${{ matrix.python_version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python_version }}
- name: Install yamllint, ansible and molecule
run: |
python -m pip install --upgrade pip
pip install yamllint 'molecule[docker]~=3.5.2' ansible-core flake8 ansible-lint voluptuous
pip install -r ansible_collections/middleware_automation/keycloak/requirements.txt
- name: Create default collection path
run: |
mkdir -p /home/runner/.ansible/
ln -s /home/runner/work/keycloak/keycloak /home/runner/.ansible/collections
- name: Install ansible-lint custom rules
uses: actions/checkout@v2
with:
repository: ansible-middleware/ansible-lint-custom-rules
path: ansible_collections/ansible-lint-custom-rules/
- name: Run sanity tests
run: ansible-test sanity -v --color --python ${{ matrix.python_version }} --exclude changelogs/fragments/.gitignore --skip-test symlinks
working-directory: ./ansible_collections/middleware_automation/keycloak
- name: Run molecule test
run: molecule test --all
working-directory: ./ansible_collections/middleware_automation/keycloak
env:
PY_COLORS: '1'
ANSIBLE_FORCE_COLOR: '1'
uses: ansible-middleware/github-actions/.github/workflows/ci.yml@main
secrets: inherit
with:
fqcn: 'middleware_automation/keycloak'
molecule_tests: >-
[ "default", "overridexml", "https_revproxy", "quarkus", "quarkus-devmode", "quarkus_upgrade", "debian", "quarkus_ha" ]

View file

@ -8,55 +8,11 @@ on:
- "[0-9]+.[0-9]+.[0-9]+"
workflow_dispatch:
env:
COLORTERM: 'yes'
TERM: 'xterm-256color'
PYTEST_ADDOPTS: '--color=yes'
jobs:
docs:
runs-on: ubuntu-latest
if: github.repository == 'ansible-middleware/keycloak'
permissions:
actions: write
checks: write
contents: write
deployments: write
packages: write
pages: write
steps:
- name: Check out code
uses: actions/checkout@v2
with:
path: ansible_collections/middleware_automation/keycloak
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install doc dependencies
run: |
python -m pip install --upgrade pip
pip install -r ansible_collections/middleware_automation/keycloak/docs/requirements.txt
pip install -r ansible_collections/middleware_automation/keycloak/requirements.txt
sudo apt install -y sed hub
- name: Create default collection path
run: |
mkdir -p /home/runner/.ansible/
ln -s /home/runner/work/keycloak/keycloak /home/runner/.ansible/collections
- name: Create changelog and documentation
uses: ansible-middleware/collection-docs-action@main
with:
collection_fqcn: middleware_automation.keycloak
collection_repo: ansible-middleware/keycloak
dependencies: false
commit_changelog: false
commit_ghpages: true
changelog_release: false
generate_docs: true
path: ansible_collections/middleware_automation/keycloak
token: ${{ secrets.GITHUB_TOKEN }}
uses: ansible-middleware/github-actions/.github/workflows/docs.yml@main
secrets: inherit
with:
fqcn: 'middleware_automation/keycloak'
collection_fqcn: 'middleware_automation.keycloak'
historical_docs: 'false'

View file

@ -2,96 +2,27 @@
name: Release collection
on:
workflow_dispatch:
inputs:
release_summary:
description: 'Optional release summary for changelogs'
required: false
jobs:
release:
runs-on: ubuntu-latest
if: github.repository == 'ansible-middleware/keycloak'
permissions:
actions: write
checks: write
contents: write
deployments: write
packages: write
pages: write
outputs:
tag_version: ${{ steps.get_version.outputs.TAG_VERSION }}
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
token: ${{ secrets.TRIGGERING_PAT }}
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: "3.x"
- name: Get current version
id: get_version
run: echo "::set-output name=TAG_VERSION::$(grep version galaxy.yml | awk -F'"' '{ print $2 }')"
- name: Check if tag exists
id: check_tag
run: echo "::set-output name=TAG_EXISTS::$(git tag | grep ${{ steps.get_version.outputs.TAG_VERSION }})"
- name: Fail if tag exists
if: ${{ steps.get_version.outputs.TAG_VERSION == steps.check_tag.outputs.TAG_EXISTS }}
uses: actions/github-script@v3
with:
script: |
core.setFailed('Release tag already exists')
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ansible-core antsibull
sudo apt install -y sed hub
- name: Build collection
run: |
ansible-galaxy collection build .
- name: Create changelog and documentation
uses: ansible-middleware/collection-docs-action@main
with:
collection_fqcn: middleware_automation.keycloak
collection_repo: ansible-middleware/keycloak
dependencies: false
commit_changelog: true
commit_ghpages: false
changelog_release: true
generate_docs: false
token: ${{ secrets.GITHUB_TOKEN }}
- name: Publish collection
env:
ANSIBLE_GALAXY_API_KEY: ${{ secrets.ANSIBLE_GALAXY_API_KEY }}
run: |
ansible-galaxy collection publish *.tar.gz --api-key $ANSIBLE_GALAXY_API_KEY
- name: Create release tag
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git tag -a ${{ steps.get_version.outputs.TAG_VERSION }} -m "Release v${{ steps.get_version.outputs.TAG_VERSION }}" || true
git push origin --tags
- name: Publish Release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.get_version.outputs.TAG_VERSION }}
files: "*.tar.gz"
body_path: gh-release.md
uses: ansible-middleware/github-actions/.github/workflows/release.yml@main
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 }}
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

26
.github/workflows/traffic.yml vendored Normal file
View file

@ -0,0 +1,26 @@
name: Collect traffic stats
on:
schedule:
- cron: "51 23 * * 0"
workflow_dispatch:
jobs:
traffic:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ref: "gh-pages"
- 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: "gh-pages"

4
.gitignore vendored
View file

@ -2,6 +2,8 @@
*.zip
.tmp
.cache
.vscode/
__pycache__/
docs/plugins/
docs/roles/
docs/_build/
@ -10,3 +12,5 @@ docs/_build/
*.retry
changelogs/.plugin-cache.yaml
*.pem
*.key
*.p12

View file

@ -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
truthy: disable
octal-values:
forbid-implicit-octal: true
forbid-explicit-octal: true

View file

@ -1,11 +1,314 @@
============================================
middleware_automation.keycloak 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 <https://github.com/ansible-middleware/keycloak/pull/241>`_
v2.4.2
======
Minor Changes
-------------
- New parameter ``keycloak_quarkus_download_path`` `#239 <https://github.com/ansible-middleware/keycloak/pull/239>`_
Bugfixes
--------
- Add wait_for_port number parameter `#237 <https://github.com/ansible-middleware/keycloak/pull/237>`_
v2.4.1
======
Release Summary
---------------
Internal release, documentation or test changes only.
v2.4.0
======
Major Changes
-------------
- Enable by default health check on restart `#234 <https://github.com/ansible-middleware/keycloak/pull/234>`_
- Update minimum ansible-core version > 2.15 `#232 <https://github.com/ansible-middleware/keycloak/pull/232>`_
v2.3.0
======
Major Changes
-------------
- Allow for custom providers hosted on maven repositories `#223 <https://github.com/ansible-middleware/keycloak/pull/223>`_
- Restart handler strategy behaviour `#231 <https://github.com/ansible-middleware/keycloak/pull/231>`_
Minor Changes
-------------
- Add support for policy files `#225 <https://github.com/ansible-middleware/keycloak/pull/225>`_
- Allow to add extra custom env vars in sysconfig file `#229 <https://github.com/ansible-middleware/keycloak/pull/229>`_
- Download from alternate URL with optional http authentication `#220 <https://github.com/ansible-middleware/keycloak/pull/220>`_
- Update Keycloak to version 24.0.4 `#218 <https://github.com/ansible-middleware/keycloak/pull/218>`_
- ``proxy-header`` enhancement `#227 <https://github.com/ansible-middleware/keycloak/pull/227>`_
Bugfixes
--------
- ``kc.sh build`` uses configured jdk `#211 <https://github.com/ansible-middleware/keycloak/pull/211>`_
v2.2.2
======
Minor Changes
-------------
- Copying of key material for TLS configuration `#210 <https://github.com/ansible-middleware/keycloak/pull/210>`_
- Validate certs parameter for JDBC driver downloads `#207 <https://github.com/ansible-middleware/keycloak/pull/207>`_
Bugfixes
--------
- Turn off controller privilege escalation `#209 <https://github.com/ansible-middleware/keycloak/pull/209>`_
v2.2.1
======
Release Summary
---------------
Internal release, documentation or test changes only.
Bugfixes
--------
- JDBC provider: fix clause in argument validation `#204 <https://github.com/ansible-middleware/keycloak/pull/204>`_
v2.2.0
======
Major Changes
-------------
- Support java keystore for configuration of sensitive options `#189 <https://github.com/ansible-middleware/keycloak/pull/189>`_
Minor Changes
-------------
- Add ``wait_for_port`` and ``wait_for_log`` systemd unit logic `#199 <https://github.com/ansible-middleware/keycloak/pull/199>`_
- Customize jdbc driver downloads, optional authentication `#202 <https://github.com/ansible-middleware/keycloak/pull/202>`_
- Keystore-based vault SPI configuration `#196 <https://github.com/ansible-middleware/keycloak/pull/196>`_
- New ``keycloak_quarkus_hostname_strict_https`` parameter `#195 <https://github.com/ansible-middleware/keycloak/pull/195>`_
- Providers config and custom providers `#201 <https://github.com/ansible-middleware/keycloak/pull/201>`_
- Remove administrator credentials from files once keycloak is bootstrapped `#197 <https://github.com/ansible-middleware/keycloak/pull/197>`_
- Update keycloak to 24.0 `#194 <https://github.com/ansible-middleware/keycloak/pull/194>`_
v2.1.2
======
Release Summary
---------------
Internal release, documentation or test changes only.
v2.1.1
======
Minor Changes
-------------
- Add reverse ``proxy_headers`` config, supersedes ``proxy_mode`` `#187 <https://github.com/ansible-middleware/keycloak/pull/187>`_
- Debian/Ubuntu compatibility `#178 <https://github.com/ansible-middleware/keycloak/pull/178>`_
- Use ``keycloak_realm`` as default for sub-entities `#180 <https://github.com/ansible-middleware/keycloak/pull/180>`_
Bugfixes
--------
- Fix permissions on controller-side downloaded artifacts `#184 <https://github.com/ansible-middleware/keycloak/pull/184>`_
- JVM args moved to ``JAVA_OPTS`` envvar (instead of JAVA_OPTS_APPEND) `#186 <https://github.com/ansible-middleware/keycloak/pull/186>`_
- Unrelax configuration file permissions `#191 <https://github.com/ansible-middleware/keycloak/pull/191>`_
- Utilize comment filter for ``ansible_managed`` annotations `#176 <https://github.com/ansible-middleware/keycloak/pull/176>`_
v2.1.0
======
Major Changes
-------------
- Implement infinispan TCPPING discovery protocol `#159 <https://github.com/ansible-middleware/keycloak/pull/159>`_
Minor Changes
-------------
- Set enable-recovery when xa transactions are enabled `#167 <https://github.com/ansible-middleware/keycloak/pull/167>`_
- keycloak_quarkus: Allow configuring log rotate options in quarkus configuration `#161 <https://github.com/ansible-middleware/keycloak/pull/161>`_
- keycloak_quarkus: ``sticky-session`` for infinispan routes `#163 <https://github.com/ansible-middleware/keycloak/pull/163>`_
Breaking Changes / Porting Guide
--------------------------------
- keycloak_quarkus: renamed infinispan host list configuration `#157 <https://github.com/ansible-middleware/keycloak/pull/157>`_
Bugfixes
--------
- keycloak_quarkus: fix custom JAVA_HOME parameter name `#171 <https://github.com/ansible-middleware/keycloak/pull/171>`_
v2.0.2
======
Minor Changes
-------------
- keycloak_quarkus: Add support for sqlserver jdbc driver `#148 <https://github.com/ansible-middleware/keycloak/pull/148>`_
- keycloak_quarkus: allow configuration of ``hostname-strict-backchannel`` `#152 <https://github.com/ansible-middleware/keycloak/pull/152>`_
- keycloak_quarkus: systemd restart behavior `#145 <https://github.com/ansible-middleware/keycloak/pull/145>`_
Bugfixes
--------
- keycloak_quarkus: Use ``keycloak_quarkus_java_opts`` `#154 <https://github.com/ansible-middleware/keycloak/pull/154>`_
- keycloak_quarkus: allow ports <1024 (e.g. :443) in systemd unit `#150 <https://github.com/ansible-middleware/keycloak/pull/150>`_
v2.0.1
======
Minor Changes
-------------
- keycloak_quarkus: add hostname-strict parameter `#139 <https://github.com/ansible-middleware/keycloak/pull/139>`_
- keycloak_quarkus: update to version 23.0.1 `#133 <https://github.com/ansible-middleware/keycloak/pull/133>`_
Bugfixes
--------
- keycloak_quarkus: template requires lowercase boolean values `#138 <https://github.com/ansible-middleware/keycloak/pull/138>`_
v2.0.0
======
Minor Changes
-------------
- Add new parameter for port offset configuration `#124 <https://github.com/ansible-middleware/keycloak/pull/124>`_
- Update Keycloak to version 22.0.5 `#122 <https://github.com/ansible-middleware/keycloak/pull/122>`_
Breaking Changes / Porting Guide
--------------------------------
- Add support for more http-related configs `#115 <https://github.com/ansible-middleware/keycloak/pull/115>`_
- Update minimum ansible-core version > 2.14 `#119 <https://github.com/ansible-middleware/keycloak/pull/119>`_
- keycloak_quarkus: enable config of key store and trust store `#116 <https://github.com/ansible-middleware/keycloak/pull/116>`_
v1.3.0
======
Major Changes
-------------
- Run service as ``keycloak_service_user`` `#106 <https://github.com/ansible-middleware/keycloak/pull/106>`_
Minor Changes
-------------
- keycloak_quarkus: Update Keycloak to version 22.0.3 `#112 <https://github.com/ansible-middleware/keycloak/pull/112>`_
- keycloak_quarkus: fix admin console redirect when running locally `#111 <https://github.com/ansible-middleware/keycloak/pull/111>`_
- keycloak_quarkus: skip proxy config if ``keycloak_quarkus_proxy_mode`` is ``none`` `#109 <https://github.com/ansible-middleware/keycloak/pull/109>`_
Bugfixes
--------
- keycloak_quarkus: fix validation failure upon port configuration change `#113 <https://github.com/ansible-middleware/keycloak/pull/113>`_
v1.2.8
======
Minor Changes
-------------
- keycloak_quarkus: set openjdk 17 as default `#103 <https://github.com/ansible-middleware/keycloak/pull/103>`_
- keycloak_quarkus: update to version 22.0.1 `#107 <https://github.com/ansible-middleware/keycloak/pull/107>`_
Bugfixes
--------
- Fix incorrect checks for ``keycloak_jgroups_subnet`` `#98 <https://github.com/ansible-middleware/keycloak/pull/98>`_
- Undefine ``keycloak_db_valid_conn_sql`` default `#91 <https://github.com/ansible-middleware/keycloak/pull/91>`_
- Update bindep.txt package python3-devel to support RHEL9 `#105 <https://github.com/ansible-middleware/keycloak/pull/105>`_
v1.2.7
======
Minor Changes
-------------
- Allow to override jgroups subnet `#93 <https://github.com/ansible-middleware/keycloak/pull/93>`_
- keycloak-quarkus: update keycloakx to v21.1.1 `#92 <https://github.com/ansible-middleware/keycloak/pull/92>`_
v1.2.6
======
Minor Changes
-------------
- Add profile features enabling/disabling `#87 <https://github.com/ansible-middleware/keycloak/pull/87>`_
- Improve service restart behavior configuration `#88 <https://github.com/ansible-middleware/keycloak/pull/88>`_
- Update default xa_datasource_class value for mariadb jdbc configuration `#89 <https://github.com/ansible-middleware/keycloak/pull/89>`_
Bugfixes
--------
- Handle WFLYCTL0117 when background validation millis is 0 `#90 <https://github.com/ansible-middleware/keycloak/pull/90>`_
v1.2.5
======
Minor Changes
-------------
- Add configuration for database connection pool validation `#85 <https://github.com/ansible-middleware/keycloak/pull/85>`_
- Allow to configure administration endpoint URL `#86 <https://github.com/ansible-middleware/keycloak/pull/86>`_
- Allow to force backend URLs to frontend URLs `#84 <https://github.com/ansible-middleware/keycloak/pull/84>`_
- Introduce systemd unit restart behavior `#81 <https://github.com/ansible-middleware/keycloak/pull/81>`_
v1.2.4
======
Minor Changes
-------------
- Add ``sqlserver`` to keycloak role jdbc configurations `#78 <https://github.com/ansible-middleware/keycloak/pull/78>`_
- Add configurability for XA transactions `#73 <https://github.com/ansible-middleware/keycloak/pull/73>`_
Bugfixes
--------
- Fix deprecation warning for ``ipaddr`` `#77 <https://github.com/ansible-middleware/keycloak/pull/77>`_
- Fix undefined facts when offline patching sso `#71 <https://github.com/ansible-middleware/keycloak/pull/71>`_
v1.2.1
======
Minor Changes
-------------
- Allow to setup keycloak HA cluster without remote cache store `#68 <https://github.com/ansible-middleware/keycloak/pull/68>`_
Bugfixes
--------
- Pass attributes to realm clients `#69 <https://github.com/ansible-middleware/keycloak/pull/69>`_
v1.2.0
======
@ -84,6 +387,11 @@ Minor Changes
v1.0.4
======
Release Summary
---------------
Internal release, documentation or test changes only.
v1.0.3
======
@ -124,7 +432,6 @@ Release Summary
Minor enhancements, bug and documentation fixes.
Major Changes
-------------
@ -142,4 +449,3 @@ Release Summary
---------------
This is the first stable release of the ``middleware_automation.keycloak`` collection.

View file

@ -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.16' 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

View file

@ -1,14 +1,18 @@
# Ansible Collection - middleware_automation.keycloak
<!--start build_status -->
[![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.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.**
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).
<!--end build_status -->
<!--start description -->
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).
<!--end description -->
<!--start requires_ansible-->
## Ansible version compatibility
This collection has been tested against following Ansible versions: **>=2.9.10**.
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.
<!--end requires_ansible-->
@ -16,12 +20,15 @@ Plugins and modules within a collection may be tested with only specific Ansible
## Installation
<!--start galaxy_download -->
### Installing the Collection from Ansible Galaxy
Before using the collection, you need to install it with the Ansible Galaxy CLI:
ansible-galaxy collection install middleware_automation.keycloak
<!--end galaxy_download -->
You can also include it in a `requirements.yml` file and install it via `ansible-galaxy collection install -r requirements.yml`, using the format:
```yaml
@ -33,69 +40,60 @@ 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:
pip install -r requirements.txt
<!--start roles_paths -->
### 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).
* `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).
<!--end roles_paths -->
## Usage
### Install Playbook
* [`playbooks/keycloak.yml`](https://github.com/ansible-middleware/keycloak/blob/main/playbooks/keycloak.yml) installs the upstream(Keycloak) based on the defined variables.
* [`playbooks/rhsso.yml`](https://github.com/ansible-middleware/keycloak/blob/main/playbooks/rhsso.yml) installs Red Hat Single Sign-On(RHSSO) based on defined variables.
<!--start rhbk_playbook -->
* [`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.
For full service configuration details, refer to the [keycloak role README](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak/README.md).
<!--end rhbk_playbook -->
#### Install from controller node (offline)
#### Install from controller node (local source)
Making the keycloak zip archive (or the RHSSO zip archive), available to the playbook repository root directory, and setting `keycloak_offline_install` to `True`, allows to skip
the download tasks. The local path for the archive matches the downloaded archive path, so it is also used as a cache when multiple hosts are provisioned in a cluster.
Making the keycloak zip archive available to the playbook working directory, and setting `keycloak_offline_install` to `true`, allows to skip
the download tasks. The local path for the archive does match the downloaded archive path, so that it is also used as a cache when multiple hosts are provisioned in a cluster.
```yaml
keycloak_offline_install: True
keycloak_offline_install: true
```
And depending on `keycloak_rhsso_enable`:
* `True`: install RHSSO using file rh-sso-x.y.z-server-dist.zip
* `False`: install keycloak using file keycloak-x.y.zip
<!--start rhn_credentials -->
<!--end rhn_credentials -->
#### Install from alternate sources (like corporate Nexus, artifactory, proxy, etc)
For RHSSO:
```yaml
sso_download_url: "https://<internal-nexus.private.net>/<path>/<to>/rh-sso-x.y.z-server-dist.zip"
```
For keycloak:
```yaml
keycloak_download_url: "https://<internal-nexus.private.net>/<path>/<to>/keycloak-x.y.zip"
```
It is possible to perform downloads from alternate sources, using the `keycloak_download_url` variable; make sure the final downloaded filename matches with the source filename (ie. keycloak-legacy-x.y.zip or rh-sso-x.y.z-server-dist.zip).
### Example installation command
Execute the following command from the source root directory
Execute the following command from the source root directory
```
ansible-playbook -i <ansible_hosts> -e @rhn-creds.yml playbooks/keycloak.yml -e keycloak_admin_password=<changeme>
```
```
- `keycloak_admin_password` Password for the administration console user account.
- `ansible_hosts` is the inventory, below is an example inventory for deploying to localhost
@ -105,14 +103,16 @@ ansible-playbook -i <ansible_hosts> -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.
## Configuration
### Config Playbook
<!--start rhbk_realm_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).
<!--end rhbk_realm_playbook -->
### Example configuration command
@ -130,16 +130,17 @@ ansible-playbook -i <ansible_hosts> playbooks/keycloak_realm.yml -e keycloak_adm
[keycloak]
localhost ansible_connection=local
```
<!--start rhbk_realm_readme -->
For full configuration details, refer to the [keycloak_realm role README](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak_realm/README.md).
<!--end rhbk_realm_readme -->
## Support
<!--start support -->
<!--end support -->
Keycloak collection v1.0.0 is a Beta release and for [Technical Preview](https://access.redhat.com/support/offerings/techpreview). If you have any issues or questions related to collection, please don't hesitate to contact us on Ansible-middleware-core@redhat.com or open an issue on https://github.com/ansible-middleware/keycloak/issues
## License
Apache License v2.0 or later
<!--start license -->
See [LICENSE](LICENSE) to view the full text.
<!--end license -->

View file

@ -1,7 +1,9 @@
python39-devel [platform:rpm compile]
git-lfs [platform:rpm]
python3-netaddr [platform:rpm]
python3-lxml [platform:rpm]
python3-jmespath [platform:rpm]
python3-requests [platform:rpm]
python3-dev [compile platform:dpkg]
python3-devel [compile platform:rpm]
python39-devel [compile platform:centos-8 platform:rhel-8]
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]

View file

@ -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:
@ -167,3 +171,445 @@ releases:
- 63.yaml
- 64.yaml
release_date: '2023-03-16'
1.2.1:
changes:
bugfixes:
- 'Pass attributes to realm clients `#69 <https://github.com/ansible-middleware/keycloak/pull/69>`_
'
minor_changes:
- 'Allow to setup keycloak HA cluster without remote cache store `#68 <https://github.com/ansible-middleware/keycloak/pull/68>`_
'
fragments:
- 68.yaml
- 69.yaml
release_date: '2023-04-11'
1.2.4:
changes:
bugfixes:
- 'Fix deprecation warning for ``ipaddr`` `#77 <https://github.com/ansible-middleware/keycloak/pull/77>`_
'
- 'Fix undefined facts when offline patching sso `#71 <https://github.com/ansible-middleware/keycloak/pull/71>`_
'
minor_changes:
- 'Add ``sqlserver`` to keycloak role jdbc configurations `#78 <https://github.com/ansible-middleware/keycloak/pull/78>`_
'
- 'Add configurability for XA transactions `#73 <https://github.com/ansible-middleware/keycloak/pull/73>`_
'
fragments:
- 71.yaml
- 73.yaml
- 77.yaml
- 78.yaml
release_date: '2023-05-09'
1.2.5:
changes:
minor_changes:
- 'Add configuration for database connection pool validation `#85 <https://github.com/ansible-middleware/keycloak/pull/85>`_
'
- 'Allow to configure administration endpoint URL `#86 <https://github.com/ansible-middleware/keycloak/pull/86>`_
'
- 'Allow to force backend URLs to frontend URLs `#84 <https://github.com/ansible-middleware/keycloak/pull/84>`_
'
- 'Introduce systemd unit restart behavior `#81 <https://github.com/ansible-middleware/keycloak/pull/81>`_
'
fragments:
- 81.yaml
- 84.yaml
- 85.yaml
- 86.yaml
release_date: '2023-05-26'
1.2.6:
changes:
bugfixes:
- 'Handle WFLYCTL0117 when background validation millis is 0 `#90 <https://github.com/ansible-middleware/keycloak/pull/90>`_
'
minor_changes:
- 'Add profile features enabling/disabling `#87 <https://github.com/ansible-middleware/keycloak/pull/87>`_
'
- 'Improve service restart behavior configuration `#88 <https://github.com/ansible-middleware/keycloak/pull/88>`_
'
- 'Update default xa_datasource_class value for mariadb jdbc configuration `#89
<https://github.com/ansible-middleware/keycloak/pull/89>`_
'
fragments:
- 87.yaml
- 88.yaml
- 89.yaml
- 90.yaml
release_date: '2023-06-07'
1.2.7:
changes:
minor_changes:
- 'Allow to override jgroups subnet `#93 <https://github.com/ansible-middleware/keycloak/pull/93>`_
'
- 'keycloak-quarkus: update keycloakx to v21.1.1 `#92 <https://github.com/ansible-middleware/keycloak/pull/92>`_
'
fragments:
- 92.yaml
- 93.yaml
release_date: '2023-06-19'
1.2.8:
changes:
bugfixes:
- 'Fix incorrect checks for ``keycloak_jgroups_subnet`` `#98 <https://github.com/ansible-middleware/keycloak/pull/98>`_
'
- 'Undefine ``keycloak_db_valid_conn_sql`` default `#91 <https://github.com/ansible-middleware/keycloak/pull/91>`_
'
- 'Update bindep.txt package python3-devel to support RHEL9 `#105 <https://github.com/ansible-middleware/keycloak/pull/105>`_
'
minor_changes:
- 'keycloak_quarkus: set openjdk 17 as default `#103 <https://github.com/ansible-middleware/keycloak/pull/103>`_
'
- 'keycloak_quarkus: update to version 22.0.1 `#107 <https://github.com/ansible-middleware/keycloak/pull/107>`_
'
fragments:
- 103.yaml
- 105.yaml
- 107.yaml
- 91.yaml
- 98.yaml
release_date: '2023-08-28'
1.3.0:
changes:
bugfixes:
- 'keycloak_quarkus: fix validation failure upon port configuration change `#113
<https://github.com/ansible-middleware/keycloak/pull/113>`_
'
major_changes:
- 'Run service as ``keycloak_service_user`` `#106 <https://github.com/ansible-middleware/keycloak/pull/106>`_
'
minor_changes:
- 'keycloak_quarkus: Update Keycloak to version 22.0.3 `#112 <https://github.com/ansible-middleware/keycloak/pull/112>`_
'
- 'keycloak_quarkus: fix admin console redirect when running locally `#111 <https://github.com/ansible-middleware/keycloak/pull/111>`_
'
- 'keycloak_quarkus: skip proxy config if ``keycloak_quarkus_proxy_mode`` is
``none`` `#109 <https://github.com/ansible-middleware/keycloak/pull/109>`_
'
fragments:
- 106.yaml
- 109.yaml
- 111.yaml
- 112.yaml
- 113.yaml
release_date: '2023-09-25'
2.0.0:
changes:
breaking_changes:
- 'Add support for more http-related configs `#115 <https://github.com/ansible-middleware/keycloak/pull/115>`_
'
- 'Update minimum ansible-core version > 2.14 `#119 <https://github.com/ansible-middleware/keycloak/pull/119>`_
'
- 'keycloak_quarkus: enable config of key store and trust store `#116 <https://github.com/ansible-middleware/keycloak/pull/116>`_
'
minor_changes:
- 'Add new parameter for port offset configuration `#124 <https://github.com/ansible-middleware/keycloak/pull/124>`_
'
- 'Update Keycloak to version 22.0.5 `#122 <https://github.com/ansible-middleware/keycloak/pull/122>`_
'
fragments:
- 115.yaml
- 116.yaml
- 119.yaml
- 122.yaml
- 124.yaml
release_date: '2023-11-20'
2.0.1:
changes:
bugfixes:
- 'keycloak_quarkus: template requires lowercase boolean values `#138 <https://github.com/ansible-middleware/keycloak/pull/138>`_
'
minor_changes:
- 'keycloak_quarkus: add hostname-strict parameter `#139 <https://github.com/ansible-middleware/keycloak/pull/139>`_
'
- 'keycloak_quarkus: update to version 23.0.1 `#133 <https://github.com/ansible-middleware/keycloak/pull/133>`_
'
fragments:
- 133.yaml
- 138.yaml
- 139.yaml
release_date: '2023-12-07'
2.0.2:
changes:
bugfixes:
- 'keycloak_quarkus: Use ``keycloak_quarkus_java_opts`` `#154 <https://github.com/ansible-middleware/keycloak/pull/154>`_
'
- 'keycloak_quarkus: allow ports <1024 (e.g. :443) in systemd unit `#150 <https://github.com/ansible-middleware/keycloak/pull/150>`_
'
minor_changes:
- 'keycloak_quarkus: Add support for sqlserver jdbc driver `#148 <https://github.com/ansible-middleware/keycloak/pull/148>`_
'
- 'keycloak_quarkus: allow configuration of ``hostname-strict-backchannel``
`#152 <https://github.com/ansible-middleware/keycloak/pull/152>`_
'
- 'keycloak_quarkus: systemd restart behavior `#145 <https://github.com/ansible-middleware/keycloak/pull/145>`_
'
fragments:
- 145.yaml
- 148.yaml
- 150.yaml
- 152.yaml
- 154.yaml
release_date: '2024-01-17'
2.1.0:
changes:
breaking_changes:
- 'keycloak_quarkus: renamed infinispan host list configuration `#157 <https://github.com/ansible-middleware/keycloak/pull/157>`_
'
bugfixes:
- 'keycloak_quarkus: fix custom JAVA_HOME parameter name `#171 <https://github.com/ansible-middleware/keycloak/pull/171>`_
'
major_changes:
- 'Implement infinispan TCPPING discovery protocol `#159 <https://github.com/ansible-middleware/keycloak/pull/159>`_
'
minor_changes:
- 'Set enable-recovery when xa transactions are enabled `#167 <https://github.com/ansible-middleware/keycloak/pull/167>`_
'
- 'keycloak_quarkus: Allow configuring log rotate options in quarkus configuration
`#161 <https://github.com/ansible-middleware/keycloak/pull/161>`_
'
- 'keycloak_quarkus: ``sticky-session`` for infinispan routes `#163 <https://github.com/ansible-middleware/keycloak/pull/163>`_
'
fragments:
- 157.yaml
- 159.yaml
- 161.yaml
- 163.yaml
- 167.yaml
- 171.yaml
release_date: '2024-02-28'
2.1.1:
changes:
bugfixes:
- 'Fix permissions on controller-side downloaded artifacts `#184 <https://github.com/ansible-middleware/keycloak/pull/184>`_
'
- 'JVM args moved to ``JAVA_OPTS`` envvar (instead of JAVA_OPTS_APPEND) `#186
<https://github.com/ansible-middleware/keycloak/pull/186>`_
'
- 'Unrelax configuration file permissions `#191 <https://github.com/ansible-middleware/keycloak/pull/191>`_
'
- 'Utilize comment filter for ``ansible_managed`` annotations `#176 <https://github.com/ansible-middleware/keycloak/pull/176>`_
'
minor_changes:
- 'Add reverse ``proxy_headers`` config, supersedes ``proxy_mode`` `#187 <https://github.com/ansible-middleware/keycloak/pull/187>`_
'
- 'Debian/Ubuntu compatibility `#178 <https://github.com/ansible-middleware/keycloak/pull/178>`_
'
- 'Use ``keycloak_realm`` as default for sub-entities `#180 <https://github.com/ansible-middleware/keycloak/pull/180>`_
'
fragments:
- 176.yaml
- 178.yaml
- 180.yaml
- 184.yaml
- 186.yaml
- 187.yaml
- 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'
2.2.0:
changes:
major_changes:
- 'Support java keystore for configuration of sensitive options `#189 <https://github.com/ansible-middleware/keycloak/pull/189>`_
'
minor_changes:
- 'Add ``wait_for_port`` and ``wait_for_log`` systemd unit logic `#199 <https://github.com/ansible-middleware/keycloak/pull/199>`_
'
- 'Customize jdbc driver downloads, optional authentication `#202 <https://github.com/ansible-middleware/keycloak/pull/202>`_
'
- 'Keystore-based vault SPI configuration `#196 <https://github.com/ansible-middleware/keycloak/pull/196>`_
'
- 'New ``keycloak_quarkus_hostname_strict_https`` parameter `#195 <https://github.com/ansible-middleware/keycloak/pull/195>`_
'
- 'Providers config and custom providers `#201 <https://github.com/ansible-middleware/keycloak/pull/201>`_
'
- 'Remove administrator credentials from files once keycloak is bootstrapped
`#197 <https://github.com/ansible-middleware/keycloak/pull/197>`_
'
- 'Update keycloak to 24.0 `#194 <https://github.com/ansible-middleware/keycloak/pull/194>`_
'
fragments:
- 189.yaml
- 194.yaml
- 195.yaml
- 196.yaml
- 197.yaml
- 199.yaml
- 201.yaml
- 202.yaml
release_date: '2024-05-01'
2.2.1:
changes:
bugfixes:
- 'JDBC provider: fix clause in argument validation `#204 <https://github.com/ansible-middleware/keycloak/pull/204>`_
'
release_summary: Internal release, documentation or test changes only.
fragments:
- 204.yaml
- v2.2.1-devel_summary.yaml
release_date: '2024-05-02'
2.2.2:
changes:
bugfixes:
- 'Turn off controller privilege escalation `#209 <https://github.com/ansible-middleware/keycloak/pull/209>`_
'
minor_changes:
- 'Copying of key material for TLS configuration `#210 <https://github.com/ansible-middleware/keycloak/pull/210>`_
'
- 'Validate certs parameter for JDBC driver downloads `#207 <https://github.com/ansible-middleware/keycloak/pull/207>`_
'
fragments:
- 207.yaml
- 209.yaml
- 210.yaml
release_date: '2024-05-06'
2.3.0:
changes:
bugfixes:
- '``kc.sh build`` uses configured jdk `#211 <https://github.com/ansible-middleware/keycloak/pull/211>`_
'
major_changes:
- 'Allow for custom providers hosted on maven repositories `#223 <https://github.com/ansible-middleware/keycloak/pull/223>`_
'
- 'Restart handler strategy behaviour `#231 <https://github.com/ansible-middleware/keycloak/pull/231>`_
'
minor_changes:
- 'Add support for policy files `#225 <https://github.com/ansible-middleware/keycloak/pull/225>`_
'
- 'Allow to add extra custom env vars in sysconfig file `#229 <https://github.com/ansible-middleware/keycloak/pull/229>`_
'
- 'Download from alternate URL with optional http authentication `#220 <https://github.com/ansible-middleware/keycloak/pull/220>`_
'
- 'Update Keycloak to version 24.0.4 `#218 <https://github.com/ansible-middleware/keycloak/pull/218>`_
'
- '``proxy-header`` enhancement `#227 <https://github.com/ansible-middleware/keycloak/pull/227>`_
'
fragments:
- 211.yaml
- 218.yaml
- 220.yaml
- 223.yaml
- 225.yaml
- 227.yaml
- 229.yaml
- 231.yaml
release_date: '2024-05-20'
2.4.0:
changes:
major_changes:
- 'Enable by default health check on restart `#234 <https://github.com/ansible-middleware/keycloak/pull/234>`_
'
- 'Update minimum ansible-core version > 2.15 `#232 <https://github.com/ansible-middleware/keycloak/pull/232>`_
'
fragments:
- 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'
2.4.2:
changes:
bugfixes:
- 'Add wait_for_port number parameter `#237 <https://github.com/ansible-middleware/keycloak/pull/237>`_
'
minor_changes:
- 'New parameter ``keycloak_quarkus_download_path`` `#239 <https://github.com/ansible-middleware/keycloak/pull/239>`_
'
fragments:
- 237.yaml
- 239.yaml
release_date: '2024-09-26'
2.4.3:
changes:
minor_changes:
- 'Update keycloak to 24.0.5 `#241 <https://github.com/ansible-middleware/keycloak/pull/241>`_
'
fragments:
- 241.yaml
release_date: '2024-10-16'

View file

@ -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

View file

@ -7,7 +7,7 @@
</div>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2022, Red Hat, Inc.</p>
<p>&#169; Copyright 2024, Red Hat, Inc.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
@ -18,4 +18,4 @@
</section>
</div>
</body>
</html>
</html>

View file

@ -24,14 +24,15 @@
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Middleware Automation</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/infinispan/">Infinispan / Red Hat Data Grid</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/keycloak/">Keycloak / Red Hat Single Sign-On</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/wildfly/">Wildfly / Red Hat JBoss EAP</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/jws/">Tomcat / Red Hat JWS</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/amq/">ActiveMQ / Red Hat AMQ Broker</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/amq_streams/">Kafka / Red Hat AMQ Streams</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/redhat-csp-download/">Red Hat CSP Download</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/ansible_collections_jcliff/">JCliff</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/infinispan/main/">Infinispan / Red Hat Data Grid</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/keycloak/main/">Keycloak / Red Hat Single Sign-On</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/wildfly/main/">Wildfly / Red Hat JBoss EAP</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/jws/main/">Tomcat / Red Hat JWS</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/amq/main/">ActiveMQ / Red Hat AMQ Broker</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/amq_streams/main/">Kafka / Red Hat AMQ Streams</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/common/main/">Ansible Middleware utilities</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/redhat-csp-download/main/">Red Hat CSP Download</a></li>
<li class="toctree-l1"><a class="reference internal" href="https://ansible-middleware.github.io/ansible_collections_jcliff/main/">JCliff</a></li>
</ul>
</div>
</div>

View file

@ -43,6 +43,7 @@ extensions = [
'myst_parser',
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx_antsibull_ext',
'ansible_basic_sphinx_ext',
]
@ -71,7 +72,7 @@ language = None
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '.tmp']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = 'ansible'
highlight_language = 'YAML+Jinja'

View file

@ -10,30 +10,25 @@ Welcome to Keycloak Collection documentation
README
plugins/index
roles/index
Changelog <CHANGELOG>
.. toctree::
:maxdepth: 2
:caption: Developer documentation
testing
developing
releasing
.. toctree::
:maxdepth: 2
:caption: General
Changelog <CHANGELOG>
Developing <developing>
Testing <testing>
Releasing <releasing>
.. toctree::
:maxdepth: 2
:caption: Middleware collections
Infinispan / Red Hat Data Grid <https://ansible-middleware.github.io/infinispan/>
Keycloak / Red Hat Single Sign-On <https://ansible-middleware.github.io/keycloak/>
Wildfly / Red Hat JBoss EAP <https://ansible-middleware.github.io/wildfly/>
Tomcat / Red Hat JWS <https://ansible-middleware.github.io/jws/>
ActiveMQ / Red Hat AMQ Broker <https://ansible-middleware.github.io/amq/>
Kafka / Red Hat AMQ Streams <https://ansible-middleware.github.io/amq_streams/>
Red Hat CSP Download <https://ansible-middleware.github.io/redhat-csp-download/>
JCliff <https://ansible-middleware.github.io/ansible_collections_jcliff/>
Keycloak / Red Hat Single Sign-On <https://ansible-middleware.github.io/keycloak/main/>
Infinispan / Red Hat Data Grid <https://ansible-middleware.github.io/infinispan/main/>
Wildfly / Red Hat JBoss EAP <https://ansible-middleware.github.io/wildfly/main/>
Tomcat / Red Hat JWS <https://ansible-middleware.github.io/jws/main/>
ActiveMQ / Red Hat AMQ Broker <https://ansible-middleware.github.io/amq/main/>
Kafka / Red Hat AMQ Streams <https://ansible-middleware.github.io/amq_streams/main/>
Ansible Middleware utilities <https://ansible-middleware.github.io/common/main/>
JCliff <https://ansible-middleware.github.io/ansible_collections_jcliff/main/>

View file

@ -1,7 +1,8 @@
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
myst-parser

View file

@ -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]

View file

@ -1,12 +1,13 @@
---
namespace: middleware_automation
name: keycloak
version: "1.2.0"
version: "3.0.0"
readme: README.md
authors:
- Romain Pelisse <rpelisse@redhat.com>
- Guido Grazioli <ggraziol@redhat.com>
- Pavan Kumar Motaparthi <pmotapar@redhat.com>
- Helmut Wolf <hwo@world-direct.at>
description: Install and configure a keycloak, or Red Hat Single Sign-on, service.
license_file: "LICENSE"
tags:
@ -21,8 +22,11 @@ tags:
- infrastructure
- authentication
- java
- runtimes
- middleware
- a4mw
dependencies:
"middleware_automation.common": ">=1.0.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
@ -31,7 +35,6 @@ issues: https://github.com/ansible-middleware/keycloak/issues
build_ignore:
- .gitignore
- .github
- .ansible-lint
- .yamllint
- '*.tar.gz'
- '*.zip'

View file

@ -1,2 +1,2 @@
---
requires_ansible: ">=2.9.10"
requires_ansible: ">=2.16.0"

View file

@ -0,0 +1,44 @@
---
- name: Converge
hosts: all
vars:
keycloak_quarkus_show_deprecation_warnings: false
keycloak_quarkus_bootstrap_admin_password: "remembertochangeme"
keycloak_quarkus_bootstrap_admin_user: "remembertochangeme"
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
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
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'

View file

@ -0,0 +1,48 @@
---
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"
cgroupns_mode: host
command: "/lib/systemd/systemd"
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
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

View file

@ -0,0 +1,12 @@
---
- name: Prepare
hosts: all
gather_facts: yes
tasks:
- name: Install sudo
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

1
molecule/debian/roles Symbolic link
View file

@ -0,0 +1 @@
../../roles

View file

@ -0,0 +1,40 @@
---
- name: Verify
hosts: all
vars:
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
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 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

View file

@ -1,47 +1,46 @@
---
- name: Converge
hosts: all
vars:
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
vars:
keycloak_quarkus_show_deprecation_warnings: false
keycloak_quarkus_bootstrap_admin_password: "remembertochangeme"
keycloak_quarkus_bootstrap_admin_user: "remembertochangeme"
keycloak_quarkus_hostname: http://instance:8080
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
- 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
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
realm: "{{ keycloak_realm }}"
public_client: "{{ keycloak_client_public }}"
web_origins: "{{ keycloak_client_web_origins }}"
users: "{{ keycloak_client_users }}"
client_id: TestClient

View file

@ -1,15 +1,9 @@
---
dependency:
name: shell
command: ansible-galaxy collection install -r molecule/requirements.yml -p $HOME/.ansible/collections --force-with-deps
driver:
name: docker
lint: |
ansible-lint --version
ansible-lint -v
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"
@ -17,6 +11,7 @@ platforms:
- "8080/tcp"
- "8443/tcp"
- "8009/tcp"
- "9000/tcp"
provisioner:
name: ansible
config_options:
@ -38,11 +33,8 @@ verifier:
name: ansible
scenario:
test_sequence:
- dependency
- lint
- cleanup
- destroy
- syntax
- create
- prepare
- converge

View file

@ -1,16 +1,9 @@
---
- name: Prepare
hosts: all
tasks:
- 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
@ -18,3 +11,19 @@
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: 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: 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/26.0.7/keycloak-26.0.7.zip
dest: /tmp/keycloak
mode: '0640'
delegate_to: localhost
run_once: true

View file

@ -2,10 +2,9 @@
- name: Verify
hosts: all
vars:
keycloak_admin_password: "remembertochangeme"
keycloak_jvm_package: java-11-openjdk-headless
keycloak_port: http://localhost:8080
keycloak_management_port: http://localhost:9990
keycloak_quarkus_bootstrap_admin_password: "remembertochangeme"
keycloak_quarkus_bootstrap_admin_user: "remembertochangeme"
keycloak_uri: "http://localhost:8080"
tasks:
- name: Populate service facts
ansible.builtin.service_facts:
@ -14,16 +13,13 @@
that:
- ansible_facts.services["keycloak.service"]["state"] == "running"
- ansible_facts.services["keycloak.service"]["status"] == "enabled"
- name: Verify we are running on requested jvm
shell: |
ps -ef | grep /usr/lib/jvm/java-11 | grep -v grep
- name: Verify token api call
ansible.builtin.uri:
url: "{{ keycloak_port }}/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"
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
retries: 2
delay: 2
delay: 2

View file

@ -0,0 +1,16 @@
---
- name: Converge
hosts: all
vars:
keycloak_quarkus_show_deprecation_warnings: false
keycloak_quarkus_bootstrap_admin_password: "remembertochangeme"
keycloak_quarkus_bootstrap_admin_user: "remembertochangeme"
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_health_check_url: http://proxy:8080/realms/master/.well-known/openid-configuration
roles:
- role: keycloak_quarkus

View file

@ -0,0 +1,57 @@
---
driver:
name: docker
platforms:
- name: instance
image: registry.access.redhat.com/ubi9/ubi-init:latest
pre_build_image: true
privileged: true
command: "/usr/sbin/init"
networks:
- name: keycloak
port_bindings:
- "8080/tcp"
published_ports:
- 0.0.0.0:8080:8080/tcp
- name: proxy
image: registry.access.redhat.com/ubi9/ubi-init:latest
pre_build_image: true
privileged: true
command: "/usr/sbin/init"
networks:
- name: keycloak
port_bindings:
- "443/tcp"
published_ports:
- 0.0.0.0:443:443/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: "{{ 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

View file

@ -0,0 +1,49 @@
---
- name: Prepare
hosts: all
tasks:
- name: Install sudo
ansible.builtin.dnf:
name: sudo
state: present
- name: "Display hera_home if defined."
ansible.builtin.set_fact:
hera_home: "{{ lookup('env', 'HERA_HOME') }}"
- name: Prepare proxy
hosts: proxy
vars:
nginx_proxy: |
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://instance:8080;
}
roles:
- elan.simple_nginx_reverse_proxy
pre_tasks:
- 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=proxy'
delegate_to: localhost
changed_when: false
- name: Make certificate directory
ansible.builtin.file:
path: /etc/nginx/tls
state: directory
mode: 0755
- name: Copy certificates
ansible.builtin.copy:
src: "{{ item.name }}"
dest: "{{ item.dest }}"
mode: 0444
become: true
loop:
- { name: 'cert.pem', dest: '/etc/nginx/tls/certificate.crt' }
- { name: 'key.pem', dest: '/etc/nginx/tls/certificate.key' }
- name: Update CA trust
ansible.builtin.command: update-ca-trust
changed_when: false
become: true

View file

@ -0,0 +1 @@
../../roles

View file

@ -0,0 +1,28 @@
---
- name: Verify
hosts: instance
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 openid config
block:
- name: Fetch openID config # noqa blocked_modules command-instead-of-module
ansible.builtin.uri:
url: http://localhost:8080/realms/master/.well-known/openid-configuration
validate_certs: false
headers:
Host: proxy
register: openid_config
changed_when: False
- name: Verify endpoint URLs
ansible.builtin.assert:
that:
- openid_config.json['issuer'] == 'https://proxy/realms/master'
- openid_config.json['authorization_endpoint'] == 'https://proxy/realms/master/protocol/openid-connect/auth'

View file

@ -1,43 +1,11 @@
---
- name: Converge
hosts: all
vars:
vars:
keycloak_admin_password: "remembertochangeme"
keycloak_config_override_template: custom.xml.j2
keycloak_http_port: 8081
keycloak_management_http_port: 19990
keycloak_service_runas: True
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

View file

@ -1,15 +1,9 @@
---
dependency:
name: shell
command: ansible-galaxy collection install -r molecule/requirements.yml -p $HOME/.ansible/collections --force-with-deps
driver:
name: docker
lint: |
ansible-lint --version
ansible-lint -v
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"
@ -17,6 +11,7 @@ platforms:
- "8080/tcp"
- "8443/tcp"
- "8009/tcp"
- "9000/tcp"
provisioner:
name: ansible
config_options:
@ -38,11 +33,8 @@ verifier:
name: ansible
scenario:
test_sequence:
- dependency
- lint
- cleanup
- destroy
- syntax
- create
- prepare
- converge

View file

@ -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

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- {{ ansible_managed }} -->
<!-- this is a custom file -->
<server xmlns="urn:jboss:domain:16.0">
<extensions>
<extension module="org.jboss.as.clustering.infinispan"/>
@ -44,7 +44,7 @@
</audit-log>
<management-interfaces>
<http-interface http-authentication-factory="management-http-authentication">
<http-upgrade enabled="true"/>
<http-upgrade enabled="true" sasl-authentication-factory="management-sasl-authentication"/>
<socket-binding http="management-http"/>
</http-interface>
</management-interfaces>
@ -481,8 +481,8 @@
<default-provider>default</default-provider>
<provider name="default" enabled="true">
<properties>
<property name="frontendUrl" value="{{ keycloak_modcluster.frontend_url }}"/>
<property name="forceBackendUrlToFrontendUrl" value="true"/>
<property name="frontendUrl" value="${keycloak.frontendUrl:}"/>
<property name="forceBackendUrlToFrontendUrl" value="false"/>
</properties>
</provider>
</spi>
@ -520,7 +520,8 @@
<subsystem xmlns="urn:jboss:domain:undertow:12.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other" statistics-enabled="${wildfly.undertow.statistics-enabled:${wildfly.statistics-enabled:false}}">
<buffer-cache name="default"/>
<server name="default-server">
<http-listener name="default" socket-binding="http"/>
<http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true"/>
<https-listener name="https" socket-binding="https" ssl-context="applicationSSC" enable-http2="true"/>
<host name="default-host" alias="localhost">
<location name="/" handler="welcome-content"/>
<http-invoker http-authentication-factory="application-http-authentication"/>
@ -533,20 +534,25 @@
<handlers>
<file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
</handlers>
<application-security-domains>
<application-security-domain name="other" security-domain="ApplicationDomain"/>
</application-security-domains>
</subsystem>
<subsystem xmlns="urn:jboss:domain:weld:4.0"/>
</profile>
<interfaces>
<interface name="management">
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
<inet-address value="127.0.0.1"/>
</interface>
<interface name="public">
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
<inet-address value="127.0.0.1"/>
</interface>
</interfaces>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding name="http" port="8081"/>
<socket-binding name="https" port="8443"/>
<socket-binding name="management-http" interface="management" port="19990"/>
<socket-binding name="management-https" interface="management" port="19991"/>
<socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/>
<outbound-socket-binding name="mail-smtp">

View file

@ -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

View file

@ -3,26 +3,56 @@
ansible.builtin.debug:
msg: "Ansible version is {{ ansible_version.full }}"
- name: Install sudo
- 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
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 is installed."
ansible.builtin.assert:
that:
- sudo_pkg_name in ansible_facts.packages
fail_msg: "sudo is not installed on target system"
- name: "Install iproute"
become: true
ansible.builtin.yum:
name:
- iproute
state: present
- 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 and deploy jws 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
- name: "Download artefacts only if assets_server is set"
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:
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
mode: '0644'
delegate_to: localhost
loop: "{{ assets }}"
loop_control:
loop_var: asset

View file

@ -0,0 +1,48 @@
---
- name: Converge
hosts: all
vars:
keycloak_quarkus_show_deprecation_warnings: false
keycloak_quarkus_bootstrap_admin_password: "remembertochangeme"
keycloak_quarkus_bootstrap_admin_user: "remembertochangeme"
keycloak_realm: TestRealm
keycloak_quarkus_log: file
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
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

View file

@ -0,0 +1,47 @@
---
driver:
name: docker
platforms:
- name: instance
image: registry.access.redhat.com/ubi9/ubi-init:latest
pre_build_image: true
privileged: true
command: "/usr/sbin/init"
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:
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

View file

@ -0,0 +1,49 @@
---
- 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: "Ensure common prepare phase are set."
ansible.builtin.include_tasks: ../prepare.yml
- name: Install JDK17
become: yes
ansible.builtin.yum:
name:
- java-17-openjdk-headless
state: present
when:
- ansible_facts.os_family == 'RedHat'
- name: Link default logs directory
become: yes
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:
hera_home: "{{ lookup('env', 'HERA_HOME') }}"

View file

@ -0,0 +1 @@
../../roles

View file

@ -0,0 +1,47 @@
---
- 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"
- 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

View file

@ -1,20 +1,61 @@
---
- name: Converge
hosts: all
vars:
keycloak_quarkus_admin_pass: "remembertochangeme"
keycloak_admin_password: "remembertochangeme"
vars:
keycloak_quarkus_show_deprecation_warnings: false
keycloak_quarkus_bootstrap_admin_password: "remembertochangeme"
keycloak_quarkus_bootstrap_admin_user: "remembertochangeme"
keycloak_realm: TestRealm
keycloak_quarkus_host: instance
keycloak_quarkus_http_relative_path: ''
keycloak_quarkus_hostname: https://instance:8443
keycloak_quarkus_log: file
keycloak_quarkus_https_enabled: True
keycloak_quarkus_key_file: "{{ keycloak.home }}/conf/key.pem"
keycloak_quarkus_cert_file: "{{ keycloak.home }}/conf/cert.pem"
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') }}"
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/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_restart_health_check: false # would fail because of self-signed cert
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
- 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: 26.0.7 # 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"
- 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
keycloak_url: http://instance:8080
keycloak_context: ''
keycloak_admin_user: "{{ keycloak_quarkus_bootstrap_admin_user }}"
keycloak_admin_password: "{{ keycloak_quarkus_bootstrap_admin_password }}"
keycloak_client_default_roles:
- TestRoleAdmin
- TestRoleUser

View file

@ -1,15 +1,9 @@
---
dependency:
name: shell
command: ansible-galaxy collection install -r molecule/requirements.yml -p $HOME/.ansible/collections --force-with-deps
driver:
name: docker
lint: |
ansible-lint --version
ansible-lint -v
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"
@ -17,6 +11,7 @@ platforms:
- "8080/tcp"
- "8443/tcp"
- "8009/tcp"
- "9000/tcp"
published_ports:
- 0.0.0.0:8443:8443/tcp
provisioner:
@ -36,15 +31,13 @@ provisioner:
ansible_python_interpreter: "{{ ansible_playbook_python }}"
env:
ANSIBLE_FORCE_COLOR: "true"
PYTHONHTTPSVERIFY: 0
verifier:
name: ansible
scenario:
test_sequence:
- dependency
- lint
- cleanup
- destroy
- syntax
- create
- prepare
- converge

View file

@ -2,37 +2,43 @@
- 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') }}"
- ansible.builtin.command: openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes -subj '/CN=instance'
- 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'
delegate_to: localhost
changed_when: false
- block:
- ansible.builtin.lineinfile:
dest: /etc/hosts
line: "127.0.0.1 instance"
state: present
delegate_to: localhost
become: yes
when:
- hera_home is defined
- hera_home | length == 0
- ansible.builtin.file:
- name: Create vault directory
become: true
ansible.builtin.file:
state: directory
path: /opt/keycloak/keycloak-18.0.0/conf/
path: "/opt/keycloak/vault"
mode: '0755'
- ansible.builtin.copy:
src: "{{ item }}"
dest: "/opt/keycloak/keycloak-18.0.0/conf/{{ item }}"
mode: 0444
loop:
- cert.pem
- key.pem
- name: Make sure a jre is available (for keytool to prepare keystore)
delegate_to: localhost
ansible.builtin.package:
name: "{{ 'java-21-openjdk-headless' if hera_home | length > 0 else 'openjdk-21-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'

View file

@ -1,35 +1,128 @@
---
- name: Verify
hosts: all
vars:
keycloak_quarkus_bootstrap_admin_password: "remembertochangeme"
keycloak_quarkus_bootstrap_admin_user: "remembertochangeme"
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"
- set_fact:
- name: Set internal envvar
ansible.builtin.set_fact:
hera_home: "{{ lookup('env', 'HERA_HOME') }}"
- block:
- name: Fetch openID config
shell: |
curl https://instance:8443/realms/master/.well-known/openid-configuration -k | jq .
delegate_to: localhost
register: openid_config
- debug:
msg: " {{ openid_config.stdout | from_json }}"
delegate_to: localhost
- name: Verify endpoint URLs
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: 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: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
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
- name: Verify token api call
ansible.builtin.uri:
url: "https://instance:8443/realms/master/protocol/openid-connect/token"
method: POST
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
retries: 2
delay: 2
- name: "Get Clients"
ansible.builtin.uri:
url: "https://instance:8443/admin/realms/TestRealm/clients"
validate_certs: false
headers:
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://instance:8443/admin/realms/TestRealm/clients/{{ keycloak_client_uuid }}"
validate_certs: false
headers:
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:
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
register: keycloak_test_client_roles

View file

@ -0,0 +1,29 @@
---
- name: Converge
hosts: keycloak
vars:
keycloak_quarkus_show_deprecation_warnings: false
keycloak_quarkus_bootstrap_admin_password: "remembertochangeme"
keycloak_quarkus_bootstrap_admin_user: "remembertochangeme"
keycloak_quarkus_hostname: "http://{{ inventory_hostname }}:8080"
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

View file

@ -0,0 +1,82 @@
---
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"
- "9000/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"
- "9000/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"
PYTHONHTTPSVERIFY: 0
verifier:
name: ansible
scenario:
test_sequence:
- cleanup
- destroy
- create
- prepare
- converge
- idempotence
- side_effect
- verify
- cleanup
- destroy

View file

@ -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

View file

@ -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

1
molecule/quarkus_ha/roles Symbolic link
View file

@ -0,0 +1 @@
../../roles

View file

@ -0,0 +1,29 @@
---
- name: Verify
hosts: keycloak
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: Check log file
become: true
ansible.builtin.stat:
path: /var/log/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

View file

@ -0,0 +1,10 @@
---
- name: Converge
hosts: all
vars_files:
- vars.yml
vars:
keycloak_quarkus_show_deprecation_warnings: false
keycloak_quarkus_version: 26.0.7
roles:
- role: keycloak_quarkus

View file

@ -0,0 +1,45 @@
---
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
- "9000/tcp"
published_ports:
- 0.0.0.0:8080:8080/TCP
- 0.0.0.0:9000:9000/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

View file

@ -0,0 +1,52 @@
---
- name: Prepare
hosts: all
vars_files:
- vars.yml
vars:
sudo_pkg_name: sudo
keycloak_quarkus_version: 24.0.5
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

View file

@ -0,0 +1 @@
../../roles

View file

@ -0,0 +1,13 @@
---
keycloak_quarkus_offline_install: false
keycloak_quarkus_bootstrap_admin_password: "remembertochangeme"
keycloak_quarkus_realm: TestRealm
keycloak_quarkus_hostname: http://instance:8080
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

View file

@ -0,0 +1,32 @@
---
- name: Verify
hosts: instance
vars:
keycloak_quarkus_bootstrap_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["keycloak.service"]["state"] == "running"
- ansible_facts.services["keycloak.service"]["status"] == "enabled"
- name: Verify we are running on requested jvm
ansible.builtin.shell: |
set -eo pipefail
ps -ef | grep 'etc/alternatives/.*21' | 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_bootstrap_admin_password }}&grant_type=password"
validate_certs: no
register: keycloak_auth_response
until: keycloak_auth_response.status == 200
retries: 2
delay: 2

View file

@ -1,8 +1,11 @@
---
collections:
- name: middleware_automation.common
- name: middleware_automation.jbcs
- name: community.general
- name: ansible.posix
- name: community.docker
version: ">=1.9.1"
version: ">=3.8.0"
roles:
- name: elan.simple_nginx_reverse_proxy

View file

@ -55,14 +55,14 @@
- TestClient1Admin
- TestClient1User
realm: "{{ keycloak_realm }}"
public_client: True
public_client: true
web_origins:
- http://testclient1origin/application
- http://testclient1origin/other
users:
- username: TestUser
password: password
client_roles:
- client: TestClient1
role: TestClient1User
realm: "{{ keycloak_realm }}"
- username: TestUser
password: password
client_roles:
- client: TestClient1
role: TestClient1User
realm: "{{ keycloak_realm }}"

View file

@ -1,13 +1,11 @@
---
- name: Playbook for Keycloak X Hosts
- name: Playbook for Keycloak X Hosts with HTTPS enabled
hosts: all
vars:
keycloak_admin_password: "remembertochangeme"
keycloak_quarkus_host: localhost:8443
keycloak_quarkus_http_relative_path: ''
keycloak_quarkus_admin_pass: "remembertochangeme"
keycloak_quarkus_hostname: http://localhost
keycloak_quarkus_port: 8443
keycloak_quarkus_log: file
keycloak_quarkus_https_enabled: True
keycloak_quarkus_key_file: conf/key.pem
keycloak_quarkus_cert_file: conf/cert.pem
keycloak_quarkus_proxy_mode: none
roles:
- middleware_automation.keycloak.keycloak_quarkus

View file

@ -0,0 +1,12 @@
---
- name: Playbook for Keycloak X Hosts in develop mode
hosts: all
vars:
keycloak_admin_password: "remembertochangeme"
keycloak_quarkus_hostname: http://localhost
keycloak_quarkus_port: 8080
keycloak_quarkus_log: file
keycloak_quarkus_start_dev: true
keycloak_quarkus_proxy_mode: none
roles:
- middleware_automation.keycloak.keycloak_quarkus

View file

@ -10,17 +10,17 @@
- TestClient1Admin
- TestClient1User
realm: TestRealm
public_client: True
public_client: true
web_origins:
- http://testclient1origin/application
- http://testclient1origin/other
users:
- username: TestUser
password: password
client_roles:
- client: TestClient1
role: TestClient1User
realm: TestRealm
- username: TestUser
password: password
client_roles:
- client: TestClient1
role: TestClient1User
realm: TestRealm
roles:
- role: middleware_automation.keycloak.keycloak_realm
keycloak_realm: TestRealm

View file

@ -3,6 +3,6 @@
hosts: sso
vars:
keycloak_admin_password: "remembertochangeme"
sso_enable: True
sso_enable: true
roles:
- middleware_automation.keycloak.keycloak

View file

@ -1,52 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2021 Eric Lavarde <elavarde@redhat.com>
# 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 = '''
name: version_sort
short_description: Sort a list according to version order instead of pure alphabetical one
version_added: 2.2.0
author: Eric L. (@ericzolf)
description:
- Sort a list according to version order instead of pure alphabetical one.
options:
_input:
description: A list of strings to sort.
type: list
elements: string
required: true
'''
EXAMPLES = '''
- name: Convert list of tuples into dictionary
ansible.builtin.set_fact:
dictionary: "{{ ['2.1', '2.10', '2.9'] | middleware_automation.keycloak.version_sort }}"
# Result is ['2.1', '2.9', '2.10']
'''
RETURN = '''
_value:
description: The list of strings sorted by version.
type: list
elements: string
'''
from ansible_collections.middleware_automation.keycloak.plugins.module_utils.version import LooseVersion
def version_sort(value, reverse=False):
'''Sort a list according to loose versions so that e.g. 2.9 is smaller than 2.10'''
return sorted(value, key=LooseVersion, reverse=reverse)
class FilterModule(object):
''' Version sort filter '''
def filters(self):
return {
'version_sort': version_sort
}

File diff suppressed because it is too large Load diff

View file

@ -1,22 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2021, Felix Fontein <felix@fontein.de>
# 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
"""Provide version object to compare version numbers."""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.six import raise_from
try:
from ansible.module_utils.compat.version import LooseVersion # noqa: F401, pylint: disable=unused-import
except ImportError:
try:
from distutils.version import LooseVersion # noqa: F401, pylint: disable=unused-import
except ImportError as exc:
msg = 'To use this plugin or module with ansible-core 2.11, you need to use Python < 3.12 with distutils.version present'
raise_from(ImportError(msg), exc)

View file

@ -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
@ -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)

View file

@ -0,0 +1,848 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright (c) 2017, Eike Frost <ei@kefro.st>
# Copyright (c) 2021, Christophe Gilles <christophe.gilles54@gmail.com>
# 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()

View file

@ -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
@ -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

View file

@ -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:
@ -475,100 +515,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: 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: 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
'''
RETURN = '''
@ -705,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
@ -761,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),
@ -793,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),
)
@ -826,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:
@ -856,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 = {}
@ -865,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
@ -874,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:
@ -893,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()
@ -919,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)
@ -978,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)

View file

@ -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
netaddr
lxml # for middleware_automation.common.maven_artifact

View file

@ -1,4 +1,5 @@
---
collections:
- name: middleware_automation.common
version: ">=1.2.1"
- name: ansible.posix

View file

@ -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`
@ -39,7 +40,7 @@ Versions
Patching
--------
When variable `keycloak_rhsso_apply_patches` is `True` (default: `False`), the role will automatically apply the latest cumulative patch for the selected base version.
When variable `keycloak_rhsso_apply_patches` is `true` (default: `false`), the role will automatically apply the latest cumulative patch for the selected base version.
| RH-SSO VERSION | Release Date | RH-SSO LATEST CP | Notes |
|:---------------|:------------------|:-----------------|:----------------|
@ -55,8 +56,9 @@ Role Defaults
| Variable | Description | Default |
|:---------|:------------|:---------|
|`keycloak_ha_enabled`| Enable auto configuration for database backend, clustering and remote caches on infinispan | `False` |
|`keycloak_ha_discovery`| Discovery protocol for HA cluster members | `JDBC_PING` if keycloak_db_enabled else `TCPPING` |
|`keycloak_ha_discovery`| Discovery protocol for HA cluster members | `JDBC_PING` if `keycloak_db_enabled` else `TCPPING` |
|`keycloak_db_enabled`| Enable auto configuration for database backend | `True` if `keycloak_ha_enabled` is True, else `False` |
|`keycloak_remote_cache_enabled`| Enable remote cache store when in clustered ha configurations | `True` if `keycloak_ha_enabled` else `False` |
|`keycloak_admin_user`| Administration console user account | `admin` |
|`keycloak_bind_address`| Address for binding service ports | `0.0.0.0` |
|`keycloak_management_port_bind_address`| Address for binding management ports | `127.0.0.1` |
@ -67,13 +69,19 @@ Role Defaults
|`keycloak_jgroups_port`| jgroups cluster tcp port | `7600` |
|`keycloak_management_http_port`| Management port | `9990` |
|`keycloak_management_https_port`| TLS management port | `9993` |
|`keycloak_prefer_ipv4`| Prefer IPv4 stack and addresses for port binding | `True` |
|`keycloak_prefer_ipv4`| Prefer IPv4 stack and addresses for port binding | `true` |
|`keycloak_config_standalone_xml`| filename for configuration | `keycloak.xml` |
|`keycloak_service_user`| posix account username | `keycloak` |
|`keycloak_service_group`| posix account group | `keycloak` |
|`keycloak_service_pidfile`| pid file path for service | `/run/keycloak.pid` |
|`keycloak_service_restart_always`| systemd restart always behavior activation | `False` |
|`keycloak_service_restart_on_failure`| systemd restart on-failure behavior activation | `False` |
|`keycloak_service_startlimitintervalsec`| systemd StartLimitIntervalSec | `300` |
|`keycloak_service_startlimitburst`| systemd StartLimitBurst | `5` |
|`keycloak_service_restartsec`| systemd RestartSec | `10s` |
|`keycloak_service_pidfile`| pid file path for service | `/run/keycloak/keycloak.pid` |
|`keycloak_features` | List of `name`/`status` pairs of features (also known as profiles on RH-SSO) to `enable` or `disable`, example: `[ { name: 'docker', status: 'enabled' } ]` | `[]`
|`keycloak_jvm_package`| RHEL java package runtime | `java-1.8.0-openjdk-headless` |
|`keycloak_java_home`| JAVA_HOME of installed JRE, leave empty for using specified keycloak_jvm_package RPM path | `None` |
|`keycloak_java_home`| `JAVA_HOME` of installed JRE, leave empty for using RPM path at `keycloak_jvm_package` | `None` |
|`keycloak_java_opts`| Additional JVM options | `-Xms1024m -Xmx2048m` |
@ -81,12 +89,12 @@ Role Defaults
| Variable | Description | Default |
|:---------|:------------|:---------|
|`keycloak_offline_install` | perform an offline install | `False`|
|`keycloak_download_url`| Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/<version>/<archive>`|
|`keycloak_offline_install` | perform an offline install | `false`|
|`keycloak_download_url`| Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/<version>/<archive>`|
|`keycloak_version`| keycloak.org package version | `18.0.2` |
|`keycloak_dest`| Installation root path | `/opt/keycloak` |
|`keycloak_download_url` | Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/{{ keycloak_version }}/{{ keycloak_archive }}` |
|`keycloak_configure_firewalld` | Ensure firewalld is running and configure keycloak ports | `False` |
|`keycloak_configure_firewalld` | Ensure firewalld is running and configure keycloak ports | `false` |
* Miscellaneous configuration
@ -97,14 +105,21 @@ Role Defaults
|`keycloak_download_url_9x` | Download URL for keycloak (deprecated) | `https://downloads.jboss.org/keycloak/{{ keycloak_version }}/{{ keycloak_archive }}` |
|`keycloak_installdir` | Installation path | `{{ keycloak_dest }}/keycloak-{{ keycloak_version }}` |
|`keycloak_jboss_home` | Installation work directory | `{{ keycloak_rhsso_installdir }}` |
|`keycloak_jboss_port_offset` | Port offset for the JBoss socket binding | `0` |
|`keycloak_config_dir` | Path for configuration | `{{ keycloak_jboss_home }}/standalone/configuration` |
|`keycloak_config_path_to_standalone_xml` | Custom path for configuration | `{{ keycloak_jboss_home }}/standalone/configuration/{{ keycloak_config_standalone_xml }}` |
|`keycloak_config_override_template` | Path to custom template for standalone.xml configuration | `''` |
|`keycloak_auth_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_host }}:{{ keycloak_http_port }}` |
|`keycloak_management_url` | URL for management console rest calls | `http://{{ keycloak_host }}:{{ keycloak_management_http_port }}` |
|`keycloak_force_install` | Remove pre-existing versions of service | `false` |
|`keycloak_url` | URL for configuration rest calls | `http://{{ keycloak_host }}:{{ keycloak_http_port + keycloak_jboss_port_offset }}` |
|`keycloak_management_url` | URL for management console rest calls | `http://{{ keycloak_host }}:{{ keycloak_management_http_port + keycloak_jboss_port_offset }}` |
|`keycloak_frontend_url_force` | Force backend requests to use the frontend URL | `false` |
|`keycloak_db_background_validation` | Enable background validation of database connection | `false` |
|`keycloak_db_background_validation_millis`| How frequenly the connection pool is validated in the background | `10000` if background validation enabled |
|`keycloak_db_background_validate_on_match` | Enable validate on match for database connections | `false` |
|`keycloak_frontend_url` | frontend URL for keycloak endpoint | `http://localhost:8080/auth/` |
|`keycloak_log_target`| Set the destination of the keycloak log folder link | `/var/log/keycloak` |
Role Variables
@ -115,10 +130,10 @@ The following are a set of _required_ variables for the role:
| Variable | Description |
|:---------|:------------|
|`keycloak_admin_password`| Password for the administration console user account (minimum 12 characters) |
|`keycloak_frontend_url` | frontend URL for keycloak endpoint | `http://localhost:8080/auth` |
|`keycloak_frontend_url` | frontend URL for keycloak endpoint | `http://localhost:8080/auth/` |
The following variables are _required_ only when `keycloak_ha_enabled` is True:
The following parameters are _required_ only when `keycloak_ha_enabled` is true:
| Variable | Description | Default |
|:---------|:------------|:--------|
@ -126,7 +141,7 @@ The following variables are _required_ only when `keycloak_ha_enabled` is True:
|`keycloak_modcluster_url` | _deprecated_ Host for the modcluster reverse proxy | `localhost` |
|`keycloak_modcluster_port` | _deprecated_ Port for the modcluster reverse proxy | `6666` |
|`keycloak_modcluster_urls` | List of {host,port} dicts for the modcluster reverse proxies | `[ { localhost:6666 } ]` |
|`keycloak_jdbc_engine` | backend database engine when db is enabled: [ postgres, mariadb ] | `postgres` |
|`keycloak_jdbc_engine` | backend database engine when db is enabled: [ postgres, mariadb, sqlserver ] | `postgres` |
|`keycloak_infinispan_url` | URL for the infinispan remote-cache server | `localhost:11122` |
|`keycloak_infinispan_user` | username for connecting to infinispan | `supervisor` |
|`keycloak_infinispan_pass` | password for connecting to infinispan | `supervisor` |
@ -136,7 +151,7 @@ The following variables are _required_ only when `keycloak_ha_enabled` is True:
|`keycloak_infinispan_trust_store_password`| Password for opening truststore | `changeit` |
The following variables are _required_ only when `keycloak_db_enabled` is True:
The following parameters are _required_ only when `keycloak_db_enabled` is true:
| Variable | Description | Default |
|:---------|:------------|:---------|
@ -146,6 +161,14 @@ The following variables are _required_ only when `keycloak_db_enabled` is True:
|`keycloak_db_pass` | password for connecting to postgres | `keycloak-pass` |
The following variables are _optional_:
| Variable | Description |
|:---------|:------------|
|`keycloak_db_valid_conn_sql` | Override the default database connection validation query sql |
|`keycloak_admin_url` | Override the default administration endpoint URL |
|`keycloak_jgroups_subnet`| Override the subnet match for jgroups cluster formation; if not defined, it will be inferred from local machine route configuration |
Example Playbook
-----------------
@ -156,8 +179,6 @@ Example Playbook
- hosts: ...
vars:
keycloak_admin_password: "remembertochangeme"
collections:
- middleware_automation.keycloak
roles:
- middleware_automation.keycloak.keycloak
```
@ -176,7 +197,7 @@ Example Playbook
name: keycloak
vars:
keycloak_admin_password: "remembertochangeme"
keycloak_offline_install: True
keycloak_offline_install: true
# This should be the filename of keycloak archive on Ansible node: keycloak-16.1.0.zip
```

View file

@ -5,26 +5,34 @@ keycloak_archive: "keycloak-legacy-{{ keycloak_version }}.zip"
keycloak_download_url: "https://github.com/keycloak/keycloak/releases/download/{{ keycloak_version }}/{{ keycloak_archive }}"
keycloak_download_url_9x: "https://downloads.jboss.org/keycloak/{{ keycloak_version }}/{{ keycloak_archive }}"
keycloak_installdir: "{{ keycloak_dest }}/keycloak-{{ keycloak_version }}"
keycloak_offline_install: False
keycloak_offline_install: false
### Install location and service settings
keycloak_jvm_package: java-1.8.0-openjdk-headless
keycloak_java_home:
keycloak_dest: /opt/keycloak
keycloak_jboss_home: "{{ keycloak_installdir }}"
keycloak_jboss_port_offset: 0
keycloak_config_dir: "{{ keycloak_jboss_home }}/standalone/configuration"
keycloak_config_standalone_xml: "keycloak.xml"
keycloak_config_path_to_standalone_xml: "{{ keycloak_jboss_home }}/standalone/configuration/{{ keycloak_config_standalone_xml }}"
keycloak_config_override_template: ''
keycloak_config_path_to_properties: "{{ keycloak_jboss_home }}/standalone/configuration/profile.properties"
keycloak_service_runas: false
keycloak_service_user: keycloak
keycloak_service_group: keycloak
keycloak_service_pidfile: "/run/keycloak.pid"
keycloak_service_pidfile: "/run/keycloak/keycloak.pid"
keycloak_service_name: keycloak
keycloak_service_desc: Keycloak
keycloak_service_start_delay: 10
keycloak_service_start_retries: 25
keycloak_service_restart_always: false
keycloak_service_restart_on_failure: false
keycloak_service_startlimitintervalsec: "300"
keycloak_service_startlimitburst: "5"
keycloak_service_restartsec: "10s"
keycloak_configure_firewalld: False
keycloak_configure_firewalld: false
keycloak_configure_iptables: false
### administrator console password
keycloak_admin_password: ''
@ -36,25 +44,29 @@ keycloak_http_port: 8080
keycloak_https_port: 8443
keycloak_ajp_port: 8009
keycloak_jgroups_port: 7600
keycloak_jgroups_subnet:
keycloak_management_port_bind_address: 127.0.0.1
keycloak_management_http_port: 9990
keycloak_management_https_port: 9993
keycloak_java_opts: "-Xms1024m -Xmx2048m"
keycloak_prefer_ipv4: True
keycloak_prefer_ipv4: true
keycloak_features: []
### Enable configuration for database backend, clustering and remote caches on infinispan
keycloak_ha_enabled: False
keycloak_ha_enabled: false
### Enable database configuration, must be enabled when HA is configured
keycloak_db_enabled: "{{ True if keycloak_ha_enabled else False }}"
### Discovery protocol for ha cluster members, valus [ 'JDBC_PING', 'TCPPING' ]
keycloak_ha_discovery: "{{ 'JDBC_PING' if keycloak_db_enabled else 'TCPPING' }}"
### Remote cache store on infinispan cluster
keycloak_remote_cache_enabled: "{{ True if keycloak_ha_enabled else False }}"
### Keycloak administration console user
keycloak_admin_user: admin
keycloak_auth_realm: master
keycloak_auth_client: admin-cli
keycloak_force_install: False
keycloak_force_install: false
### mod_cluster reverse proxy list
keycloak_modcluster_enabled: "{{ True if keycloak_ha_enabled else False }}"
@ -65,23 +77,29 @@ keycloak_modcluster_urls:
port: "{{ keycloak_modcluster_port }}"
### keycloak frontend url
keycloak_frontend_url: http://localhost:8080/auth
keycloak_frontend_url: http://localhost:8080/auth/
keycloak_frontend_url_force: false
keycloak_admin_url:
### infinispan remote caches access (hotrod)
keycloak_infinispan_user: supervisor
keycloak_infinispan_pass: supervisor
keycloak_infinispan_url: localhost
keycloak_infinispan_sasl_mechanism: SCRAM-SHA-512
keycloak_infinispan_use_ssl: False
keycloak_infinispan_use_ssl: false
# if ssl is enabled, import ispn server certificate here
keycloak_infinispan_trust_store_path: /etc/pki/java/cacerts
keycloak_infinispan_trust_store_password: changeit
### database backend engine: values [ 'postgres', 'mariadb' ]
### database backend engine: values [ 'postgres', 'mariadb', 'sqlserver' ]
keycloak_jdbc_engine: postgres
### database backend credentials
keycloak_db_user: keycloak-user
keycloak_db_pass: keycloak-pass
## connection validation
keycloak_db_background_validation: false
keycloak_db_background_validation_millis: "{{ 10000 if keycloak_db_background_validation else 0 }}"
keycloak_db_background_validate_on_match: false
keycloak_jdbc_url: "{{ keycloak_default_jdbc[keycloak_jdbc_engine].url }}"
keycloak_jdbc_driver_version: "{{ keycloak_default_jdbc[keycloak_jdbc_engine].version }}"
# override the variables above, following defaults show minimum supported versions
@ -92,5 +110,11 @@ keycloak_default_jdbc:
mariadb:
url: 'jdbc:mariadb://localhost:3306/keycloak'
version: 2.7.4
sqlserver:
url: 'jdbc:sqlserver://localhost:1433;databaseName=keycloak;'
version: 12.2.0
# role specific vars
keycloak_no_log: True
keycloak_no_log: true
### logging configuration
keycloak_log_target: /var/log/keycloak

View file

@ -2,42 +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:
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"
@ -45,106 +41,100 @@ 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"
keycloak_jboss_port_offset:
default: 0
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:
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.pid"
default: "/run/keycloak/keycloak.pid"
description: "PID file path for service"
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' } ]`
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"
keycloak_management_port_bind_address:
default: "127.0.0.1"
description: "Address for binding the managemnt ports"
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"
@ -153,27 +143,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"
@ -182,7 +167,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"
@ -195,83 +179,71 @@ 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"
keycloak_frontend_url_force:
default: false
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 ]"
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 }}"
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 }}"
default: "http://{{ keycloak_host }}:{{ keycloak_management_http_port + keycloak_jboss_port_offset }}"
description: "URL for management console rest calls"
type: "str"
keycloak_service_name:
@ -290,10 +262,77 @@ argument_specs:
default: "25"
description: "How many time should Ansible retry to connect to the service after it was started, before failing."
type: "int"
keycloak_service_restart_always:
default: false
description: "systemd restart always behavior activation for keycloak"
type: "bool"
keycloak_service_restart_on_failure:
default: false
description: "systemd restart on-failure behavior activation for keycloak"
type: "bool"
keycloak_service_startlimitintervalsec:
default: 300
description: "systemd StartLimitIntervalSec for keycloak"
type: "int"
keycloak_service_startlimitburst:
default: 5
description: "systemd StartLimitBurst for keycloak"
type: "int"
keycloak_service_restartsec:
default: "5s"
description: "systemd RestartSec for keycloak"
type: "str"
keycloak_no_log:
default: true
type: "bool"
description: "Changes default behavior for no_log for debugging purpose, do not change for production system."
keycloak_remote_cache_enabled:
default: "{{ True if keycloak_ha_enabled else False }}"
description: "Enable remote cache store when in clustered ha configurations"
type: "bool"
keycloak_db_background_validation:
default: false
description: "Enable background validation of database connection"
type: "bool"
keycloak_db_background_validation_millis:
default: "{{ 10000 if keycloak_db_background_validation else 0 }}"
description: "How frequenly the connection pool is validated in the background"
type: 'int'
keycloak_db_background_validate_on_match:
default: false
description: "Enable validate on match for database connections"
type: "bool"
keycloak_db_valid_conn_sql:
required: false
description: "Override the default database connection validation query sql"
type: "str"
keycloak_admin_url:
required: false
description: "Override the default administration endpoint URL"
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
type: "str"
keycloak_log_target:
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:
@ -313,15 +352,15 @@ argument_specs:
description: "Installation path for Red Hat SSO"
type: "str"
sso_apply_patches:
default: False
default: false
description: "Install Red Hat SSO most recent cumulative patch"
type: "bool"
sso_enable:
default: True
default: true
description: "Enable Red Hat Single Sign-on installation"
type: "str"
sso_offline_install:
default: False
default: false
description: "Perform an offline install"
type: "bool"
sso_service_name:
@ -333,7 +372,7 @@ argument_specs:
description: "systemd description for Red Hat Single Sign-On"
type: "str"
sso_patch_version:
required: False
required: false
description: "Red Hat Single Sign-On latest cumulative patch version to apply; defaults to latest version when sso_apply_patches is True"
type: "str"
sso_patch_bundle:

View file

@ -12,12 +12,12 @@ galaxy_info:
license: Apache License 2.0
min_ansible_version: "2.9"
min_ansible_version: "2.16"
platforms:
- name: EL
versions:
- 8
- name: EL
versions:
- "8"
galaxy_tags:
- keycloak

View file

@ -0,0 +1,6 @@
---
- name: Include firewall config tasks
ansible.builtin.include_tasks: iptables.yml
when: keycloak_configure_iptables
tags:
- firewall

View file

@ -1,20 +1,31 @@
---
- name: Check packages to be installed
block:
- name: "Check if packages are already installed" # noqa command-instead-of-module this runs faster
ansible.builtin.command: "rpm -q {{ packages_list | join(' ') }}"
register: rpm_info
changed_when: rpm_info.failed
- name: "Check if packages are already installed" # noqa command-instead-of-module this runs faster
ansible.builtin.command: "rpm -q {{ packages_list | join(' ') }}"
register: rpm_info
changed_when: false
failed_when: false
when: ansible_facts.os_family == "RedHat"
rescue:
- 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$') | flatten }}"
when: rpm_info.failed
- 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: yes
ansible.builtin.yum:
become: true
ansible.builtin.dnf:
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"

View file

@ -6,19 +6,19 @@
- firewalld
- name: Enable and start the firewalld service
become: yes
become: true
ansible.builtin.systemd:
name: firewalld
enabled: yes
enabled: true
state: started
- name: "Configure firewall for {{ keycloak.service_name }} ports"
become: yes
- name: "Configure firewall ports for {{ keycloak.service_name }}"
become: true
ansible.posix.firewalld:
port: "{{ item }}"
permanent: true
state: enabled
immediate: yes
immediate: true
loop:
- "{{ keycloak_http_port }}/tcp"
- "{{ keycloak_https_port }}/tcp"

View file

@ -11,7 +11,7 @@
quiet: true
- name: Check for an existing deployment
become: yes
become: true
ansible.builtin.stat:
path: "{{ keycloak_jboss_home }}"
register: existing_deploy
@ -20,38 +20,47 @@
when: existing_deploy.stat.exists and keycloak_force_install | bool
block:
- name: "Stop the old {{ keycloak.service_name }} service"
become: yes
ignore_errors: yes
become: true
failed_when: false
ansible.builtin.systemd:
name: keycloak
state: stopped
- name: "Remove the old {{ keycloak.service_name }} deployment"
become: yes
become: true
ansible.builtin.file:
path: "{{ keycloak_jboss_home }}"
state: absent
- name: Check for an existing deployment after possible forced removal
become: yes
become: true
ansible.builtin.stat:
path: "{{ keycloak_jboss_home }}"
- name: "Create {{ keycloak.service_name }} service user/group"
become: yes
- name: "Create service user/group for {{ keycloak.service_name }}"
become: true
ansible.builtin.user:
name: "{{ keycloak_service_user }}"
home: /opt/keycloak
system: yes
create_home: no
system: true
create_home: false
- name: "Create {{ keycloak.service_name }} install location"
become: yes
- name: "Create install location for {{ keycloak.service_name }}"
become: true
ansible.builtin.file:
dest: "{{ keycloak_dest }}"
state: directory
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
mode: 0750
mode: '0750'
- name: Create pidfile folder
become: true
ansible.builtin.file:
dest: "{{ keycloak_service_pidfile | dirname }}"
state: directory
owner: "{{ keycloak_service_user if keycloak_service_runas else omit }}"
group: "{{ keycloak_service_group if keycloak_service_runas else omit }}"
mode: '0750'
## check remote archive
- name: Set download archive path
@ -59,7 +68,7 @@
archive: "{{ keycloak_dest }}/{{ keycloak.bundle }}"
- name: Check download archive path
become: yes
become: true
ansible.builtin.stat:
path: "{{ archive }}"
register: archive_path
@ -75,9 +84,9 @@
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: yes
run_once: true
when:
- archive_path is defined
- archive_path.stat is defined
@ -87,7 +96,7 @@
- name: Perform download from RHN using JBoss Network API
delegate_to: localhost
run_once: yes
run_once: true
when:
- archive_path is defined
- archive_path.stat is defined
@ -105,13 +114,13 @@
register: rhn_products
no_log: "{{ omit_rhn_output | default(true) }}"
delegate_to: localhost
run_once: yes
run_once: true
- name: Determine install zipfile from search results
ansible.builtin.set_fact:
rhn_filtered_products: "{{ rhn_products.results | selectattr('file_path', 'match', '[^/]*/' + sso_archive + '$') }}"
delegate_to: localhost
run_once: yes
run_once: true
- name: Download Red Hat Single Sign-On
middleware_automation.common.product_download: # noqa risky-file-permissions delegated, uses controller host user
@ -121,15 +130,15 @@
dest: "{{ local_path.stat.path }}/{{ keycloak.bundle }}"
no_log: "{{ omit_rhn_output | default(true) }}"
delegate_to: localhost
run_once: yes
run_once: true
- name: Download rhsso archive from alternate location
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: yes
run_once: true
when:
- archive_path is defined
- archive_path.stat is defined
@ -151,29 +160,29 @@
dest: "{{ archive }}"
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
mode: 0640
mode: '0640'
register: new_version_downloaded
when:
- not archive_path.stat.exists
- local_archive_path.stat is defined
- local_archive_path.stat.exists
become: yes
become: true
- name: "Check target directory: {{ keycloak.home }}"
ansible.builtin.stat:
path: "{{ keycloak.home }}"
register: path_to_workdir
become: yes
become: true
- name: "Extract {{ keycloak_service_desc }} archive on target"
ansible.builtin.unarchive:
remote_src: yes
remote_src: true
src: "{{ archive }}"
dest: "{{ keycloak_dest }}"
creates: "{{ keycloak.home }}"
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
become: yes
become: true
when:
- new_version_downloaded.changed or not path_to_workdir.stat.exists
notify:
@ -191,7 +200,13 @@
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
recurse: true
become: yes
become: true
changed_when: false
- name: Ensure permissions are correct on existing deploy
ansible.builtin.command: chown -R "{{ keycloak_service_user }}:{{ keycloak_service_group }}" "{{ keycloak.home }}"
when: keycloak_service_runas
become: true
changed_when: false
# driver and configuration
@ -199,17 +214,31 @@
ansible.builtin.include_tasks: jdbc_driver.yml
when: keycloak_jdbc[keycloak_jdbc_engine].enabled
- name: "Deploy {{ keycloak.service_name }} config to {{ keycloak_config_path_to_standalone_xml }} from {{ keycloak.config_template_source }}"
become: yes
- name: "Deploy custom {{ keycloak.service_name }} config to {{ keycloak_config_path_to_standalone_xml }} from {{ keycloak_config_override_template }}"
become: true
ansible.builtin.template:
src: "templates/{{ keycloak.config_template_source }}"
src: "templates/{{ keycloak_config_override_template }}"
dest: "{{ keycloak_config_path_to_standalone_xml }}"
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
mode: 0640
mode: '0640'
notify:
- restart keycloak
when: not keycloak_remotecache.enabled or keycloak_config_override_template | length > 0
when: keycloak_config_override_template | length > 0
- name: "Deploy standalone {{ keycloak.service_name }} config to {{ keycloak_config_path_to_standalone_xml }}"
become: true
ansible.builtin.template:
src: templates/standalone.xml.j2
dest: "{{ keycloak_config_path_to_standalone_xml }}"
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
mode: '0640'
notify:
- restart keycloak
when:
- not keycloak_ha_enabled
- keycloak_config_override_template | length == 0
- name: Create tcpping cluster node list
ansible.builtin.set_fact:
@ -218,21 +247,51 @@
{
"name": item,
"address": 'jgroups-' + item,
"inventory_host": hostvars[item].ansible_default_ipv4.address | default(item) + '[' + keycloak_jgroups_port + ']',
"inventory_host": hostvars[item].ansible_default_ipv4.address | default(item) + '[' + (keycloak_jgroups_port | string) + ']',
"value": hostvars[item].ansible_default_ipv4.address | default(item)
}
] }}
loop: "{{ ansible_play_batch }}"
loop: "{{ ansible_play_batch }}"
when: keycloak_ha_enabled and keycloak_ha_discovery == 'TCPPING'
- name: "Deploy {{ keycloak.service_name }} config with remote cache store to {{ keycloak_config_path_to_standalone_xml }}"
become: yes
- name: "Deploy HA {{ keycloak.service_name }} config to {{ keycloak_config_path_to_standalone_xml }}"
become: true
ansible.builtin.template:
src: templates/standalone-ha.xml.j2
dest: "{{ keycloak_config_path_to_standalone_xml }}"
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
mode: '0640'
notify:
- restart keycloak
when:
- keycloak_ha_enabled
- not keycloak_remote_cache_enabled
- keycloak_config_override_template | length == 0
- name: "Deploy HA {{ keycloak.service_name }} config with infinispan remote cache store to {{ keycloak_config_path_to_standalone_xml }}"
become: true
ansible.builtin.template:
src: templates/standalone-infinispan.xml.j2
dest: "{{ keycloak_config_path_to_standalone_xml }}"
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
mode: 0640
mode: '0640'
notify:
- restart keycloak
when: keycloak_remotecache.enabled
when:
- keycloak_ha_enabled
- keycloak_remote_cache_enabled
- keycloak_config_override_template | length == 0
- name: "Deploy profile.properties file to {{ keycloak_config_path_to_properties }}"
become: true
ansible.builtin.template:
src: keycloak-profile.properties.j2
dest: "{{ keycloak_config_path_to_properties }}"
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
mode: '0640'
notify:
- restart keycloak
when: keycloak_features | length > 0

View file

@ -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 }}"

View file

@ -3,19 +3,26 @@
ansible.builtin.stat:
path: "{{ keycloak_jdbc[keycloak_jdbc_engine].driver_module_dir }}"
register: dest_path
become: yes
become: true
- name: "Set up module dir for JDBC Driver {{ keycloak_jdbc[keycloak_jdbc_engine].driver_module_name }}"
ansible.builtin.file:
path: "{{ keycloak_jdbc[keycloak_jdbc_engine].driver_module_dir }}"
state: directory
recurse: yes
recurse: true
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
mode: 0750
become: yes
mode: '0750'
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,8 +30,11 @@
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 }}"
mode: 0640
become: yes
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
- name: "Deploy module.xml for JDBC Driver"
ansible.builtin.template:
@ -32,5 +42,5 @@
dest: "{{ keycloak_jdbc[keycloak_jdbc_engine].driver_module_dir }}/module.xml"
group: "{{ keycloak_service_group }}"
owner: "{{ keycloak_service_user }}"
mode: 0640
become: yes
mode: '0640'
become: true

View file

@ -5,11 +5,10 @@
tags:
- prereqs
- name: Include firewall config tasks
ansible.builtin.include_tasks: firewalld.yml
when: keycloak_configure_firewalld
- name: Distro specific tasks
ansible.builtin.include_tasks: "{{ ansible_os_family | lower }}.yml"
tags:
- firewall
- unbound
- name: Include install tasks
ansible.builtin.include_tasks: install.yml
@ -26,6 +25,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
@ -34,8 +34,8 @@
ansible.builtin.file:
state: link
src: "{{ keycloak_jboss_home }}/standalone/log"
dest: /var/log/keycloak
become: yes
dest: "{{ keycloak_log_target }}"
become: true
- name: Set admin credentials and restart if not already created
block:
@ -44,7 +44,7 @@
url: "{{ keycloak_url }}/auth/realms/master/protocol/openid-connect/token"
method: POST
body: "client_id={{ keycloak_auth_client }}&username={{ keycloak_admin_user }}&password={{ keycloak_admin_password }}&grant_type=password"
validate_certs: no
validate_certs: false
register: keycloak_auth_response
until: keycloak_auth_response.status == 200
retries: 2
@ -58,8 +58,8 @@
- "-rmaster"
- "-u{{ keycloak_admin_user }}"
- "-p{{ keycloak_admin_password }}"
changed_when: yes
become: yes
changed_when: true
become: true
- name: "Restart {{ keycloak.service_name }}"
ansible.builtin.include_tasks: tasks/restart_keycloak.yml
- name: "Wait until {{ keycloak.service_name }} becomes active {{ keycloak.health_url }}"

View file

@ -3,15 +3,18 @@
ansible.builtin.assert:
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"
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
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)
quiet: True
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' }}"
@ -20,27 +23,36 @@
that:
- (rhn_username is defined and sso_enable is defined and sso_enable) or not sso_enable is defined or not sso_enable or keycloak_offline_install
- (rhn_password is defined and sso_enable is defined and sso_enable) or not sso_enable is defined or not sso_enable or keycloak_offline_install
quiet: True
quiet: true
fail_msg: "Cannot install Red Hat SSO without RHN credentials. Check rhn_username and rhn_password are defined"
success_msg: "Installing {{ keycloak_service_desc }}"
- name: Validate persistence configuration
ansible.builtin.assert:
that:
- keycloak_jdbc_engine is defined and keycloak_jdbc_engine in [ 'postgres', 'mariadb' ]
- keycloak_jdbc_engine is defined and keycloak_jdbc_engine in [ 'postgres', 'mariadb', 'sqlserver' ]
- keycloak_jdbc_url | length > 0
- keycloak_db_user | length > 0
- keycloak_db_pass | length > 0
quiet: True
quiet: true
fail_msg: "Configuration for the JDBC persistence is invalid or incomplete"
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
- initscripts
packages_list: "{{ keycloak_prereq_package_list }}"

View file

@ -0,0 +1,6 @@
---
- name: Include firewall config tasks
ansible.builtin.include_tasks: firewalld.yml
when: keycloak_configure_firewalld
tags:
- firewall

View file

@ -2,11 +2,12 @@
- name: "Restart and enable {{ keycloak.service_name }} service"
ansible.builtin.systemd:
name: keycloak
enabled: yes
enabled: true
state: restarted
become: yes
daemon_reload: true
become: true
delegate_to: "{{ ansible_play_hosts | first }}"
run_once: True
run_once: true
- name: "Wait until {{ keycloak.service_name }} becomes active {{ keycloak.health_url }}"
ansible.builtin.uri:
@ -14,14 +15,14 @@
register: keycloak_status
until: keycloak_status.status == 200
delegate_to: "{{ ansible_play_hosts | first }}"
run_once: True
run_once: true
retries: "{{ keycloak_service_start_retries }}"
delay: "{{ keycloak_service_start_delay }}"
- name: "Restart and enable {{ keycloak.service_name }} service"
ansible.builtin.systemd:
name: keycloak
enabled: yes
enabled: true
state: restarted
become: yes
become: true
when: inventory_hostname != ansible_play_hosts | first

View file

@ -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
register: cli_result

View file

@ -3,6 +3,8 @@
- name: Set download patch archive path
ansible.builtin.set_fact:
patch_archive: "{{ keycloak_dest }}/{{ sso_patch_bundle }}"
patch_bundle: "{{ sso_patch_bundle }}"
patch_version: "{{ sso_patch_version }}"
when: sso_patch_version is defined
- name: Check download patch archive path
@ -10,10 +12,11 @@
path: "{{ patch_archive }}"
register: patch_archive_path
when: sso_patch_version is defined
become: true
- name: Perform patch download from RHN via JBossNetwork API
delegate_to: localhost
run_once: yes
run_once: true
when:
- sso_enable is defined and sso_enable
- not keycloak_offline_install
@ -29,21 +32,23 @@
register: rhn_products
no_log: "{{ omit_rhn_output | default(true) }}"
delegate_to: localhost
run_once: yes
run_once: true
- name: Determine patch versions list
set_fact:
filtered_versions: "{{ rhn_products.results | map(attribute='file_path') | select('match', '^[^/]*/rh-sso-.*[0-9]*[.][0-9]*[.][0-9]*.*$') | map('regex_replace','[^/]*/rh-sso-([0-9]*[.][0-9]*[.][0-9]*)-.*','\\1' ) | list | unique }}"
ansible.builtin.set_fact:
filtered_versions: "{{ rhn_products.results | map(attribute='file_path') | \
select('match', '^[^/]*/rh-sso-.*[0-9]*[.][0-9]*[.][0-9]*.*$') | \
map('regex_replace', '[^/]*/rh-sso-([0-9]*[.][0-9]*[.][0-9]*(-[0-9])?)-.*', '\\1') | list | unique }}"
when: sso_patch_version is not defined or sso_patch_version | length == 0
delegate_to: localhost
run_once: yes
run_once: true
- name: Determine latest version
set_fact:
sso_latest_version: "{{ filtered_versions | middleware_automation.keycloak.version_sort | last }}"
ansible.builtin.set_fact:
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: yes
run_once: true
- name: Determine install zipfile from search results
ansible.builtin.set_fact:
@ -52,26 +57,26 @@
patch_version: "{{ sso_latest_version }}"
when: sso_patch_version is not defined or sso_patch_version | length == 0
delegate_to: localhost
run_once: yes
run_once: true
- name: "Determine selected patch from supplied version: {{ sso_patch_version }}"
set_fact:
ansible.builtin.set_fact:
rhn_filtered_products: "{{ rhn_products.results | selectattr('file_path', 'match', '[^/]*/' + sso_patch_bundle + '$') }}"
patch_bundle: "{{ sso_patch_bundle }}"
patch_version: "{{ sso_patch_version }}"
when: sso_patch_version is defined
delegate_to: localhost
run_once: yes
run_once: true
- name: Download Red Hat Single Sign-On patch
middleware_automation.common.product_download: # noqa risky-file-permissions delegated, uses controller host user
client_id: "{{ rhn_username }}"
client_secret: "{{ rhn_password }}"
product_id: "{{ (rhn_filtered_products | first).id }}"
product_id: "{{ (rhn_filtered_products | sort | last).id }}"
dest: "{{ local_path.stat.path }}/{{ patch_bundle }}"
no_log: "{{ omit_rhn_output | default(true) }}"
delegate_to: localhost
run_once: yes
run_once: true
- name: Set download patch archive path
ansible.builtin.set_fact:
@ -81,7 +86,7 @@
ansible.builtin.stat:
path: "{{ patch_archive }}"
register: patch_archive_path
become: yes
become: true
## copy and unpack
- name: Copy patch archive to target nodes
@ -90,48 +95,48 @@
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
- local_archive_path.stat is defined
- local_archive_path.stat.exists
become: yes
become: true
- name: "Check installed patches"
ansible.builtin.include_tasks: rhsso_cli.yml
vars:
query: "patch info"
cli_query: "patch info"
args:
apply:
become: yes
become: true
become_user: "{{ keycloak_service_user }}"
- name: "Perform patching"
when:
- cli_result is defined
- cli_result.stdout is defined
- patch_version not in cli_result.stdout
- patch_version | regex_replace('-[0-9]$', '') not in cli_result.stdout
block:
- 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: yes
become: true
become_user: "{{ keycloak_service_user }}"
- 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:
apply:
become: yes
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:
@ -144,11 +149,11 @@
- name: "Query installed patch after restart"
ansible.builtin.include_tasks: rhsso_cli.yml
vars:
query: "patch info"
cli_query: "patch info"
args:
apply:
become: yes
become_user: "{{ keycloak_service_user }}"
become: true
become_user: "{{ keycloak_service_user }}"
- name: "Verify installed patch version"
ansible.builtin.assert:

View file

@ -2,9 +2,10 @@
- name: "Start {{ keycloak.service_name }} service"
ansible.builtin.systemd:
name: keycloak
enabled: yes
enabled: true
state: started
become: yes
daemon_reload: true
become: true
- name: "Wait until {{ keycloak.service_name }} becomes active {{ keycloak.health_url }}"
ansible.builtin.uri:

View file

@ -2,6 +2,6 @@
- name: "Stop {{ keycloak.service_name }}"
ansible.builtin.systemd:
name: keycloak
enabled: yes
enabled: true
state: stopped
become: yes
become: true

View file

@ -1,34 +1,23 @@
---
- name: "Configure {{ keycloak.service_name }} service script wrapper"
become: yes
become: true
ansible.builtin.template:
src: keycloak-service.sh.j2
dest: "{{ keycloak_dest }}/keycloak-service.sh"
owner: root
group: root
mode: 0755
mode: '0755'
notify:
- restart keycloak
- name: Determine JAVA_HOME for selected JVM RPM # noqa blocked_modules
ansible.builtin.shell: |
set -o pipefail
rpm -ql {{ keycloak_jvm_package }} | grep -Po '/usr/lib/jvm/.*(?=/bin/java$)'
args:
executable: /bin/bash
changed_when: False
register: rpm_java_home
- name: "Configure sysconfig file for {{ keycloak.service_name }} service"
become: yes
become: true
ansible.builtin.template:
src: keycloak-sysconfig.j2
dest: /etc/sysconfig/keycloak
dest: "{{ keycloak_sysconf_file }}"
owner: root
group: root
mode: 0644
vars:
keycloak_rpm_java_home: "{{ rpm_java_home.stdout }}"
mode: '0644'
notify:
- restart keycloak
@ -38,21 +27,15 @@
dest: /etc/systemd/system/keycloak.service
owner: root
group: root
mode: 0644
become: yes
mode: '0644'
become: true
register: systemdunit
notify:
- restart keycloak
- name: Reload systemd
become: yes
ansible.builtin.systemd:
daemon_reload: yes
when: systemdunit.changed
- name: "Start and wait for {{ keycloak.service_name }} service (first node db)"
ansible.builtin.include_tasks: start_keycloak.yml
run_once: yes
run_once: true
when: keycloak_db_enabled
- name: "Start and wait for {{ keycloak.service_name }} service (remaining nodes)"
@ -61,7 +44,7 @@
- name: Check service status
ansible.builtin.command: "systemctl status keycloak"
register: keycloak_service_status
changed_when: False
changed_when: false
- name: Verify service status
ansible.builtin.assert:

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- {{ ansible_managed }} -->
{{ ansible_managed | comment('xml') }}
<server xmlns="urn:jboss:domain:16.0">
<extensions>
<extension module="org.jboss.as.clustering.infinispan"/>
@ -631,7 +631,7 @@
</mail-session>
</subsystem>
<subsystem xmlns="urn:wildfly:metrics:1.0" security-enabled="false" exposed-subsystems="*" prefix="${wildfly.metrics.prefix:jboss}"/>
{% if keycloak_modcluster.enabled %}
{% if keycloak_modcluster.enabled %}
<subsystem xmlns="urn:jboss:domain:modcluster:5.0">
<proxy name="default" advertise="false" listener="ajp" proxies="proxy1">
<dynamic-load-provider>
@ -639,7 +639,7 @@
</dynamic-load-provider>
</proxy>
</subsystem>
{% endif %}
{% endif %}
<subsystem xmlns="urn:jboss:domain:naming:2.0">
<remote-naming/>
</subsystem>
@ -728,7 +728,7 @@
</interface>
<interface name="jgroups">
{% if ansible_default_ipv4 is defined %}
<subnet-match value="{{ (ansible_default_ipv4.network + '/' + ansible_default_ipv4.netmask) | ipaddr('net') }}"/>
<subnet-match value="{{ (ansible_default_ipv4.network + '/' + ansible_default_ipv4.netmask) | ansible.utils.ipaddr('net') }}"/>
{% else %}
<any-address />
{% endif %}
@ -737,7 +737,7 @@
<inet-address value="{{ keycloak_bind_address }}"/>
</interface>
</interfaces>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:{{ keycloak_jboss_port_offset }}}">
<socket-binding name="ajp" port="{{ keycloak_ajp_port }}"/>
<socket-binding name="http" port="{{ keycloak_http_port }}"/>
<socket-binding name="https" port="{{ keycloak_https_port }}"/>

View file

@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- {{ ansible_managed }} -->
{{ ansible_managed | comment('xml') }}
<server xmlns="urn:jboss:domain:16.0">
<extensions>
<extension module="org.jboss.as.clustering.infinispan"/>
@ -638,7 +638,7 @@
<inet-address value="{{ keycloak_bind_address }}"/>
</interface>
</interfaces>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:{{ keycloak_jboss_port_offset }}}">
<socket-binding name="ajp" port="{{ keycloak_ajp_port }}"/>
<socket-binding name="http" port="{{ keycloak_http_port }}"/>
<socket-binding name="https" port="{{ keycloak_https_port }}"/>

View file

@ -725,7 +725,7 @@
</interface>
<interface name="jgroups">
{% if ansible_default_ipv4 is defined %}
<subnet-match value="{{ (ansible_default_ipv4.network + '/' + ansible_default_ipv4.netmask) | ipaddr('net') }}"/>
<subnet-match value="{{ (ansible_default_ipv4.network + '/' + ansible_default_ipv4.netmask) | ansible.utils.ipaddr('net') }}"/>
{% else %}
<any-address />
{% endif %}
@ -734,7 +734,7 @@
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
</interface>
</interfaces>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:{{ keycloak_jboss_port_offset }}}">
<socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
<socket-binding name="http" port="${jboss.http.port:8080}"/>
<socket-binding name="https" port="${jboss.https.port:8443}"/>

View file

@ -598,7 +598,7 @@
<inet-address value="${jboss.bind.address:127.0.0.1}"/>
</interface>
</interfaces>
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:{{ keycloak_jboss_port_offset }}}">
<socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
<socket-binding name="http" port="${jboss.http.port:8080}"/>
<socket-binding name="https" port="${jboss.https.port:8443}"/>

Some files were not shown because too many files have changed in this diff Show more