Add base role and playbook, molecule configuration

This commit is contained in:
Guido Grazioli 2021-12-14 11:26:42 +01:00
commit 187473447d
35 changed files with 3658 additions and 0 deletions

View file

@ -0,0 +1,72 @@
---
- assert:
that:
- zipfile_dest is defined
- rhn_id_file is defined
- rhn_username is defined
- rhn_password is defined
quiet: true
- set_fact:
rhn_base_url: "{{ override_rhn_base_url | default('https://access.redhat.com/jbossnetwork/restricted/softwareDownload.html?softwareId=') }}"
rhn_download_url: "{{ rhn_base_url }}{{ rhn_id_file }}"
- name: "Check zipfile dest directory {{ zipfile_dest }}"
stat:
path: "{{ zipfile_dest }}"
register: archive_path
- name: "Install zipfile from RHN: {{ rhn_download_url }}"
redhat_csp_download:
url: "{{ rhn_download_url }}"
dest: "{{ zipfile_dest }}"
username: "{{ rhn_username }}"
password: "{{ rhn_password }}"
no_log: "{{ omit_rhn_output | default(true) }}"
when:
- archive_path is defined
- archive_path.stat is defined
- not archive_path.stat.exists
- name: "Check zipfile dest directory {{ zipfile_dest }}"
stat:
path: "{{ zipfile_dest }}"
register: path_to_downloaded_artefact
- block:
- file:
path: "{{ work_dir }}"
state: directory
- stat:
path: "{{ target_dir }}"
register: target_dir_state
- assert:
that:
- target_dir_state is defined
- target_dir_state.stat is defined
fail_msg: "Directory layout for {{ target_dir }} is invalid."
quiet: true
- name: "Decompress {{ zipfile_dest }} into {{ work_dir }} (results in {{ target_dir }}."
unarchive:
src: "{{ zipfile_dest }}"
dest: "{{ work_dir }}"
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_user }}"
remote_src: yes
creates: "{{ target_dir }}"
when:
- not target_dir_state.stat.exists
- debug:
msg: "{{ target_dir }} already exists, skipping decompressing {{ zipfile_dest }}"
when:
- target_dir_state.stat.exists
when:
- path_to_downloaded_artefact is defined
- path_to_downloaded_artefact.stat is defined
- path_to_downloaded_artefact.stat.exists
- target_dir is defined
- work_dir is defined

View file

@ -0,0 +1,14 @@
---
- block:
- name: "Check if package {{ package_name }} is already installed"
command: rpm -q {{ package_name }}
args:
warn: no
register: rpm_info
changed_when: rpm_info.failed
rescue:
- name: "If package {{ package_name }} is missing, add it to the yum install list."
set_fact:
packages_to_install: "{{ packages_to_install + [ package_name ] }}"
when: rpm_info.failed

View file

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

View file

@ -0,0 +1,25 @@
---
- name: Ensures required package firewalld are installed
ansible.builtin.include_tasks: fastpackages/install.yml
vars:
packages_list:
- firewalld
- name: Enable and start the firewalld service
become: yes
systemd:
name: firewalld
enabled: yes
state: started
- name: Configure firewall for jdg ports
become: yes
ansible.posix.firewalld:
port: "{{ item }}"
permanent: true
state: enabled
immediate: yes
loop:
- "{{ keycloak_http_port }}/tcp"
- "{{ keycloak_https_port }}/tcp"
- "8009/tcp"

View file

