Merge pull request #29 from guidograzioli/quarkus

New role for installing keycloak >= 17.0.0 (quarkus)
main
Guido Grazioli 2022-04-11 14:03:47 +02:00 committed by GitHub
commit 548db6fc4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 916 additions and 16 deletions

View File

@ -43,6 +43,7 @@ A requirement file is provided to install:
* [`keycloak`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak/README.md): role for installing the service. * [`keycloak`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak/README.md): role for installing the service.
* [`keycloak_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_realm`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak_realm/README.md): role for configuring a realm, user federation(s), clients and users, in an installed service.
* [`keycloak_quarkus`](https://github.com/ansible-middleware/keycloak/blob/main/roles/keycloak_quarkus/README.md): role for installing the quarkus variant of keycloak (>= 17.0.0).
## Usage ## Usage

View File

@ -0,0 +1,39 @@
---
- name: Converge
hosts: all
vars:
keycloak_quarkus_admin_pass: "remembertochangeme"
keycloak_realm: TestRealm
roles:
- role: keycloak_quarkus
- role: keycloak_realm
keycloak_context: ''
keycloak_admin_password: "remembertochangeme"
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,53 @@
---
dependency:
name: shell
command: ansible-galaxy collection install -r molecule/default/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
pre_build_image: true
privileged: true
command: "/usr/sbin/init"
port_bindings:
- "8080/tcp"
- "8443/tcp"
- "8009/tcp"
provisioner:
name: ansible
config_options:
defaults:
interpreter_python: auto_silent
ssh_connection:
pipelining: false
playbooks:
prepare: prepare.yml
converge: converge.yml
verify: verify.yml
inventory:
host_vars:
localhost:
ansible_python_interpreter: "{{ ansible_playbook_python }}"
env:
ANSIBLE_FORCE_COLOR: "true"
verifier:
name: ansible
scenario:
test_sequence:
- dependency
- lint
- cleanup
- destroy
- syntax
- create
- prepare
- converge
- idempotence
- side_effect
- verify
- cleanup
- destroy

View File

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

View File

@ -0,0 +1,10 @@
---
collections:
- name: middleware_automation.redhat_csp_download
version: ">=1.2.1"
- name: middleware_automation.wildfly
version: ">=0.0.5"
- name: community.general
- name: community.docker
version: ">=1.9.1"

View File

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

View File

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

View File

@ -0,0 +1,101 @@
keycloak_quarkus
================
Install [keycloak](https://keycloak.org/) >= 17.0.0 (quarkus) server configurations.
Role Defaults
-------------
* Service configuration
| Variable | Description | Default |
|:---------|:------------|:--------|
|`keycloak_quarkus_ha_enabled`| Enable auto configuration for database backend, clustering and remote caches on infinispan | `False` |
|`keycloak_quarkus_db_enabled`| Enable auto configuration for database backend | `True` if `keycloak_quarkus_ha_enabled` is True, else `False` |
|`keycloak_quarkus_admin_user`| Administration console user account | `admin` |
|`keycloak_quarkus_bind_address`| Address for binding service ports | `0.0.0.0` |
|`keycloak_quarkus_host`| hostname | `localhost` |
|`keycloak_quarkus_http_port`| HTTP port | `8080` |
|`keycloak_quarkus_https_port`| TLS HTTP port | `8443` |
|`keycloak_quarkus_ajp_port`| AJP port | `8009` |
|`keycloak_quarkus_jgroups_port`| jgroups cluster tcp port | `7600` |
|`keycloak_quarkus_java_opts`| Additional JVM options | `-Xms1024m -Xmx2048m` |
|`keycloak_quarkus_service_user`| Posix account username | `keycloak` |
|`keycloak_quarkus_service_group`| Posix account group | `keycloak` |
|`keycloak_quarkus_service_pidfile`| Pid file path for service | `/run/keycloak.pid` |
|`keycloak_quarkus_jvm_package`| RHEL java package runtime | `java-11-openjdk-headless` |
|`keycloak_quarkus_frontend_url`| Service public URL | `http://localhost:8080/auth` |
|`keycloak_quarkus_http_relative_path` | Service context path | `auth` |
* Database configuration
| Variable | Description | Default |
|:---------|:------------|:--------|
|`keycloak_quarkus_jdbc_engine` | Database engine [mariadb,postres] | `postgres` |
|`keycloak_quarkus_db_user` | User for database connection | `keycloak-user` |
|`keycloak_quarkus_db_pass` | Password for database connection | `keycloak-pass` |
|`keycloak_quarkus_jdbc_url` | JDBC URL for connecting to database | `jdbc:postgresql://localhost:5432/keycloak` |
|`keycloak_quarkus_jdbc_driver_version` | Version for JDBC driver | `9.4.1212` |
* Remote caches configuration
| Variable | Description | Default |
|:---------|:------------|:--------|
|`keycloak_quarkus_ispn_user` | Username for connecting to infinispan | `supervisor` |
|`keycloak_quarkus_ispn_pass` | Password for connecting to infinispan | `supervisor` |
|`keycloak_quarkus_ispn_url` | URL for connecting to infinispan | `localhost` |
|`keycloak_quarkus_ispn_sasl_mechanism` | Infinispan auth mechanism | `SCRAM-SHA-512` |
|`keycloak_quarkus_ispn_use_ssl` | Whether infinispan uses TLS connection | `false` |
|`keycloak_quarkus_ispn_trust_store_path` | Path to infinispan server trust certificate | `/etc/pki/java/cacerts` |
|`keycloak_quarkus_ispn_trust_store_password` | Password for infinispan certificate keystore | `changeit` |
* Install options
| Variable | Description | Default |
|:---------|:------------|:---------|
|`keycloak_quarkus_offline_install` | Perform an offline install | `False`|
|`keycloak_quarkus_download_url`| Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/<version>/<archive>`|
|`keycloak_quarkus_version`| keycloak.org package version | `17.0.1` |
|`keycloak_quarkus_dest`| Installation root path | `/opt/keycloak` |
|`keycloak_quarkus_download_url` | Download URL for keycloak | `https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}` |
|`keycloak_quarkus_configure_firewalld` | Ensure firewalld is running and configure keycloak ports | `False` |
* Miscellaneous configuration
| Variable | Description | Default |
|:---------|:------------|:--------|
|`keycloak_quarkus_metrics_enabled`| Whether to enable metrics | `False` |
|`keycloak_quarkus_archive` | keycloak install archive filename | `keycloak-{{ keycloak_quarkus_version }}.zip` |
|`keycloak_quarkus_installdir` | Installation path | `{{ keycloak_quarkus_dest }}/keycloak-{{ keycloak_quarkus_version }}` |
|`keycloak_quarkus_home` | Installation work directory | `{{ keycloak_quarkus_installdir }}` |
|`keycloak_quarkus_config_dir` | Path for configuration | `{{ keycloak_quarkus_home }}/conf` |
|`keycloak_quarkus_master_realm` | Name for rest authentication realm | `master` |
|`keycloak_auth_client` | Authentication client for configuration REST calls | `admin-cli` |
|`keycloak_force_install` | Remove pre-existing versions of service | `False` |
|`keycloak_url` | URL for configuration rest calls | `http://{{ keycloak_quarkus_host }}:{{ keycloak_http_port }}` |
|`keycloak_management_url` | URL for management console rest calls | `http://{{ keycloak_quarkus_host }}:{{ keycloak_management_http_port }}` |
Role Variables
--------------
| Variable | Description |
|:---------|:------------|
|`keycloak_quarkus_admin_pass`| Password of console admin account |
License
-------
Apache License 2.0
Author Information
------------------
* [Guido Grazioli](https://github.com/guidograzioli)

View File

@ -0,0 +1,70 @@
---
### Configuration specific to keycloak
keycloak_quarkus_version: 17.0.1
keycloak_quarkus_archive: "keycloak-{{ keycloak_quarkus_version }}.zip"
keycloak_quarkus_download_url: "https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}"
keycloak_quarkus_installdir: "{{ keycloak_quarkus_dest }}/keycloak-{{ keycloak_quarkus_version }}"
# whether to install from local archive
keycloak_quarkus_offline_install: False
### Install location and service settings
keycloak_quarkus_jvm_package: java-11-openjdk-headless
keycloak_quarkus_dest: /opt/keycloak
keycloak_quarkus_home: "{{ keycloak_quarkus_installdir }}"
keycloak_quarkus_config_dir: "{{ keycloak_quarkus_home }}/conf"
keycloak_quarkus_service_user: keycloak
keycloak_quarkus_service_group: keycloak
keycloak_quarkus_service_pidfile: "/run/keycloak.pid"
keycloak_quarkus_configure_firewalld: False
### administrator console password
keycloak_quarkus_admin_user: admin
keycloak_quarkus_admin_pass: ''
keycloak_quarkus_master_realm: master
### Configuration settings
keycloak_quarkus_bind_address: 0.0.0.0
keycloak_quarkus_host: localhost
keycloak_quarkus_http_port: 8080
keycloak_quarkus_https_port: 8443
keycloak_quarkus_ajp_port: 8009
keycloak_quarkus_jgroups_port: 7600
keycloak_quarkus_java_opts: "-Xms1024m -Xmx2048m"
### Enable configuration for database backend, clustering and remote caches on infinispan
keycloak_quarkus_ha_enabled: False
### Enable database configuration, must be enabled when HA is configured
keycloak_quarkus_db_enabled: "{{ True if keycloak_quarkus_ha_enabled else False }}"
### keycloak frontend url
keycloak_quarkus_http_relative_path: auth
keycloak_quarkus_frontend_url: http://localhost:8080/auth
keycloak_quarkus_metrics_enabled: False
### infinispan remote caches access (hotrod)
keycloak_quarkus_ispn_user: supervisor
keycloak_quarkus_ispn_pass: supervisor
keycloak_quarkus_ispn_url: localhost
keycloak_quarkus_ispn_sasl_mechanism: SCRAM-SHA-512
keycloak_quarkus_ispn_use_ssl: False
# if ssl is enabled, import ispn server certificate here
keycloak_quarkus_ispn_trust_store_path: /etc/pki/java/cacerts
keycloak_quarkus_ispn_trust_store_password: changeit
### database backend engine: values [ 'postgres', 'mariadb' ]
keycloak_quarkus_jdbc_engine: postgres
### database backend credentials
keycloak_quarkus_db_user: keycloak-user
keycloak_quarkus_db_pass: keycloak-pass
keycloak_quarkus_jdbc_url: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].url }}"
keycloak_quarkus_jdbc_driver_version: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].version }}"
# override the variables above, following defaults show minimum supported versions
keycloak_quarkus_default_jdbc:
postgres:
url: 'jdbc:postgresql://localhost:5432/keycloak'
version: 9.4.1212
mariadb:
url: 'jdbc:mariadb://localhost:3306/keycloak'
version: 2.7.4

