Compare commits

..

13 Commits

Author SHA1 Message Date
Guido Grazioli
d5bf0a195a docs: fix typo 2022-03-11 15:31:48 +01:00
Guido Grazioli
c5b38e8bac docs: add testing and releasing contributor pages 2022-03-11 15:15:18 +01:00
Guido Grazioli
266f2bc00b Bump to v1.0.1 2022-03-11 15:11:21 +01:00
Guido Grazioli
cfdc043770 Update docs, fix patch apply steps and cli vars 2022-03-11 15:03:55 +01:00
Guido Grazioli
707d8cfb11 add rhsso_cli tasks, change shape of rhsso_rhn_ids 2022-03-11 15:03:55 +01:00
Guido Grazioli
f5cd6d8061 Merge pull request #17 from guidograzioli/replace_serial_with_runonce
Replace use of serial with run_once
2022-03-08 12:32:54 +01:00
Guido Grazioli
b88c43933c Replace use of serial with run_once
run_once on first node when database config enabled (so the first
node creates the tables), then wakeup all other nodes
2022-03-08 12:08:40 +01:00
Guido Grazioli
0bc81cc781 chore: add build ignores / fix release tag names 2022-03-01 19:05:28 +01:00
Guido Grazioli
60c5a42ae4 Merge pull request #16 from hcherukuri/main
Bump version to 1.0.0 to satisfy Automation hub
2022-03-01 19:00:38 +01:00
Harsha Cherukuri
2073c90e1d Bump version to 1.0.0 to statisfy Automation hub 2022-03-01 12:44:09 -05:00
Harsha Cherukuri
ffd146d392 Merge pull request #15 from guidograzioli/fqcn-builtins
fix: use FQCN
2022-03-01 12:42:09 -05:00
Guido Grazioli
78f225b10c chore: reword collection tags not accepted by galaxy 2022-03-01 10:46:06 +01:00
Guido Grazioli
b90684a44a fix: use FQCN 2022-02-24 15:00:10 +01:00
38 changed files with 394 additions and 117 deletions

View File

@@ -5,7 +5,7 @@ on:
branches:
- main
tags:
- "*.*.*"
- "[0-9]+.[0-9]+.[0-9]+"
env:
COLORTERM: 'yes'

View File

@@ -1,9 +1,9 @@
---
name: Release collection
on:
push:
tags:
- "*.*.*"
- "[0-9]+.[0-9]+.[0-9]+"
jobs:
release:
@@ -31,7 +31,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
files: "*.tar.gz"
body: "Release ${{ steps.get_version.outputs.TAG_VERSION }}"
body: "Release v${{ steps.get_version.outputs.TAG_VERSION }}"
- name: Publish collection
env:
ANSIBLE_GALAXY_API_KEY: ${{ secrets.ANSIBLE_GALAXY_API_KEY }}

View File

@@ -1,7 +1,7 @@
## Contributor's Guidelines
- All YAML files named with '.yml' extension
- All YAML files named with `.yml` extension
- Use spaces around jinja variables. `{{ var }}` over `{{var}}`
- Variables that are internal to the role should be lowercase and start with the role name
- Keep roles self contained - Roles should avoid including tasks from other roles when possible
@@ -11,4 +11,4 @@
- Indentation - Use 2 spaces for each indent
- `vars/` vs `defaults/` - internal or interpolated variables that don't need to change or be overridden by user go in `vars/`, those that a user would likely override, go under `defaults/` directory
- All role arguments have a specification in `meta/argument_specs.yml`
- All playbooks/roles should be focused on compatibility with Ansible Tower
- All playbooks/roles should be focused on compatibility with Ansible Automation Platform

View File

@@ -156,6 +156,9 @@ ansible-playbook -i <ansible_hosts> playbooks/keycloak_realm.yml -e keycloak_adm
For full configuration details, refer to the [keycloak_realm role README](roles/keycloak_realm/README.md).
## 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

View File

@@ -7,7 +7,7 @@
</div>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2022, Red Hat, Inc..</p>
<p>&#169; Copyright 2022, 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>

61
docs/releasing.md Normal file
View File