@ -0,0 +1,141 @@
---
- assert:
that:
- keycloak_jboss_home is defined
- keycloak_service_user is defined
- keycloak_dest is defined
- keycloak_archive is defined
- keycloak_download_url is defined
- keycloak_version is defined
quiet: true
- set_fact:
keycloak_service_group: "{{ keycloak_service_user }}"
when:
- not keycloak_service_group is defined
- name: check for an existing deployment
become: yes
stat:
path: "{{ keycloak_jboss_home }}"
register: existing_deploy
- block:
- name: stop the old keycloak service
become: yes
ignore_errors: yes
systemd:
name: keycloak
state: stopped
- name: remove the old Keycloak deployment
become: yes
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:
path: "{{ keycloak_jboss_home }}"
- name: create Keycloak service user/group
become: yes
user:
name: "{{ keycloak_service_user }}"
home: /opt/keycloak
system: yes
create_home: no
- name: create Keycloak install location
become: yes
file:
dest: "{{ keycloak_dest }}"
state: directory
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
- block:
- set_fact:
archive: "{{ keycloak_dest }}/{{ keycloak_archive }}"
- name: "Check archive directory {{ archive }}"
stat:
path: "{{ archive }}"
register: archive_path
- name: download Keycloak archive to target
get_url:
url: "{{ keycloak_download_url }}"
dest: "{{ keycloak_dest }}"
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
when:
- archive_path is defined
- archive_path.stat is defined
- not archive_path.stat.exists
- name: extract Keycloak archive on target
unarchive:
remote_src: yes
src: "{{ archive }}"
dest: "{{ keycloak_dest }}"
creates: "{{ keycloak_jboss_home }}"
owner: "{{ keycloak_service_user }}"
group: "{{ keycloak_service_group }}"
notify:
- restart keycloak
become: yes
when: not keycloak_rhsso_enable
- block:
- assert:
that:
- rhsso_rhn_id is defined
quiet: true
fail_msg: "Can't install RHSSO without RHN ID."
- name: create download directory
file:
path: /opt/apps
state: directory
- include_tasks: download_from_rhn.yml
vars:
rhn_id_file: "{{ rhsso_rhn_id }}"
zipfile_dest: "{{ keycloak_dest }}/{{ keycloak_rhsso_archive }}"
work_dir: "{{ keycloak_dest }}"
target_dir: "{{ keycloak_jboss_home }}"
become: yes
when: keycloak_rhsso_enable
- name: "Install Postresql driver"
include_role:
name: wildfly_driver
tasks_from: jdbc_driver.yml
vars:
wildfly_user: "{{ keycloak_service_user }}"
jdbc_driver_module_dir: "{{ keycloak_jdbc.postgres.driver_module_dir }}"
jdbc_driver_version: "{{ keycloak_jdbc.postgres.driver_version }}"
jdbc_driver_jar_filename: "{{ keycloak_jdbc.postgres.driver_jar_filename }}"
jdbc_driver_jar_url: "{{ keycloak_jdbc.postgres.driver_jar_url }}"
jdbc_driver_jar_installation_path: "{{ keycloak_jdbc.postgres.driver_module_dir }}/{{ keycloak_jdbc.postgres.driver_jar_filename }}"
jdbc_driver_module_name: "{{ keycloak_jdbc.postgres.driver_module_name }}"
when: keycloak_jdbc.postgres.enabled
- name: "Deploy Keycloak's standalone.xml"
become: yes
template:
src: "{{ 'templates/standalone-rhsso.xml.j2' if keycloak_rhsso_enable else 'templates/standalone.xml.j2' }}"
dest: "{{ keycloak_jboss_home }}/standalone/configuration/standalone.xml"
notify:
- restart keycloak
when: not keycloak_remotecache.enabled
- name: "Deploy Keycloak's standalone.xml with remote cache store"
become: yes
template:
src: "{{ 'templates/standalone-rhsso-jdg.xml.j2' if keycloak_rhsso_enable else 'templates/standalone-infinispan.xml.j2' }}"
dest: "{{ keycloak_jboss_home }}/standalone/configuration/standalone.xml"
notify:
- restart keycloak
when: keycloak_remotecache.enabled

View file

@ -0,0 +1,24 @@
---
# tasks file for keycloak
- name: Prerequisites
include_tasks: prereqs.yml
tags:
- prereqs
- include_tasks: tasks/install.yml
- name: create Keycloak admin user
command:
args:
argv:
- "{{ keycloak_jboss_home }}/bin/add-user-keycloak.sh"
- -rmaster
- -u{{ keycloak_admin_user }}
- -p{{ keycloak_admin_password }}
creates: "{{ keycloak_config_dir }}/keycloak-add-user.json"
become: yes
- include_tasks: tasks/systemd.yml

View file

@ -0,0 +1,12 @@
- name: Create client roles
community.general.keycloak_role:
name: "{{ item }}"
realm: "{{ client.realm }}"
client_id: "{{ client.name }}"
auth_client_id: "{{ keycloak_auth_client }}"
auth_keycloak_url: "{{ keycloak_url }}/auth"
auth_realm: "{{ keycloak_auth_realm }}"
auth_username: "{{ keycloak_admin_user }}"
auth_password: "{{ keycloak_admin_password }}"
state: present
loop: "{{ client.roles | flatten }}"

View file