View File

@ -0,0 +1,4 @@
---
- name: "Restart {{ keycloak.service_name }}"
ansible.builtin.include_tasks: restart.yml
listen: "restart keycloak"

View File

@ -0,0 +1,203 @@
argument_specs:
main:
options:
keycloak_quarkus_version:
# line 3 of defaults/main.yml
default: "17.0.1"
description: "keycloak.org package version"
type: "str"
keycloak_quarkus_archive:
# line 4 of defaults/main.yml
default: "keycloak-{{ keycloak_quarkus_version }}.zip"
description: "keycloak install archive filename"
type: "str"
keycloak_quarkus_download_url:
# line 5 of defaults/main.yml
default: "https://github.com/keycloak/keycloak/releases/download/{{ keycloak_quarkus_version }}/{{ keycloak_quarkus_archive }}"
description: "Download URL for keycloak"
type: "str"
keycloak_quarkus_installdir:
# line 6 of defaults/main.yml
default: "{{ keycloak_quarkus_dest }}/keycloak-{{ keycloak_quarkus_version }}"
description: "Installation path"
type: "str"
keycloak_quarkus_offline_install:
# line 9 of defaults/main.yml
default: false
description: "Perform an offline install"
type: "bool"
keycloak_quarkus_jvm_package:
# line 12 of defaults/main.yml
default: "java-11-openjdk-headless"
description: "RHEL java package runtime"
type: "str"
keycloak_quarkus_dest:
# line 13 of defaults/main.yml
default: "/opt/keycloak"
description: "Installation root path"
type: "str"
keycloak_quarkus_home:
# line 14 of defaults/main.yml
default: "{{ keycloak_quarkus_installdir }}"
description: "Installation work directory"
type: "str"
keycloak_quarkus_config_dir:
# line 15 of defaults/main.yml
default: "{{ keycloak_quarkus_home }}/conf"
description: "Path for configuration"
type: "str"
keycloak_quarkus_service_user:
# line 16 of defaults/main.yml
default: "keycloak"
description: "Posix account username"
type: "str"
keycloak_quarkus_service_group:
# line 17 of defaults/main.yml
default: "keycloak"
description: "Posix account group"
type: "str"
keycloak_quarkus_service_pidfile:
# line 18 of defaults/main.yml
default: "/run/keycloak.pid"
description: "Pid file path for service"
type: "str"
keycloak_quarkus_configure_firewalld:
# line 19 of defaults/main.yml
default: false
description: "Ensure firewalld is running and configure keycloak ports"
type: "bool"
keycloak_quarkus_admin_user:
# line 22 of defaults/main.yml
default: "admin"
description: "Administration console user account"
type: "str"
keycloak_quarkus_admin_pass:
# line 23 of defaults/main.yml
default: ""
description: "Password of console admin account"
type: "str"
keycloak_quarkus_master_realm:
# line 24 of defaults/main.yml
default: "master"
description: "Name for rest authentication realm"
type: "str"
keycloak_quarkus_bind_address:
# line 27 of defaults/main.yml
default: "0.0.0.0"
description: "Address for binding service ports"
type: "str"
keycloak_quarkus_host:
# line 28 of defaults/main.yml
default: "localhost"
description: "hostname"
type: "str"
keycloak_quarkus_http_port:
# line 29 of defaults/main.yml
default: 8080
description: "HTTP port"
type: "int"
keycloak_quarkus_https_port:
# line 30 of defaults/main.yml
default: 8443
description: "HTTPS port"
type: "int"
keycloak_quarkus_ajp_port:
# line 31 of defaults/main.yml
default: 8009
description: "AJP port"
type: "int"
keycloak_quarkus_jgroups_port:
# line 32 of defaults/main.yml
default: 7600
description: "jgroups cluster tcp port"
type: "int"
keycloak_quarkus_java_opts:
# line 33 of defaults/main.yml
default: "-Xms1024m -Xmx2048m"
description: "Additional JVM options"
type: "str"
keycloak_quarkus_ha_enabled:
# line 36 of defaults/main.yml
default: false
description: "Enable auto configuration for database backend, clustering and remote caches on infinispan"
type: "bool"
keycloak_quarkus_db_enabled:
# line 38 of defaults/main.yml
default: "{{ True if keycloak_quarkus_ha_enabled else False }}"
description: "Enable auto configuration for database backend"
type: "str"
keycloak_quarkus_http_relative_path:
# line 41 of defaults/main.yml
default: "auth"
description: "Service context path"
type: "str"
keycloak_quarkus_frontend_url:
# line 41 of defaults/main.yml
default: "http://localhost:8080/auth"
description: "Service public URL"
type: "str"
keycloak_quarkus_metrics_enabled:
# line 43 of defaults/main.yml
default: false
description: "Whether to enable metrics"
type: "bool"
keycloak_quarkus_ispn_user:
# line 46 of defaults/main.yml
default: "supervisor"
description: "Username for connecting to infinispan"
type: "str"
keycloak_quarkus_ispn_pass:
# line 47 of defaults/main.yml
default: "supervisor"
description: "Password for connecting to infinispan"
type: "str"
keycloak_quarkus_ispn_url:
# line 48 of defaults/main.yml
default: "localhost"
description: "URL for connecting to infinispan"
type: "str"
keycloak_quarkus_ispn_sasl_mechanism:
# line 49 of defaults/main.yml
default: "SCRAM-SHA-512"
description: "Infinispan auth mechanism"
type: "str"
keycloak_quarkus_ispn_use_ssl:
# line 50 of defaults/main.yml
default: false
description: "Whether infinispan uses TLS connection"
type: "bool"
keycloak_quarkus_ispn_trust_store_path:
# line 52 of defaults/main.yml
default: "/etc/pki/java/cacerts"
description: "Path to infinispan server trust certificate"
type: "str"
keycloak_quarkus_ispn_trust_store_password:
# line 53 of defaults/main.yml
default: "changeit"
description: "Password for infinispan certificate keystore"
type: "str"
keycloak_quarkus_jdbc_engine:
# line 56 of defaults/main.yml
default: "postgres"
description: "Database engine [mariadb,postres]"
type: "str"
keycloak_quarkus_db_user:
# line 58 of defaults/main.yml
default: "keycloak-user"
description: "User for database connection"
type: "str"
keycloak_quarkus_db_pass:
# line 59 of defaults/main.yml
default: "keycloak-pass"
description: "Password for database connection"
type: "str"
keycloak_quarkus_jdbc_url:
# line 60 of defaults/main.yml
default: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].url }}"
description: "JDBC URL for connecting to database"
type: "str"
keycloak_quarkus_jdbc_driver_version:
# line 61 of defaults/main.yml
default: "{{ keycloak_quarkus_default_jdbc[keycloak_quarkus_jdbc_engine].version }}"
description: "Version for JDBC driver"
type: "str"