@@ -0,0 +1,61 @@
# Collection Versioning Strategy
Each supported collection maintained by Ansible follows Semantic Versioning 2.0.0 (https://semver.org/), for example:
Given a version number MAJOR.MINOR.PATCH, the following is incremented:
MAJOR version: when making incompatible API changes (see Feature Release scenarios below for examples)
MINOR version: when adding features or functionality in a backwards compatible manner, or updating testing matrix and/or metadata (deprecation)
PATCH version: when adding backwards compatible bug fixes or security fixes (strict).
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
The first version of a generally available supported collection on Ansible Automation Hub shall be version 1.0.0. NOTE: By default, all newly created collections may begin with a smaller default version of 0.1.0, and therefore a version of 1.0.0 should be explicitly stated by the collection maintainer.
## New content is added to an existing collection
Assuming the current release is 1.0.0, and a new module is ready to be added to the collection, the minor version would be incremented to 1.1.0. The change in the MINOR version indicates an additive change was made while maintaining backward compatibility for existing content within the collection.
## New feature to existing plugin or role within a collection (backwards compatible)
Assuming the current release is 1.0.0, and new features for an existing module are ready for release . We would increment the MINOR version to 1.1.0. The change in the MINOR version indicates an additive change was made while maintaining backward compatibility for existing content within the collection.
## Bug fix or security fix to existing content within a collection
Assuming the current release is 1.0.0 and a bug is fixed prior to the next minor release, the PATCH version would be incremented to 1.0.1. The patch indicates only a bug was fixed within a current version. The PATCH release does not contain new content, nor was functionality removed. Bug fixes may be included in a MINOR or MAJOR feature release if the timing allows, eliminating the need for a PATCH dedicated to the fix.
## Breaking change to any content within a collection
Assuming the current release is 1.0.0, and a breaking change (API or module) is introduced for a user or developer. The MAJOR version would be incremented to 2.0.0.
Examples of breaking changes within a collection may include but are not limited to:
- Argspec changes for a module that require either inventory structure or playbook changes.
- A change in the shape of either the inbound or returned payload of a filter plugin.
- Changes to a connection plugin that require additional inventory parameters or ansible.cfg entries.
- New functionality added to a module that changes the outcome of that module as released in previous versions.
- The removal of plugins from a collection.
## Content removed from a collection
Deleting a module or API is a breaking change. Please see the 'Breaking change' section for how to version this.
## A typographical error was fixed in the documentation for a collection
A correction to the README would be considered a bug fix and the PATCH incremented. See 'Bug fix' above.
## Documentation added/removed/modified within a collection
Only the PATCH version should be increased for a release that contains changes limited to revised documentation.
## Release automation
New releases are triggered by annotated git tags named after semantic versioning. The automation publishes the built artifacts to ansible-galaxy and github releases page.

49
docs/testing.md Normal file
View File

@@ -0,0 +1,49 @@
# Testing
## Continuous integration
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.
## Test playbooks
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
# create inventory for localhost
cat << EOF > inventory
[keycloak]
localhost ansible_connection=local
EOF
# run the playbook
ansible-playbook -i inventory playbooks/keycloak.yml
```

View File

@@ -1,6 +1,7 @@
---
namespace: middleware_automation
name: keycloak
version: "0.2.5"
version: "1.0.1"
readme: README.md
authors:
- Romain Pelisse <rpelisse@redhat.com>
@@ -12,9 +13,10 @@ tags:
- keycloak
- redhat
- rhel
- rhn
- sso
- single sign-on
- openid
- application
- identity
- security
- infrastructure
- authentication
@@ -25,3 +27,7 @@ repository: https://github.com/ansible-middleware/keycloak
documentation: https://ansible-middleware.github.io/keycloak
homepage: https://github.com/ansible-middleware/keycloak
issues: https://github.com/ansible-middleware/keycloak/issues
build_ignore:
- molecule
- docs
- .github

View File

@@ -3,10 +3,10 @@
hosts: all
tasks:
- name: Disable beta repos
command: yum config-manager --disable '*beta*'
ansible.builtin.command: yum config-manager --disable '*beta*'
ignore_errors: yes
- name: Install sudo
yum:
ansible.builtin.yum:
name: sudo
state: present

View File

@@ -5,6 +5,6 @@
- name: Populate service facts
ansible.builtin.service_facts:
- name: Check if keycloak service started
assert:
ansible.builtin.assert:
that:
- ansible_facts.services["keycloak.service"]["state"] == "running"

View File

@@ -5,7 +5,7 @@
- middleware_automation.keycloak
tasks:
- name: Include keycloak role
include_role:
name: keycloak
ansible.builtin.include_role:
name: middleware_automation.keycloak.keycloak
vars:
keycloak_admin_password: "changeme"

View File

@@ -3,8 +3,8 @@
hosts: keycloak
tasks:
- name: Keycloak Realm Role
include_role:
name: keycloak_realm
ansible.builtin.include_role:
name: middleware_automation.keycloak.keycloak_realm
vars:
keycloak_admin_password: "changeme"
keycloak_realm: TestRealm

View File

@@ -4,11 +4,11 @@
collections:
- middleware_automation.redhat_csp_download
roles:
- redhat_csp_download
- middleware_automation.redhat_csp_download.redhat_csp_download
tasks:
- name: Keycloak Role
include_role:
name: keycloak
ansible.builtin.include_role:
name: middleware_automation.keycloak.keycloak
vars:
keycloak_admin_password: "changeme"
keycloak_rhsso_enable: True

View File

@@ -31,6 +31,17 @@ Versions
|`7.5.0 GA` |September 20, 2021 |`15.0.2` | `7.4.0` |[Release Notes](https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.5/html/release_notes/index)|
Patching
--------
When variable `keycloak_rhsso_apply_patches` is `True` (default: `True`), the role will automatically apply the latest cumulative patch for the selected base version.
| RH-SSO VERSION | Release Date | RH-SSO LATEST CP | Notes |
|:---------------|:------------------|:-----------------|:----------------|
|`7.5.0 GA` |January 20, 2022 |`7.5.1 GA` |[Release Notes](https://access.redhat.com/articles/6646321)|
Role Defaults
-------------
@@ -62,15 +73,17 @@ Role Defaults
| Variable | Description | Default |
|:---------|:------------|:---------|
|`keycloak_rhsso_enable`| Enable Red Hat Single Sign-on installation | `False` |
|`keycloak_rhsso_enable`| Enable Red Hat Single Sign-on installation | `False` |
|`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_rhsso_download_url`| Download URL for RHSSO | `https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=<productID>`|
|`keycloak_version`| keycloak.org package version | `15.0.2` |
|`keycloak_rhsso_version`| RHSSO version | `7.5.0` |
|`keycloak_rhsso_apply_patches`| Install RHSSO more recent cumulative patch | `True` |
|`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_rhn_url` | Base download URI for customer portal | `https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=` |
|`keycloak_configure_firewalld` | Ensure firewalld is running and configure keycloak ports | `False` |
* Miscellaneous configuration
@@ -91,7 +104,7 @@ Role Defaults
|`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 }}` |
|`rhsso_rhn_id` | Customer Portal product ID for Red Hat SSO | `{{ rhsso_rhn_ids[keycloak_rhsso_version] }}` |
|`rhsso_rhn_id` | Customer Portal product ID for Red Hat SSO | `{{ rhsso_rhn_ids[keycloak_rhsso_version].id }}` |
Role Variables

View File

@@ -8,11 +8,12 @@ keycloak_installdir: "{{ keycloak_dest }}/keycloak-{{ keycloak_version }}"
### Configuration specific to Red Hat Single Sing-On
keycloak_rhsso_version: 7.5.0
rhsso_rhn_id: "{{ rhsso_rhn_ids[keycloak_rhsso_version] }}"
rhsso_rhn_id: "{{ rhsso_rhn_ids[keycloak_rhsso_version].id }}"
keycloak_rhsso_archive: "rh-sso-{{ keycloak_rhsso_version }}-server-dist.zip"
keycloak_rhsso_installdir: "{{ keycloak_dest }}/rh-sso-{{ keycloak_rhsso_version | regex_replace('^([0-9])\\.([0-9]*).*', '\\1.\\2') }}"
keycloak_rhn_url: 'https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId='
keycloak_rhsso_download_url: "{{ keycloak_rhn_url }}{{ rhsso_rhn_id }}"
keycloak_rhsso_apply_patches: True
### keycloak/rhsso choice: by default install rhsso if rhn credentials are defined
keycloak_rhsso_enable: "{{ True if rhsso_rhn_id is defined and rhn_username is defined and rhn_password is defined else False }}"
@@ -29,6 +30,7 @@ keycloak_config_path_to_standalone_xml: "{{ keycloak_jboss_home }}/standalone/co
keycloak_service_user: keycloak
keycloak_service_group: keycloak
keycloak_service_pidfile: "/run/keycloak.pid"
keycloak_configure_firewalld: False
### Common configuration settings
keycloak_bind_address: 0.0.0.0

View File

@@ -1,3 +1,3 @@
---
- name: restart keycloak
include_tasks: restart_keycloak.yml
ansible.builtin.include_tasks: restart_keycloak.yml

View File

@@ -11,6 +11,11 @@ argument_specs:
default: "keycloak-{{ keycloak_version }}.zip"
description: "keycloak install archive filename"
type: "str"
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 }}"
@@ -33,7 +38,7 @@ argument_specs:
type: "str"
rhsso_rhn_id:
# line 11 of keycloak/defaults/main.yml
default: "{{ rhsso_rhn_ids[keycloak_rhsso_version] }}"
default: "{{ rhsso_rhn_ids[keycloak_rhsso_version].id }}"
description: "Customer Portal product ID for Red Hat SSO"
type: "str"
keycloak_rhsso_archive:
@@ -41,6 +46,11 @@ argument_specs:
default: "rh-sso-{{ keycloak_rhsso_version }}-server-dist.zip"
description: "ed Hat SSO install archive filename"
type: "str"
keycloak_rhsso_apply_patches:
# line 16 of keycloak/defaults/main.yml
default: true
description: "Install RHSSO more recent cumulative patch"
type: "bool"
keycloak_rhsso_installdir:
# line 13 of keycloak/defaults/main.yml
default: "{{ keycloak_dest }}/rh-sso-{{ keycloak_rhsso_version | regex_replace('^([0-9])\\.([0-9]*).*', '\\1.\\2') }}"

View File

@@ -1,7 +1,7 @@
---
- block:
- name: "Check if package {{ package_name }} is already installed"
command: rpm -q {{ package_name }}
ansible.builtin.command: rpm -q {{ package_name }}
args:
warn: no
register: rpm_info
@@ -9,6 +9,6 @@
rescue:
- name: "Add {{ package_name }} to the yum install list if missing"
set_fact:
ansible.builtin.set_fact:
packages_to_install: "{{ packages_to_install + [ package_name ] }}"
when: rpm_info.failed

View File

@@ -1,18 +1,18 @@
---
- name: Set facts
set_fact:
ansible.builtin.set_fact:
update_cache: true
packages_to_install: []
- name: "Check packages to be installed"
include_tasks: check.yml
ansible.builtin.include_tasks: check.yml
loop: "{{ packages_list | flatten }}"
loop_control:
loop_var: package_name
- name: "Install packages: {{ packages_to_install }}"
become: yes
yum:
ansible.builtin.yum:
name: "{{ packages_to_install }}"
state: present
when: packages_to_install | length > 0

View File

@@ -7,7 +7,7 @@
- name: Enable and start the firewalld service
become: yes
systemd:
ansible.builtin.systemd:
name: firewalld
enabled: yes
state: started

View File

@@ -1,6 +1,6 @@
---
- name: Validate parameters
assert:
ansible.builtin.assert:
that:
- keycloak_jboss_home is defined
- keycloak_service_user is defined
@@ -12,7 +12,7 @@
- name: Check for an existing deployment
become: yes
stat:
ansible.builtin.stat:
path: "{{ keycloak_jboss_home }}"
register: existing_deploy
@@ -20,24 +20,24 @@
- name: Stop the old keycloak service
become: yes
ignore_errors: yes
systemd:
ansible.builtin.systemd:
name: keycloak
state: stopped
- name: Remove the old Keycloak deployment
become: yes
file:
ansible.builtin.file:
path: "{{ keycloak_jboss_home }}"
state: absent
when: existing_deploy.stat.exists and keycloak_force_install|bool
- name: check for an existing deployment after possible forced removal
become: yes
stat:
ansible.builtin.stat:
path: "{{ keycloak_jboss_home }}"
- name: create Keycloak service user/group
become: yes
user:
ansible.builtin.user:
name: "{{ keycloak_service_user }}"
home: /opt/keycloak
system: yes
@@ -45,7 +45,7 @@
- name: create Keycloak install location
become: yes
file:
ansible.builtin.file:
dest: "{{ keycloak_dest }}"
state: directory
owner: "{{ keycloak_service_user }}"
@@ -54,23 +54,23 @@
## check remote archive
- name: Set download archive path
set_fact:
ansible.builtin.set_fact:
archive: "{{ keycloak_dest }}/{{ keycloak.bundle }}"
- name: Check download archive path
stat:
ansible.builtin.stat:
path: "{{ archive }}"
register: archive_path
## download to controller
- name: Check local download archive path
stat:
ansible.builtin.stat:
path: "{{ lookup('env', 'PWD') }}"
register: local_path
delegate_to: localhost
- name: Download keycloak archive
get_url:
ansible.builtin.get_url:
url: "{{ keycloak_download_url }}"
dest: "{{ local_path.stat.path }}/{{ keycloak.bundle }}"
delegate_to: localhost
@@ -82,7 +82,7 @@
- not keycloak_offline_install
- name: Perform download from RHN
redhat_csp_download:
middleware_automation.redhat_csp_download.redhat_csp_download:
url: "{{ keycloak_rhsso_download_url }}"
dest: "{{ local_path.stat.path }}/{{ keycloak.bundle }}"
username: "{{ rhn_username }}"
@@ -98,7 +98,7 @@
- keycloak_rhn_url in keycloak_rhsso_download_url
- name: Download rhsso archive from alternate location
get_url:
ansible.builtin.get_url:
url: "{{ keycloak_rhsso_download_url }}"
dest: "{{ local_path.stat.path }}/{{ keycloak.bundle }}"
delegate_to: localhost
@@ -111,14 +111,14 @@
- not keycloak_rhn_url in keycloak_rhsso_download_url
- name: Check downloaded archive
stat:
ansible.builtin.stat:
path: "{{ local_path.stat.path }}/{{ keycloak.bundle }}"
register: local_archive_path
delegate_to: localhost
## copy and unpack
- name: Copy archive to target nodes
copy:
ansible.builtin.copy:
src: "{{ local_path.stat.path }}/{{ keycloak.bundle }}"
dest: "{{ archive }}"
owner: "{{ keycloak_service_user }}"
@@ -132,13 +132,13 @@
become: yes
- name: "Check target directory: {{ keycloak.home }}"
stat:
ansible.builtin.stat:
path: "{{ keycloak.home }}"
register: path_to_workdir
become: yes
- name: "Extract {{ 'Red Hat Single Sign-On' if keycloak_rhsso_enable else 'Keycloak' }} archive on target"
unarchive:
ansible.builtin.unarchive:
remote_src: yes
src: "{{ archive }}"
dest: "{{ keycloak_dest }}"
@@ -152,13 +152,13 @@
- restart keycloak
- name: Inform decompression was not executed
debug:
ansible.builtin.debug:
msg: "{{ keycloak.home }} already exists and version unchanged, skipping decompression"
when:
- not new_version_downloaded.changed and path_to_workdir.stat.exists
- name: "Reown installation directory to {{ keycloak_service_user }}"
file:
ansible.builtin.file:
path: "{{ keycloak.home }}"
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
@@ -168,8 +168,8 @@
# driver and configuration
- name: "Install {{ keycloak_jdbc_engine }} driver"
include_role:
name: wildfly_driver
ansible.builtin.include_role:
name: middleware_automation.wildfly.wildfly_driver
vars:
wildfly_user: "{{ keycloak_service_user }}"
jdbc_driver_module_dir: "{{ keycloak_jdbc[keycloak_jdbc_engine].driver_module_dir }}"
@@ -182,7 +182,7 @@
- name: "Deploy {{ keycloak.service_name }} config to {{ keycloak_config_path_to_standalone_xml }}"
become: yes
template:
ansible.builtin.template:
src: templates/standalone.xml.j2
dest: "{{ keycloak_config_path_to_standalone_xml }}"
owner: "{{ keycloak_service_user }}"
@@ -194,7 +194,7 @@
- name: "Deploy {{ keycloak.service_name }} config with remote cache store to {{ keycloak_config_path_to_standalone_xml }}"
become: yes
template:
ansible.builtin.template:
src: templates/standalone-infinispan.xml.j2
dest: "{{ keycloak_config_path_to_standalone_xml }}"
owner: "{{ keycloak_service_user }}"

View File

@@ -2,25 +2,42 @@
# tasks file for keycloak
- name: Check prerequisites
include_tasks: prereqs.yml
ansible.builtin.include_tasks: prereqs.yml
tags:
- prereqs
- name: Include firewall config tasks
ansible.builtin.include_tasks: firewalld.yml
when: keycloak_configure_firewalld
tags:
- firewall
- name: Include install tasks
include_tasks: tasks/install.yml
ansible.builtin.include_tasks: install.yml
tags:
- install
- name: Include systemd tasks
include_tasks: tasks/systemd.yml
ansible.builtin.include_tasks: systemd.yml
tags:
- systemd
- name: Include patch install tasks
ansible.builtin.include_tasks: rhsso_patch.yml
when: keycloak_rhsso_apply_patches and keycloak_rhsso_enable
tags:
- install
- patch
- name: Link default logs directory
file:
ansible.builtin.file:
state: link
src: "{{ keycloak_jboss_home }}/standalone/log"
dest: /var/log/keycloak
- block:
- name: Check admin credentials by generating a token
uri:
ansible.builtin.uri:
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"
@@ -31,7 +48,7 @@
delay: 2
rescue:
- name: "Create {{ keycloak.service_name }} admin user"
command:
ansible.builtin.command:
args:
argv:
- "{{ keycloak_jboss_home }}/bin/add-user-keycloak.sh"
@@ -41,9 +58,9 @@
changed_when: yes
become: yes
- name: "Restart {{ keycloak.service_name }}"
include_tasks: tasks/restart_keycloak.yml
ansible.builtin.include_tasks: tasks/restart_keycloak.yml
- name: "Wait until {{ keycloak.service_name }} becomes active {{ keycloak.health_url }}"
uri:
ansible.builtin.uri:
url: "{{ keycloak.health_url }}"
register: keycloak_status
until: keycloak_status.status == 200

View File

@@ -1,6 +1,6 @@
---
- name: Validate configuration
assert:
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
@@ -8,7 +8,7 @@
success_msg: "{{ 'Configuring HA' if keycloak_ha_enabled else 'Configuring standalone' }}"
- name: Validate credentials
assert:
ansible.builtin.assert:
that:
- (rhn_username is defined and keycloak_rhsso_enable) or not keycloak_rhsso_enable or keycloak_offline_install
- (rhn_password is defined and keycloak_rhsso_enable) or not keycloak_rhsso_enable or keycloak_offline_install
@@ -17,7 +17,7 @@
success_msg: "{{ 'Installing Red Hat Single Sign-On' if keycloak_rhsso_enable else 'Installing keycloak.org' }}"
- name: Set required packages facts
set_fact:
ansible.builtin.set_fact:
required_packages:
- "{{ jvm_package }}"
- unzip

View File

@@ -1,6 +1,6 @@
---
- name: "Restart and enable keycloack service"
systemd:
ansible.builtin.systemd:
name: keycloak
enabled: yes
state: restarted

View File

@@ -0,0 +1,13 @@
---
- name: Ensure required params for CLI have been provided
ansible.builtin.assert:
that:
- query is defined
fail_msg: "Missing required parameters to execute CLI."
quiet: true
- name: "Execute CLI query: {{ query }}"
ansible.builtin.command: >
{{ keycloak.cli_path }} --connect --command='{{ query }}' --controller={{ keycloak_host }}:{{ keycloak_management_http_port }}
changed_when: false
register: cli_result

View File

@@ -0,0 +1,87 @@
---
## check remote patch archive
- name: Set download patch archive path
ansible.builtin.set_fact:
patch_archive: "{{ keycloak_dest }}/{{ keycloak.patch_bundle }}"
- name: Check download patch archive path
ansible.builtin.stat:
path: "{{ patch_archive }}"
register: patch_archive_path
- name: Perform download from RHN
middleware_automation.redhat_csp_download.redhat_csp_download:
url: "{{ keycloak_rhn_url }}{{ rhsso_rhn_ids[keycloak_rhsso_version].latest_cp.id }}"
dest: "{{ local_path.stat.path }}/{{ keycloak.patch_bundle }}"
username: "{{ rhn_username }}"
password: "{{ rhn_password }}"
no_log: "{{ omit_rhn_output | default(true) }}"
delegate_to: localhost
when:
- patch_archive_path is defined
- patch_archive_path.stat is defined
- not patch_archive_path.stat.exists
- keycloak_rhsso_enable
- not keycloak_offline_install
## copy and unpack
- name: Copy patch archive to target nodes
ansible.builtin.copy:
src: "{{ local_path.stat.path }}/{{ keycloak.patch_bundle }}"
dest: "{{ patch_archive }}"
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
mode: 0750
register: new_version_downloaded
when:
- not patch_archive_path.stat.exists
- local_archive_path.stat is defined
- local_archive_path.stat.exists
become: yes
- name: "Check installed patches"
ansible.builtin.include_tasks: rhsso_cli.yml
vars:
query: "patch info"
- name: "Perform patching"
when:
- cli_result is defined
- cli_result.stdout is defined
- rhsso_rhn_ids[keycloak_rhsso_version].latest_cp.v not in cli_result.stdout
block:
- name: "Apply patch {{ rhsso_rhn_ids[keycloak_rhsso_version].latest_cp.v }} to server"
ansible.builtin.include_tasks: rhsso_cli.yml
vars:
query: "patch apply {{ patch_archive }}"
- name: "Restart server to ensure patch content is running"
ansible.builtin.include_tasks: rhsso_cli.yml
vars:
query: "shutdown --restart"
when:
- cli_result.rc == 0
- name: "Wait until Keycloak becomes active {{ keycloak.health_url }}"
ansible.builtin.uri:
url: "{{ keycloak.health_url }}"
register: keycloak_status
until: keycloak_status.status == 200
retries: 25
delay: 10
- name: "Query installed patch after restart"
ansible.builtin.include_tasks: rhsso_cli.yml
vars:
query: "patch info"
- name: "Verify installed patch version"
ansible.builtin.assert:
that:
- rhsso_rhn_ids[keycloak_rhsso_version].latest_cp.v not in cli_result.stdout
fail_msg: "Patch installation failed"
success_msg: "Patch installation successful"
- name: "Skipping patch"
debug:
msg: "Latest cumulative patch {{ rhsso_rhn_ids[keycloak_rhsso_version].latest_cp.v }} already installed, skipping patch installation."

View File

@@ -0,0 +1,15 @@
---
- name: start keycloak
ansible.builtin.systemd:
name: keycloak
enabled: yes
state: started
become: yes
- name: "Wait until Keycloak becomes active {{ keycloak.health_url }}"
ansible.builtin.uri:
url: "{{ keycloak.health_url }}"
register: keycloak_status
until: keycloak_status.status == 200
retries: 25
delay: 10

View File

@@ -1,6 +1,6 @@
---
- name: "Stop SSO service"
systemd:
- name: Stop keycloak
ansible.builtin.systemd:
name: keycloak
enabled: yes
state: stopped

View File

@@ -1,6 +1,6 @@
- name: configure keycloak service script wrapper
- name: Configure keycloak service script wrapper
become: yes
template:
ansible.builtin.template:
src: keycloak-service.sh.j2
dest: "{{ keycloak_dest }}/keycloak-service.sh"
owner: root
@@ -9,9 +9,9 @@
notify:
- restart keycloak
- name: configure sysconfig file for keycloak service
- name: Configure sysconfig file for keycloak service
become: yes
template:
ansible.builtin.template:
src: keycloak-sysconfig.j2
dest: /etc/sysconfig/keycloak
owner: root
@@ -20,8 +20,8 @@
notify:
- restart keycloak
- name: configure systemd unit file for keycloak service
template:
- name: Configure systemd unit file for keycloak service
ansible.builtin.template:
src: keycloak.service.j2
dest: /etc/systemd/system/keycloak.service
owner: root
@@ -32,37 +32,30 @@
notify:
- restart keycloak
- name: reload systemd
- name: Reload systemd
become: yes
systemd:
ansible.builtin.systemd:
daemon_reload: yes
when: systemdunit.changed
- name: start keycloak
systemd:
name: keycloak
enabled: yes
state: started
become: yes
- name: Start and wait for keycloak service (first node db)
ansible.builtin.include_tasks: start_keycloak.yml
run_once: yes
when: keycloak_db_enabled
- name: Start and wait for keycloak service (remaining nodes)
ansible.builtin.include_tasks: start_keycloak.yml
- name: Check service status
command: "systemctl status keycloak"
ansible.builtin.command: "systemctl status keycloak"
register: keycloak_service_status
changed_when: False
- name: Verify service status
assert:
ansible.builtin.assert:
that:
- keycloak_service_status is defined
- keycloak_service_status.stdout is defined
- name: Flush handlers
meta: flush_handlers
- name: "Wait until Keycloak becomes active {{ keycloak.health_url }}"
uri:
url: "{{ keycloak.health_url }}"
register: keycloak_status
until: keycloak_status.status == 200
retries: 25
delay: 10
ansible.builtin.meta: flush_handlers

View File

@@ -633,7 +633,7 @@
<subsystem xmlns="urn:wildfly:metrics:1.0" security-enabled="false" exposed-subsystems="*" prefix="${wildfly.metrics.prefix:jboss}"/>
{% if keycloak_modcluster.enabled %}
<subsystem xmlns="urn:jboss:domain:modcluster:5.0">
<proxy name="default" advertise-socket="modcluster" listener="ajp" proxies="proxy1">
<proxy name="default" advertise="false" listener="ajp" proxies="proxy1">
<dynamic-load-provider>
<load-metric type="cpu"/>
</dynamic-load-provider>
@@ -726,7 +726,7 @@
<interface name="management">
<inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
</interface>
<interface name="jgroups">
<interface name="jgroups">
{% if ansible_default_ipv4 is defined %}
<subnet-match value="{{ (ansible_default_ipv4.network + '/' + ansible_default_ipv4.netmask) | ipaddr('net') }}"/>
{% else %}
@@ -744,7 +744,6 @@
<socket-binding name="management-http" interface="management" port="{{ keycloak_management_http_port }}"/>
<socket-binding name="management-https" interface="management" port="{{ keycloak_management_https_port }}"/>
<socket-binding name="jgroups-tcp" interface="jgroups" port="{{ keycloak_jgroups_port }}"/>
<socket-binding name="modcluster" multicast-address="${jboss.modcluster.multicast.address:224.0.1.105}" multicast-port="23364"/>
<socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/>
<outbound-socket-binding name="mail-smtp">

View File

@@ -546,7 +546,7 @@
<subsystem xmlns="urn:wildfly:metrics:1.0" security-enabled="false" exposed-subsystems="*" prefix="${wildfly.metrics.prefix:jboss}"/>
{% if keycloak_modcluster.enabled %}
<subsystem xmlns="urn:jboss:domain:modcluster:5.0">
<proxy name="default" advertise-socket="modcluster" listener="ajp" proxies="proxy1">
<proxy name="default" advertise="false" listener="ajp" proxies="proxy1">
<dynamic-load-provider>
<load-metric type="cpu"/>
</dynamic-load-provider>
@@ -644,7 +644,6 @@
<socket-binding name="https" port="{{ keycloak_https_port }}"/>
<socket-binding name="management-http" interface="management" port="{{ keycloak_management_http_port }}"/>
<socket-binding name="management-https" interface="management" port="{{ keycloak_management_https_port }}"/>
<socket-binding name="modcluster" multicast-address="${jboss.modcluster.multicast.address:224.0.1.105}" multicast-port="23364"/>
<socket-binding name="txn-recovery-environment" port="4712"/>
<socket-binding name="txn-status-manager" port="4713"/>
<outbound-socket-binding name="mail-smtp">

View File

@@ -5,8 +5,11 @@ keycloak_admin_password:
# internal variables below
rhsso_rhn_ids:
'7.5.0': '101971'
'7.5.1': '103836'
'7.5.0':
id: '101971'
latest_cp:
id: '103836'
v: '7.5.1'
# locations
keycloak_url: "http://{{ keycloak_host }}:{{ keycloak_http_port }}"
@@ -17,8 +20,10 @@ keycloak:
home: "{{ keycloak_jboss_home }}"
config_dir: "{{ keycloak_config_dir }}"
bundle: "{{ keycloak_rhsso_archive if keycloak_rhsso_enable else keycloak_archive }}"
patch_bundle: "rh-sso-{{ rhsso_rhn_ids[keycloak_rhsso_version].latest_cp.v }}-patch.zip"
service_name: "{{ 'rhsso' if keycloak_rhsso_enable else 'keycloak' }}"
health_url: "{{ keycloak_management_url }}/health"
cli_path: "{{ keycloak_jboss_home }}/bin/jboss-cli.sh"
# database
keycloak_jdbc:

View File

@@ -1,17 +1,18 @@
---
- name: Generate keycloak auth token
uri:
ansible.builtin.uri:
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
no_log: True
register: keycloak_auth_response
until: keycloak_auth_response.status == 200
retries: 5
delay: 2
- name: "Determine if realm exists"
uri:
ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}"
method: GET
status_code:
@@ -23,7 +24,7 @@
register: keycloak_realm_exists
- name: Create Realm
uri:
ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms"
method: POST
body: "{{ lookup('template','realm.json.j2') }}"
@@ -47,6 +48,7 @@
provider_type: "{{ item.provider_type | default(org.keycloak.storage.UserStorageProvider) }}"
config: "{{ item.config }}"
mappers: "{{ item.mappers | default(omit) }}"
no_log: True
register: create_user_federation_result
loop: "{{ keycloak_user_federation | flatten }}"
when: keycloak_user_federation is defined
@@ -78,19 +80,20 @@
public_client: "{{ item.public_client | default(False) }}"
protocol: "{{ item.protocol | default(omit) }}"
state: present
no_log: True
register: create_client_result
loop: "{{ keycloak_clients | flatten }}"
when: (item.name is defined and item.client_id is defined) or (item.name is defined and item.id is defined)
- name: Create client roles
include_tasks: manage_client_roles.yml
ansible.builtin.include_tasks: manage_client_roles.yml
loop: "{{ keycloak_clients | flatten }}"
loop_control:
loop_var: client
when: "'roles' in client"
- name: Create client users
include_tasks: manage_client_users.yml
ansible.builtin.include_tasks: manage_client_users.yml
loop: "{{ keycloak_clients | flatten }}"
loop_control:
loop_var: client

View File

@@ -10,3 +10,4 @@
auth_password: "{{ keycloak_admin_password }}"
state: present
loop: "{{ client.roles | flatten }}"
no_log: True

View File

@@ -1,12 +1,12 @@
---
- name: Manage Users
include_tasks: manage_user.yml
ansible.builtin.include_tasks: manage_user.yml
loop: "{{ client.users | flatten }}"
loop_control:
loop_var: user
- name: Manage User Roles
include_tasks: manage_user_roles.yml
ansible.builtin.include_tasks: manage_user_roles.yml
loop: "{{ client.users | flatten }}"
loop_control:
loop_var: user

View File

@@ -1,6 +1,6 @@
---
- name: "Check if User Already Exists"
uri:
ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users?username={{ user.username }}"
validate_certs: no
headers:
@@ -8,7 +8,7 @@
register: keycloak_user_search_result
- name: "Create User"
uri:
ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users"
method: POST
body:
@@ -26,7 +26,7 @@
when: keycloak_user_search_result.json | length == 0
- name: "Get User"
uri:
ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users?username={{ user.username }}"
validate_certs: no
headers:
@@ -34,7 +34,7 @@
register: keycloak_user
- name: "Update User Password"
uri:
ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users/{{ (keycloak_user.json | first).id }}/reset-password"
method: PUT
body:

View File

@@ -1,6 +1,6 @@
---
- name: "Get Realm for role"
uri:
ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ client_role.realm }}"
method: GET
status_code:
@@ -11,7 +11,7 @@
register: client_role_realm
- name: Check if Mapping is available
uri:
ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ client_role.realm }}/users/{{ (keycloak_user.json | first).id }}/role-mappings/clients/{{ (create_client_result.results | selectattr('end_state.clientId', 'equalto', client_role.client) | list | first).end_state.id }}/available"
method: GET
status_code:
@@ -22,7 +22,7 @@
register: client_role_user_available
- name: "Create Role Mapping"
uri:
ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ client_role.realm }}/users/{{ (keycloak_user.json | first).id }}/role-mappings/clients/{{ (create_client_result.results | selectattr('end_state.clientId', 'equalto', client_role.client) | list | first).end_state.id }}"
method: POST
body:

View File

@@ -1,6 +1,6 @@
---
- name: "Get User {{ user.username }}"
uri:
ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users?username={{ user.username }}"
headers:
validate_certs: no
@@ -8,18 +8,19 @@
register: keycloak_user
- name: Refresh keycloak auth token
uri:
ansible.builtin.uri:
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
register: keycloak_auth_response
no_log: True
until: keycloak_auth_response.status == 200
retries: 5
delay: 2
- name: "Manage Client Role Mapping for {{ user.username }}"
include_tasks: manage_user_client_roles.yml
ansible.builtin.include_tasks: manage_user_client_roles.yml
loop: "{{ user.client_roles | flatten }}"
loop_control:
loop_var: client_role