@ -0,0 +1,73 @@
---
- name: Generate keycloak auth token
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
until: keycloak_auth_response.status == 200
retries: 5
delay: 2
- name: "Determine if realm exists"
uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}"
method: GET
status_code:
- 200
- 404
headers:
Accept: "application/json"
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
register: keycloak_realm_exists
- name: Create Realm
uri:
url: "{{ keycloak_url }}/auth/admin/realms"
method: POST
body: "{{ lookup('template','realm.json.j2') }}"
validate_certs: no
body_format: json
headers:
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
status_code: 201
when: keycloak_realm_exists.status == 404
- name: Create Client
community.general.keycloak_client:
auth_client_id: "{{ keycloak_auth_client }}"
auth_keycloak_url: "{{ keycloak_url }}/auth"
auth_realm: "{{ keycloak_auth_realm }}"
auth_username: "{{ keycloak_admin_user }}"
auth_password: "{{ keycloak_admin_password }}"
client_id: "{{ item.name }}"
realm: "{{ item.realm }}"
default_roles: "{{ item.roles | default(omit) }}"
root_url: "{{ item.root_url | default('') }}"
redirect_uris: "{{ demo_app_redirect_uris | default([]) }}"
public_client: "{{ item.public_client | default(False) }}"
web_origins: "{{ item.web_origins | default('+') }}"
state: present
register: create_client_result
loop: "{{ keycloak_clients | flatten }}"
- name: Create client roles
include_tasks: manage_client_roles.yml
when: keycloak_rhsso_enable
loop: "{{ keycloak_clients | flatten }}"
loop_control:
loop_var: client
- name: Manage Users
include_tasks: manage_user.yml
loop: "{{ keycloak_users }}"
loop_control:
loop_var: user
- name: Manage User Roles
include_tasks: manage_user_roles.yml
loop: "{{ keycloak_users | flatten }}"
loop_control:
loop_var: user
when: "'client_roles' in user"

View file

@ -0,0 +1,51 @@
---
- name: "Check if User Already Exists"
uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users?username={{ user.username }}"
validate_certs: no
headers:
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
register: keycloak_user_serach_result
- name: "Create User"
uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users"
method: POST
body:
enabled: true
attributes: "{{ user.attributes | default(omit) }}"
username: "{{ user.username }}"
email: "{{ user.email | default(omit) }}"
firstName: "{{ user.firstName | default(omit) }}"
lastName: "{{ user.lastName | default(omit) }}"
validate_certs: no
body_format: json
headers:
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
status_code: 201
when: keycloak_user_serach_result.json | length == 0
- name: "Get User"
uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users?username={{ user.username }}"
validate_certs: no
headers:
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
register: keycloak_user
- name: "Update User Password"
uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users/{{ (keycloak_user.json | first).id }}/reset-password"
method: PUT
body:
type: password
temporary: false
value: "{{ user.password }}"
validate_certs: no
body_format: json
status_code:
- 200
- 204
headers:
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
register: keycloak_user

View file

@ -0,0 +1,40 @@
---
- name: "Get Realm for role"
uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ client_role.realm }}"
method: GET
status_code:
- 200
headers:
Accept: "application/json"
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
register: client_role_realm
- name: Check if Mapping is available
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:
- 200
headers:
Accept: "application/json"
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
register: client_role_user_available
- name: "Create Role Mapping"
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:
- id: "{{ item.id }}"
clientRole: "{{ item.clientRole }}"
containerId: "{{ item.containerId }}"
name: "{{ item.name }}"
composite: "{{ item.composite }}"
validate_certs: False
body_format: json
headers:
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
status_code: 204
loop: "{{ client_role_user_available.json | flatten }}"
when: item.name == client_role.role

View file

@ -0,0 +1,26 @@
---
- name: "Get User {{ user.username }}"
uri:
url: "{{ keycloak_url }}/auth/admin/realms/{{ keycloak_realm }}/users?username={{ user.username }}"
headers:
validate_certs: no
Authorization: "Bearer {{ keycloak_auth_response.json.access_token }}"
register: keycloak_user
- name: Refresh keycloak auth token
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
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
loop: "{{ user.client_roles | flatten }}"
loop_control:
loop_var: client_role

View file

@ -0,0 +1,12 @@
---
- set_fact:
required_packages:
- "{{ jvm_package | default('java-1.8.0-openjdk-devel') }}"
- unzip
- procps-ng
- initscripts
- name: "Ensures required packages are installed"
ansible.builtin.include_tasks: fastpackages/install.yml
vars:
packages_list: "{{ required_packages }}"

View file

@ -0,0 +1,7 @@
---
- name: "Restart and enable keycloack service"
systemd:
name: keycloak
enabled: yes
state: restarted
become: yes

View file

@ -0,0 +1,7 @@
---
- name: "Stop SSO service"
systemd:
name: keycloak
enabled: yes
state: stopped
become: yes

View file

@ -0,0 +1,65 @@
- name: configure keycloak service script wrapper
become: yes
template:
src: keycloak-service.sh.j2
dest: "{{ keycloak_dest }}/keycloak-service.sh"
owner: root
group: root
mode: 0755
notify:
- restart keycloak
- name: configure sysconfig file for keycloak service
become: yes
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
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
systemd:
daemon_reload: yes
when: systemdunit.changed
- name: start keycloak
systemd:
name: keycloak
enabled: yes
state: started
become: yes
- command: "systemctl status keycloak"
register: keycloak_service_status
changed_when: False
- assert:
that:
- keycloak_service_status is defined
- keycloak_service_status.stdout is defined
- meta: flush_handlers
- name: Wait until Keycloak becomes active
uri:
url: "{{ keycloak_management_url }}/health"
register: keycloak_status
until: keycloak_status.status == 200
retries: 20
delay: 10