View File

@ -0,0 +1,28 @@
---
collections:
galaxy_info:
role_name: keycloak_quarkus
namespace: middleware_automation
author: Guido Grazioli
description: Install keycloak on quarkus server configurations
company: Red Hat, Inc.
license: Apache License 2.0
min_ansible_version: "2.9"
platforms:
- name: EL
versions:
- 8
galaxy_tags:
- keycloak
- quarkus
- redhat
- rhel
- sso
- authentication
- identity
- security

View File

@ -0,0 +1,21 @@
---
- block:
- name: "Check if packages are already installed"
ansible.builtin.command: "rpm -q {{ packages_list | join(' ') }}"
args:
warn: no
register: rpm_info
changed_when: rpm_info.failed
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: "Install packages: {{ packages_to_install }}"
become: yes
ansible.builtin.yum:
name: "{{ packages_to_install }}"
state: present
when: packages_to_install | default([]) | length > 0

View File

@ -0,0 +1,25 @@
---
- name: Ensure required package firewalld are installed
ansible.builtin.include_tasks: fastpackages.yml
vars:
packages_list:
- firewalld
- name: Enable and start the firewalld service
become: yes
ansible.builtin.systemd:
name: firewalld
enabled: yes
state: started
- name: "Configure firewall for {{ keycloak.service_name }} ports"
become: yes
firewalld:
port: "{{ item }}"
permanent: true
state: enabled
immediate: yes
loop:
- "{{ keycloak_quarkus_http_port }}/tcp"
- "{{ keycloak_quarkus_https_port }}/tcp"
- "{{ keycloak_quarkus_jgroups_port }}/tcp"

View File

@ -0,0 +1,110 @@
---
- name: Validate parameters
ansible.builtin.assert:
that:
- keycloak.home is defined
- keycloak_quarkus_service_user is defined
- keycloak_quarkus_dest is defined
- keycloak_quarkus_archive is defined
- keycloak_quarkus_download_url is defined
- keycloak_quarkus_version is defined
quiet: true
- name: Check for an existing deployment
become: yes
ansible.builtin.stat:
path: "{{ keycloak.home }}"
register: existing_deploy
- name: "Create {{ keycloak.service_name }} service user/group"
become: yes
ansible.builtin.user:
name: "{{ keycloak.service_user }}"
home: /opt/keycloak
system: yes
create_home: no
- name: "Create {{ keycloak.service_name }} install location"
become: yes
ansible.builtin.file:
dest: "{{ keycloak_quarkus_dest }}"
state: directory
owner: "{{ keycloak.service_user }}"
group: "{{ keycloak.service_group }}"
mode: 0750
## check remote archive
- name: Set download archive path
ansible.builtin.set_fact:
archive: "{{ keycloak_quarkus_dest }}/{{ keycloak.bundle }}"
- name: Check download archive path
become: yes
ansible.builtin.stat:
path: "{{ archive }}"
register: archive_path
## download to controller
- name: Check local download archive path
ansible.builtin.stat:
path: "{{ lookup('env', 'PWD') }}"
register: local_path
delegate_to: localhost
- name: Download keycloak archive
ansible.builtin.get_url:
url: "{{ keycloak_quarkus_download_url }}"
dest: "{{ local_path.stat.path }}/{{ keycloak.bundle }}"
delegate_to: localhost
when:
- archive_path is defined
- archive_path.stat is defined
- not archive_path.stat.exists
- not keycloak.offline_install
- name: Check downloaded archive
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
ansible.builtin.copy:
src: "{{ local_path.stat.path }}/{{ keycloak.bundle }}"
dest: "{{ archive }}"
owner: "{{ keycloak.service_user }}"
group: "{{ keycloak.service_group }}"
mode: 0750
register: new_version_downloaded
when:
- not archive_path.stat.exists
- local_archive_path.stat is defined
- local_archive_path.stat.exists
become: yes
- name: "Check target directory: {{ keycloak.home }}"
ansible.builtin.stat:
path: "{{ keycloak.home }}"
register: path_to_workdir
become: yes
- name: "Extract Keycloak archive on target"
ansible.builtin.unarchive:
remote_src: yes
src: "{{ archive }}"
dest: "{{ keycloak_quarkus_dest }}"
creates: "{{ keycloak.home }}"
owner: "{{ keycloak.service_user }}"
group: "{{ keycloak.service_group }}"
become: yes
when:
- new_version_downloaded.changed or not path_to_workdir.stat.exists
notify:
- restart keycloak
- name: Inform decompression was not executed
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

View File

@ -0,0 +1,41 @@
---
# tasks file for keycloak
- name: Check prerequisites
ansible.builtin.include_tasks: prereqs.yml
tags:
- prereqs
- name: Include firewall config tasks
ansible.builtin.include_tasks: firewalld.yml
when: keycloak_quarkus_configure_firewalld
tags:
- firewall
- name: Include install tasks
ansible.builtin.include_tasks: install.yml
tags:
- install
- name: Include systemd tasks
ansible.builtin.include_tasks: systemd.yml
tags:
- systemd
- name: "Configure config for keycloak service"
ansible.builtin.template:
src: keycloak.conf.j2
dest: "{{ keycloak.home }}/conf/keycloak.conf"
owner: "{{ keycloak.service_user }}"
group: "{{ keycloak.service_group }}"
mode: 0644
notify:
- restart keycloak
- name: "Start and wait for keycloak service"
ansible.builtin.include_tasks: start.yml
- name: Check service status
ansible.builtin.command: "systemctl status keycloak"
register: keycloak_service_status
changed_when: False

View File

@ -0,0 +1,34 @@
---
- name: Validate admin console password
ansible.builtin.assert:
that:
- keycloak_quarkus_admin_pass | length > 12
quiet: True
fail_msg: "The console administrator password is empty or invalid. Please set the keycloak_quarkus_admin_pass variable to a 12+ char long string"
success_msg: "{{ 'Console administrator password OK' }}"
- name: Validate configuration
ansible.builtin.assert:
that:
- (keycloak_quarkus_ha_enabled and keycloak_quarkus_db_enabled) or (not keycloak_quarkus_ha_enabled and keycloak_quarkus_db_enabled) or (not keycloak_quarkus_ha_enabled and not keycloak_quarkus_db_enabled)
quiet: True
fail_msg: "Cannot install HA setup without a backend database service. Check keycloak_quarkus_ha_enabled and keycloak_quarkus_db_enabled"
success_msg: "{{ 'Configuring HA' if keycloak_quarkus_ha_enabled else 'Configuring standalone' }}"
# - name: Validate credentials
# 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
# quiet: True
# fail_msg: "Cannot install Red Hat SSO without RHN credentials. Check rhn_username and rhn_password are defined"
# success_msg: "{{ 'Installing Red Hat Single Sign-On' if keycloak_rhsso_enable else 'Installing keycloak.org' }}"
- name: Ensure required packages are installed
ansible.builtin.include_tasks: fastpackages.yml
vars:
packages_list:
- "{{ keycloak_quarkus_jvm_package }}"
- unzip
- procps-ng
- initscripts

View File

@ -0,0 +1,7 @@
---
- name: "Restart and enable {{ keycloak.service_name }} service"
ansible.builtin.systemd:
name: keycloak
enabled: yes
state: restarted
become: yes

View File

@ -0,0 +1,15 @@
---
- name: "Start {{ keycloak.service_name }} service"
ansible.builtin.systemd:
name: keycloak
enabled: yes
state: started
become: yes
- name: "Wait until {{ keycloak.service_name }} 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

@ -0,0 +1,29 @@
---
- name: "Configure sysconfig file for keycloak service"
become: yes
ansible.builtin.template:
src: keycloak-sysconfig.j2
dest: /etc/sysconfig/keycloak
owner: root
group: root
mode: 0644
notify:
- restart keycloak
- name: "Configure systemd unit file for keycloak service"
ansible.builtin.template:
src: keycloak.service.j2
dest: /etc/systemd/system/keycloak.service
owner: root
group: root
mode: 0644
become: yes
register: systemdunit
notify:
- restart keycloak
- name: Reload systemd
become: yes
ansible.builtin.systemd:
daemon_reload: yes
when: systemdunit.changed

View File

@ -0,0 +1,3 @@
# {{ ansible_managed }}
KEYCLOAK_ADMIN={{ keycloak_quarkus_admin_user }}
KEYCLOAK_ADMIN_PASSWORD='{{ keycloak_quarkus_admin_pass }}'

View File

@ -0,0 +1,51 @@
# {{ ansible_managed }}
# Database
# Database vendor [dev-file, dev-mem, mariadb, mssql, mysql, oracle, postgres]
#db=postgres
# The username of the database user.
#db-username=keycloak
# The password of the database user.
#db-password=password
# The full database JDBC URL. If not provided, a default URL is set based on the selected database vendor.
#db-url=jdbc:postgresql://localhost/keycloak
# Observability
# If the server should expose metrics and healthcheck endpoints.
#metrics-enabled=true
# HTTP
http-enabled=true
http-port=8080
https-port=8443
# The file path to a server certificate or certificate chain in PEM format.
#https-certificate-file=${kc.home.dir}conf/server.crt.pem
# The file path to a private key in PEM format.
#https-certificate-key-file=${kc.home.dir}conf/server.key.pem
# The proxy address forwarding mode if the server is behind a reverse proxy.
#proxy=reencrypt
# Do not attach route to cookies and rely on the session affinity capabilities from reverse proxy
#spi-sticky-session-encoder-infinispan-should-attach-route=false
# Hostname for the Keycloak server.
hostname={{ keycloak_quarkus_host }}
hostname-path={{ keycloak_quarkus_http_relative_path }}
# Cluster
#cache=ispn
#Defines the cache mechanism for high-availability. [local, ispn]
#cache-config-file=conf/cache-ispn.xml
#Defines the file from which cache configuration should be loaded from.
#cache-stack=tcp
#Define the default stack to use for cluster communication and node discovery. [tcp, udp, kubernetes, ec2, azure, google]
# Proxy
# The proxy address forwarding mode if the server is behind a reverse proxy. [edge, reencrypt, passthrough]
#proxy=
# Logging
# The format of log entries.
#log-format=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] (%t) %s%e%n
# The log level of the root category or a comma-separated list of individual categories and their levels.
#log-level=info

View File

@ -0,0 +1,14 @@
# {{ ansible_managed }}
[Unit]
Description=Keycloak Server
After=network.target
[Service]
Type=simple
EnvironmentFile=-/etc/sysconfig/keycloak
PIDFile={{ keycloak_quarkus_service_pidfile }}
ExecStart={{ keycloak.home }}/bin/kc.sh start
#--http-relative-path={{ keycloak_quarkus_http_relative_path }}
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,11 @@
---
keycloak:
home: "{{ keycloak_quarkus_home }}"
config_dir: "{{ keycloak_quarkus_config_dir }}"
bundle: "{{ keycloak_quarkus_archive }}"
service_name: "keycloak"
health_url: "http://localhost:8080/realms/master/.well-known/openid-configuration"
cli_path: "{{ keycloak_quarkus_home }}/bin/kcadm.sh"
service_user: "{{ keycloak_quarkus_service_user }}"
service_group: "{{ keycloak_quarkus_service_group }}"
offline_install: "{{ keycloak_quarkus_offline_install }}"

View File

@ -10,6 +10,7 @@ keycloak_rhsso_enable: False
keycloak_admin_user: admin keycloak_admin_user: admin
keycloak_auth_realm: master keycloak_auth_realm: master
keycloak_auth_client: admin-cli keycloak_auth_client: admin-cli
keycloak_context: /auth
# administrator console password, this is a required variable # administrator console password, this is a required variable
keycloak_admin_password: '' keycloak_admin_password: ''

View File

@ -4,7 +4,12 @@ argument_specs:
keycloak_host: keycloak_host:
# line 3 of keycloak_realm/defaults/main.yml # line 3 of keycloak_realm/defaults/main.yml
default: "localhost" default: "localhost"
description: "hostname for rest calls" description: "Hostname for rest calls"
type: "str"
keycloak_context:
# line 5 of keycloak_realm/defaults/main.yml
default: "/auth"
description: "Context path for rest calls"
type: "str" type: "str"
keycloak_http_port: keycloak_http_port:
# line 4 of keycloak_realm/defaults/main.yml # line 4 of keycloak_realm/defaults/main.yml

View File

@ -1,7 +1,7 @@
--- ---
- name: Generate keycloak auth token - name: Generate keycloak auth token
ansible.builtin.uri: ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/realms/master/protocol/openid-connect/token" url: "{{ keycloak_url }}{{ keycloak_context }}/realms/master/protocol/openid-connect/token"
method: POST method: POST
body: "client_id={{ keycloak_auth_client }}&username={{ keycloak_admin_user }}&password={{ keycloak_admin_password }}&grant_type=password" body: "client_id={{ keycloak_auth_client }}&username={{ keycloak_admin_user }}&password={{ keycloak_admin_password }}&grant_type=password"
validate_certs: no validate_certs: no
@ -13,7 +13,7 @@
- name: "Determine if realm exists" - name: "Determine if realm exists"
ansible.builtin.uri: ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}" url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ keycloak_realm }}"
method: GET method: GET
status_code: status_code:
- 200 - 200
@ -25,7 +25,7 @@
- name: Create Realm - name: Create Realm
ansible.builtin.uri: ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms" url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms"
method: POST method: POST
body: "{{ lookup('template','realm.json.j2') }}" body: "{{ lookup('template','realm.json.j2') }}"
validate_certs: no validate_certs: no
@ -37,7 +37,7 @@
- name: Create user federation - name: Create user federation
community.general.keycloak_user_federation: community.general.keycloak_user_federation:
auth_keycloak_url: "{{ keycloak_url }}/auth" auth_keycloak_url: "{{ keycloak_url }}{{ keycloak_context }}"
auth_realm: "{{ keycloak_auth_realm }}" auth_realm: "{{ keycloak_auth_realm }}"
auth_username: "{{ keycloak_admin_user }}" auth_username: "{{ keycloak_admin_user }}"
auth_password: "{{ keycloak_admin_password }}" auth_password: "{{ keycloak_admin_password }}"
@ -56,7 +56,7 @@
- name: Create or update a Keycloak client - name: Create or update a Keycloak client
community.general.keycloak_client: community.general.keycloak_client:
auth_client_id: "{{ keycloak_auth_client }}" auth_client_id: "{{ keycloak_auth_client }}"
auth_keycloak_url: "{{ keycloak_url }}/auth" auth_keycloak_url: "{{ keycloak_url }}{{ keycloak_context }}"
auth_realm: "{{ keycloak_auth_realm }}" auth_realm: "{{ keycloak_auth_realm }}"
auth_username: "{{ keycloak_admin_user }}" auth_username: "{{ keycloak_admin_user }}"
auth_password: "{{ keycloak_admin_password }}" auth_password: "{{ keycloak_admin_password }}"

View File

@ -4,7 +4,7 @@
realm: "{{ client.realm }}" realm: "{{ client.realm }}"
client_id: "{{ client.name }}" client_id: "{{ client.name }}"
auth_client_id: "{{ keycloak_auth_client }}" auth_client_id: "{{ keycloak_auth_client }}"
auth_keycloak_url: "{{ keycloak_url }}/auth" auth_keycloak_url: "{{ keycloak_url }}{{ keycloak_context }}"
auth_realm: "{{ keycloak_auth_realm }}" auth_realm: "{{ keycloak_auth_realm }}"
auth_username: "{{ keycloak_admin_user }}" auth_username: "{{ keycloak_admin_user }}"
auth_password: "{{ keycloak_admin_password }}" auth_password: "{{ keycloak_admin_password }}"

View File

@ -1,7 +1,7 @@
--- ---
- name: "Check if User Already Exists" - name: "Check if User Already Exists"
ansible.builtin.uri: ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users?username={{ user.username }}" url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ keycloak_realm }}/users?username={{ user.username }}"
validate_certs: no validate_certs: no
headers: headers:
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
@ -9,7 +9,7 @@
- name: "Create User" - name: "Create User"
ansible.builtin.uri: ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users" url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ keycloak_realm }}/users"
method: POST method: POST
body: body:
enabled: true enabled: true
@ -27,7 +27,7 @@
- name: "Get User" - name: "Get User"
ansible.builtin.uri: ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users?username={{ user.username }}" url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ keycloak_realm }}/users?username={{ user.username }}"
validate_certs: no validate_certs: no
headers: headers:
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
@ -35,7 +35,7 @@
- name: "Update User Password" - name: "Update User Password"
ansible.builtin.uri: ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users/{{ (keycloak_user.json | first).id }}/reset-password" url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ keycloak_realm }}/users/{{ (keycloak_user.json | first).id }}/reset-password"
method: PUT method: PUT
body: body:
type: password type: password

View File

@ -1,7 +1,7 @@
--- ---
- name: "Get Realm for role" - name: "Get Realm for role"
ansible.builtin.uri: ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ client_role.realm }}" url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm }}"
method: GET method: GET
status_code: status_code:
- 200 - 200
@ -12,7 +12,7 @@
- name: Check if Mapping is available - name: Check if Mapping is available
ansible.builtin.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" url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm }}/users/{{ (keycloak_user.json | first).id }}/role-mappings/clients/{{ (create_client_result.results | selectattr('end_state.clientId', 'equalto', client_role.client) | list | first).end_state.id }}/available"
method: GET method: GET
status_code: status_code:
- 200 - 200
@ -23,7 +23,7 @@
- name: "Create Role Mapping" - name: "Create Role Mapping"
ansible.builtin.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 }}" url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ client_role.realm }}/users/{{ (keycloak_user.json | first).id }}/role-mappings/clients/{{ (create_client_result.results | selectattr('end_state.clientId', 'equalto', client_role.client) | list | first).end_state.id }}"
method: POST method: POST
body: body:
- id: "{{ item.id }}" - id: "{{ item.id }}"

View File

@ -1,7 +1,7 @@
--- ---
- name: "Get User {{ user.username }}" - name: "Get User {{ user.username }}"
ansible.builtin.uri: ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users?username={{ user.username }}" url: "{{ keycloak_url }}{{ keycloak_context }}/admin/realms/{{ keycloak_realm }}/users?username={{ user.username }}"
headers: headers:
validate_certs: no validate_certs: no
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}" Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
@ -9,7 +9,7 @@
- name: Refresh keycloak auth token - name: Refresh keycloak auth token
ansible.builtin.uri: ansible.builtin.uri:
url: "{{ keycloak_url }}/auth/realms/master/protocol/openid-connect/token" url: "{{ keycloak_url }}{{ keycloak_context }}/realms/master/protocol/openid-connect/token"
method: POST method: POST
body: "client_id={{ keycloak_auth_client }}&username={{ keycloak_admin_user }}&password={{ keycloak_admin_password }}&grant_type=password" body: "client_id={{ keycloak_auth_client }}&username={{ keycloak_admin_user }}&password={{ keycloak_admin_password }}&grant_type=password"
validate_certs: no validate_certs: no