mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-11-19 19:46:33 +00:00
Compare commits
12 Commits
feature/ke
...
2610aec293
| Author | SHA1 | Date | |
|---|---|---|---|
| 2610aec293 | |||
| 07db162368 | |||
| a526d1adc4 | |||
| ca95079111 | |||
| e410d66cb4 | |||
| ab48cf522f | |||
| 41c12bdc12 | |||
| aae463b602 | |||
| bb50551533 | |||
| 098099b41e | |||
| 0a7d767252 | |||
| d88599f76c |
@@ -43,9 +43,10 @@ plugins:
|
|||||||
enabled: true
|
enabled: true
|
||||||
discourse-akismet:
|
discourse-akismet:
|
||||||
enabled: true
|
enabled: true
|
||||||
discourse-cakeday:
|
# The following plugins moved to the default setup
|
||||||
enabled: true
|
# discourse-cakeday:
|
||||||
# discourse-solved: Seems like this plugin is now also part of the default setup
|
# enabled: true
|
||||||
|
# discourse-solved:
|
||||||
# enabled: true
|
# enabled: true
|
||||||
# discourse-voting:
|
# discourse-voting:
|
||||||
# enabled: true
|
# enabled: true
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
load_dependencies: True # When set to false the dependencies aren't loaded. Helpful for developing
|
load_dependencies: True # When set to false the dependencies aren't loaded. Helpful for developing
|
||||||
actions:
|
actions:
|
||||||
import_realm: True # Import REALM
|
import_realm: True # Import REALM
|
||||||
create_automation_client: True
|
|
||||||
features:
|
features:
|
||||||
matomo: true
|
matomo: true
|
||||||
css: true
|
css: true
|
||||||
@@ -50,4 +49,10 @@ docker:
|
|||||||
credentials:
|
credentials:
|
||||||
recaptcha:
|
recaptcha:
|
||||||
website_key: "" # Required if you enabled recaptcha:
|
website_key: "" # Required if you enabled recaptcha:
|
||||||
secret_key: "" # Required if you enabled recaptcha:
|
secret_key: "" # Required if you enabled recaptcha:
|
||||||
|
|
||||||
|
accounts:
|
||||||
|
bootstrap:
|
||||||
|
username: "administrator"
|
||||||
|
system:
|
||||||
|
username: "{{ SOFTWARE_NAME | replace('.', '_') | lower }}"
|
||||||
89
roles/web-app-keycloak/tasks/05_login.yml
Normal file
89
roles/web-app-keycloak/tasks/05_login.yml
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
- name: "Wait until '{{ KEYCLOAK_CONTAINER }}' container is healthy"
|
||||||
|
community.docker.docker_container_info:
|
||||||
|
name: "{{ KEYCLOAK_CONTAINER }}"
|
||||||
|
register: kc_info
|
||||||
|
retries: 60
|
||||||
|
delay: 5
|
||||||
|
until: >
|
||||||
|
kc_info is succeeded and
|
||||||
|
(kc_info.container | default({})) != {} and
|
||||||
|
(kc_info.container.State | default({})) != {} and
|
||||||
|
(kc_info.container.State.Health | default({})) != {} and
|
||||||
|
(kc_info.container.State.Health.Status | default('')) == 'healthy'
|
||||||
|
|
||||||
|
- name: Ensure permanent Keycloak admin exists and can log in (container env only)
|
||||||
|
block:
|
||||||
|
|
||||||
|
- name: Try login with permanent admin (uses container ENV)
|
||||||
|
shell: |
|
||||||
|
{{ KEYCLOAK_EXEC_CONTAINER }} sh -lc '
|
||||||
|
{{ KEYCLOAK_KCADM }} config credentials \
|
||||||
|
--server {{ KEYCLOAK_SERVER_INTERNAL_URL }} \
|
||||||
|
--realm master \
|
||||||
|
--user "$KEYCLOAK_PERMANENT_ADMIN_USERNAME" \
|
||||||
|
--password "$KEYCLOAK_PERMANENT_ADMIN_PASSWORD"
|
||||||
|
'
|
||||||
|
register: kc_login_perm
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
rescue:
|
||||||
|
|
||||||
|
- name: Login with bootstrap admin (uses container ENV)
|
||||||
|
shell: |
|
||||||
|
{{ KEYCLOAK_EXEC_CONTAINER }} sh -lc '
|
||||||
|
{{ KEYCLOAK_KCADM }} config credentials \
|
||||||
|
--server {{ KEYCLOAK_SERVER_INTERNAL_URL }} \
|
||||||
|
--realm master \
|
||||||
|
--user "$KC_BOOTSTRAP_ADMIN_USERNAME" \
|
||||||
|
--password "$KC_BOOTSTRAP_ADMIN_PASSWORD"
|
||||||
|
'
|
||||||
|
register: kc_login_bootstrap
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Ensure permanent admin user exists (create if missing)
|
||||||
|
shell: |
|
||||||
|
{{ KEYCLOAK_EXEC_CONTAINER }} sh -lc '
|
||||||
|
{{ KEYCLOAK_KCADM }} create users -r master \
|
||||||
|
-s "username=$KEYCLOAK_PERMANENT_ADMIN_USERNAME" \
|
||||||
|
-s "enabled=true"
|
||||||
|
'
|
||||||
|
register: kc_create_perm_admin
|
||||||
|
failed_when: >
|
||||||
|
not (
|
||||||
|
kc_create_perm_admin.rc == 0 or
|
||||||
|
(kc_create_perm_admin.stderr is defined and
|
||||||
|
('User exists with same username' in kc_create_perm_admin.stderr))
|
||||||
|
)
|
||||||
|
changed_when: kc_create_perm_admin.rc == 0
|
||||||
|
|
||||||
|
- name: Set permanent admin password (by username, no ID needed)
|
||||||
|
shell: |
|
||||||
|
{{ KEYCLOAK_EXEC_CONTAINER }} sh -lc '
|
||||||
|
{{ KEYCLOAK_KCADM }} set-password -r master \
|
||||||
|
--username "$KEYCLOAK_PERMANENT_ADMIN_USERNAME" \
|
||||||
|
--new-password "$KEYCLOAK_PERMANENT_ADMIN_PASSWORD"
|
||||||
|
'
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
|
- name: Grant global admin via master realm role 'admin'
|
||||||
|
shell: |
|
||||||
|
{{ KEYCLOAK_EXEC_CONTAINER }} sh -lc '
|
||||||
|
{{ KEYCLOAK_KCADM }} add-roles -r master \
|
||||||
|
--uusername "$KEYCLOAK_PERMANENT_ADMIN_USERNAME" \
|
||||||
|
--rolename admin
|
||||||
|
'
|
||||||
|
register: kc_grant_master_admin
|
||||||
|
changed_when: (kc_grant_master_admin.stderr is defined and kc_grant_master_admin.stderr | length > 0) or
|
||||||
|
(kc_grant_master_admin.stdout is defined and kc_grant_master_admin.stdout | length > 0)
|
||||||
|
failed_when: false
|
||||||
|
|
||||||
|
- name: Verify login with permanent admin (after creation)
|
||||||
|
shell: |
|
||||||
|
{{ KEYCLOAK_EXEC_CONTAINER }} sh -lc '
|
||||||
|
{{ KEYCLOAK_KCADM }} config credentials \
|
||||||
|
--server {{ KEYCLOAK_SERVER_INTERNAL_URL }} \
|
||||||
|
--realm master \
|
||||||
|
--user "$KEYCLOAK_PERMANENT_ADMIN_USERNAME" \
|
||||||
|
--password "$KEYCLOAK_PERMANENT_ADMIN_PASSWORD"
|
||||||
|
'
|
||||||
|
changed_when: false
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
# Creates a confidential client with service account, fetches the secret,
|
|
||||||
# and grants realm-management/realm-admin to its service-account user.
|
|
||||||
|
|
||||||
- name: "Ensure automation client exists (confidential + service accounts)"
|
|
||||||
shell: |
|
|
||||||
{{ KEYCLOAK_EXEC_KCADM }} create clients -r {{ KEYCLOAK_REALM }} \
|
|
||||||
-s clientId={{ KEYCLOAK_AUTOMATION_CLIENT_ID }} \
|
|
||||||
-s protocol=openid-connect \
|
|
||||||
-s publicClient=false \
|
|
||||||
-s serviceAccountsEnabled=true \
|
|
||||||
-s directAccessGrantsEnabled=false
|
|
||||||
register: create_client
|
|
||||||
changed_when: create_client.rc == 0
|
|
||||||
failed_when: create_client.rc != 0 and ('already exists' not in (create_client.stderr | lower))
|
|
||||||
|
|
||||||
- name: "Resolve automation client id"
|
|
||||||
shell: >
|
|
||||||
{{ KEYCLOAK_EXEC_KCADM }} get clients -r {{ KEYCLOAK_REALM }}
|
|
||||||
--query 'clientId={{ KEYCLOAK_AUTOMATION_CLIENT_ID }}' --fields id --format json | jq -r '.[0].id'
|
|
||||||
register: auto_client_id_cmd
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: "Fail if client id could not be resolved"
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "(auto_client_id_cmd.stdout | trim) is match('^[0-9a-f-]+$')"
|
|
||||||
fail_msg: "Automation client id could not be resolved."
|
|
||||||
|
|
||||||
- name: "Read client secret"
|
|
||||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
||||||
shell: >
|
|
||||||
{{ KEYCLOAK_EXEC_KCADM }} get clients/{{ auto_client_id_cmd.stdout | trim }}/client-secret
|
|
||||||
-r {{ KEYCLOAK_REALM }} --format json | jq -r .value
|
|
||||||
register: auto_client_secret_cmd
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: "Expose client secret as a fact"
|
|
||||||
set_fact:
|
|
||||||
KEYCLOAK_AUTOMATION_CLIENT_SECRET: "{{ auto_client_secret_cmd.stdout | trim }}"
|
|
||||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
||||||
|
|
||||||
- name: "Grant {{ KEYCLOAK_AUTOMATION_GRANT_ROLE }} to service account"
|
|
||||||
shell: >
|
|
||||||
{{ KEYCLOAK_EXEC_KCADM }} add-roles -r {{ KEYCLOAK_REALM }}
|
|
||||||
--uusername service-account-{{ KEYCLOAK_AUTOMATION_CLIENT_ID }}
|
|
||||||
--cclientid realm-management
|
|
||||||
--rolename {{ KEYCLOAK_AUTOMATION_GRANT_ROLE }}
|
|
||||||
register: grant_role
|
|
||||||
changed_when: grant_role.rc == 0
|
|
||||||
failed_when: grant_role.rc != 0 and ('already exists' not in (grant_role.stderr | lower))
|
|
||||||
|
|
||||||
- name: "Verify client-credentials login works"
|
|
||||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
||||||
shell: >
|
|
||||||
{{ KEYCLOAK_EXEC_KCADM }} config credentials
|
|
||||||
--server {{ KEYCLOAK_SERVER_INTERNAL_URL }}
|
|
||||||
--realm {{ KEYCLOAK_REALM }}
|
|
||||||
--client {{ KEYCLOAK_AUTOMATION_CLIENT_ID }}
|
|
||||||
--client-secret {{ KEYCLOAK_AUTOMATION_CLIENT_SECRET }} &&
|
|
||||||
{{ KEYCLOAK_EXEC_KCADM }} get realms/{{ KEYCLOAK_REALM }} --format json | jq -r '.realm'
|
|
||||||
register: verify_cc
|
|
||||||
changed_when: false
|
|
||||||
failed_when: (verify_cc.rc != 0) or ((verify_cc.stdout | trim) != (KEYCLOAK_REALM | trim))
|
|
||||||
@@ -13,118 +13,21 @@
|
|||||||
include_tasks: 04_dependencies.yml
|
include_tasks: 04_dependencies.yml
|
||||||
when: KEYCLOAK_LOAD_DEPENDENCIES | bool
|
when: KEYCLOAK_LOAD_DEPENDENCIES | bool
|
||||||
|
|
||||||
- name: "Wait until '{{ KEYCLOAK_CONTAINER }}' container is healthy"
|
- name: "Load Login routines for '{{ application_id }}'"
|
||||||
community.docker.docker_container_info:
|
include_tasks: 05_login.yml
|
||||||
name: "{{ KEYCLOAK_CONTAINER }}"
|
|
||||||
register: kc_info
|
|
||||||
retries: 60
|
|
||||||
delay: 5
|
|
||||||
until: >
|
|
||||||
kc_info is succeeded and
|
|
||||||
(kc_info.container | default({})) != {} and
|
|
||||||
(kc_info.container.State | default({})) != {} and
|
|
||||||
(kc_info.container.State.Health | default({})) != {} and
|
|
||||||
(kc_info.container.State.Health.Status | default('')) == 'healthy'
|
|
||||||
|
|
||||||
- name: kcadm login (master)
|
- name: "Load Client Update routines for '{{ application_id }}'"
|
||||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
include_tasks: update/01_client.yml
|
||||||
shell: >
|
|
||||||
{{ KEYCLOAK_EXEC_KCADM }} config credentials
|
|
||||||
--server {{ KEYCLOAK_SERVER_INTERNAL_URL }}
|
|
||||||
--realm master
|
|
||||||
--user {{ KEYCLOAK_MASTER_API_USER_NAME }}
|
|
||||||
--password {{ KEYCLOAK_MASTER_API_USER_PASSWORD }}
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Verify kcadm session works (quick read)
|
- name: "Load Mail Update routines for '{{ application_id }} - {{ KEYCLOAK_REALM }}'"
|
||||||
shell: >
|
include_tasks: update/02_mail_realm.yml
|
||||||
{{ KEYCLOAK_EXEC_KCADM }} get realms --format json | jq -r '.[0].realm' | head -n1
|
|
||||||
register: kcadm_verify
|
|
||||||
changed_when: false
|
|
||||||
failed_when: >
|
|
||||||
(kcadm_verify.rc != 0)
|
|
||||||
or ('HTTP 401' in (kcadm_verify.stderr | default('')))
|
|
||||||
or ((kcadm_verify.stdout | trim) == '')
|
|
||||||
|
|
||||||
# --- Create & grant automation service account (Option A) ---
|
|
||||||
- name: "Ensure automation service account client (Option A)"
|
|
||||||
include_tasks: 05a_service_account.yml
|
|
||||||
when: applications | get_app_conf(application_id, 'actions.create_automation_client', True)
|
|
||||||
|
|
||||||
# --- Switch session to the service account for all subsequent API work ---
|
- name: "Load Mail Update routines for '{{ application_id }} - master'"
|
||||||
- name: kcadm login (realm) using service account
|
include_tasks: update/03_mail_master.yml
|
||||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
||||||
shell: >
|
|
||||||
{{ KEYCLOAK_EXEC_KCADM }} config credentials
|
|
||||||
--server {{ KEYCLOAK_SERVER_INTERNAL_URL }}
|
|
||||||
--realm {{ KEYCLOAK_REALM }}
|
|
||||||
--client {{ KEYCLOAK_AUTOMATION_CLIENT_ID }}
|
|
||||||
--client-secret {{ KEYCLOAK_AUTOMATION_CLIENT_SECRET }}
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
- name: Verify kcadm session works (exact realm via service account)
|
- name: "Load RBAC Update routines for '{{ application_id }}'"
|
||||||
shell: >
|
include_tasks: update/04_rbac_client_scope.yml
|
||||||
{{ KEYCLOAK_EXEC_KCADM }} get realms/{{ KEYCLOAK_REALM }} --format json | jq -r '.realm'
|
|
||||||
register: kcadm_verify_sa
|
|
||||||
changed_when: false
|
|
||||||
failed_when: >
|
|
||||||
(kcadm_verify_sa.rc != 0)
|
|
||||||
or ('HTTP 401' in (kcadm_verify_sa.stderr | default('')))
|
|
||||||
or ((kcadm_verify_sa.stdout | trim) != (KEYCLOAK_REALM | trim))
|
|
||||||
|
|
||||||
- name: "Update Client settings"
|
- name: "Load LDAP Update routines for '{{ application_id }}'"
|
||||||
vars:
|
include_tasks: update/05_ldap.yml
|
||||||
kc_object_kind: "client"
|
|
||||||
kc_lookup_value: "{{ KEYCLOAK_CLIENT_ID }}"
|
|
||||||
kc_desired: >-
|
|
||||||
{{
|
|
||||||
KEYCLOAK_DICTIONARY_REALM.clients
|
|
||||||
| selectattr('clientId','equalto', KEYCLOAK_CLIENT_ID)
|
|
||||||
| list | first
|
|
||||||
}}
|
|
||||||
kc_force_attrs:
|
|
||||||
publicClient: >-
|
|
||||||
{{
|
|
||||||
(KEYCLOAK_DICTIONARY_REALM.clients
|
|
||||||
| selectattr('clientId','equalto', KEYCLOAK_CLIENT_ID)
|
|
||||||
| map(attribute='publicClient')
|
|
||||||
| first)
|
|
||||||
}}
|
|
||||||
serviceAccountsEnabled: >-
|
|
||||||
{{
|
|
||||||
(KEYCLOAK_DICTIONARY_REALM.clients
|
|
||||||
| selectattr('clientId','equalto', KEYCLOAK_CLIENT_ID)
|
|
||||||
| map(attribute='serviceAccountsEnabled')
|
|
||||||
| first )
|
|
||||||
}}
|
|
||||||
frontchannelLogout: >-
|
|
||||||
{{
|
|
||||||
(KEYCLOAK_DICTIONARY_REALM.clients
|
|
||||||
| selectattr('clientId','equalto', KEYCLOAK_CLIENT_ID)
|
|
||||||
| map(attribute='frontchannelLogout')
|
|
||||||
| first)
|
|
||||||
}}
|
|
||||||
attributes: >-
|
|
||||||
{{
|
|
||||||
( (KEYCLOAK_DICTIONARY_REALM.clients
|
|
||||||
| selectattr('clientId','equalto', KEYCLOAK_CLIENT_ID)
|
|
||||||
| list | first | default({}) ).attributes | default({}) )
|
|
||||||
| combine({'frontchannel.logout.url': KEYCLOAK_FRONTCHANNEL_LOGOUT_URL}, recursive=True)
|
|
||||||
}}
|
|
||||||
include_tasks: _update.yml
|
|
||||||
|
|
||||||
- name: "Update REALM mail settings from realm dictionary (SPOT)"
|
|
||||||
include_tasks: _update.yml
|
|
||||||
vars:
|
|
||||||
kc_object_kind: "realm"
|
|
||||||
kc_lookup_field: "id"
|
|
||||||
kc_lookup_value: "{{ KEYCLOAK_REALM }}"
|
|
||||||
kc_desired:
|
|
||||||
smtpServer: "{{ KEYCLOAK_DICTIONARY_REALM.smtpServer | default({}, true) }}"
|
|
||||||
kc_merge_path: "smtpServer"
|
|
||||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
|
||||||
|
|
||||||
- include_tasks: 05_rbac_client_scope.yml
|
|
||||||
|
|
||||||
- include_tasks: 06_ldap.yml
|
|
||||||
when: KEYCLOAK_LDAP_ENABLED | bool
|
when: KEYCLOAK_LDAP_ENABLED | bool
|
||||||
|
|||||||
40
roles/web-app-keycloak/tasks/update/01_client.yml
Normal file
40
roles/web-app-keycloak/tasks/update/01_client.yml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
- name: "Update Client settings"
|
||||||
|
vars:
|
||||||
|
kc_object_kind: "client"
|
||||||
|
kc_lookup_value: "{{ KEYCLOAK_CLIENT_ID }}"
|
||||||
|
kc_desired: >-
|
||||||
|
{{
|
||||||
|
KEYCLOAK_DICTIONARY_REALM.clients
|
||||||
|
| selectattr('clientId','equalto', KEYCLOAK_CLIENT_ID)
|
||||||
|
| list | first
|
||||||
|
}}
|
||||||
|
kc_force_attrs:
|
||||||
|
publicClient: >-
|
||||||
|
{{
|
||||||
|
(KEYCLOAK_DICTIONARY_REALM.clients
|
||||||
|
| selectattr('clientId','equalto', KEYCLOAK_CLIENT_ID)
|
||||||
|
| map(attribute='publicClient')
|
||||||
|
| first)
|
||||||
|
}}
|
||||||
|
serviceAccountsEnabled: >-
|
||||||
|
{{
|
||||||
|
(KEYCLOAK_DICTIONARY_REALM.clients
|
||||||
|
| selectattr('clientId','equalto', KEYCLOAK_CLIENT_ID)
|
||||||
|
| map(attribute='serviceAccountsEnabled')
|
||||||
|
| first )
|
||||||
|
}}
|
||||||
|
frontchannelLogout: >-
|
||||||
|
{{
|
||||||
|
(KEYCLOAK_DICTIONARY_REALM.clients
|
||||||
|
| selectattr('clientId','equalto', KEYCLOAK_CLIENT_ID)
|
||||||
|
| map(attribute='frontchannelLogout')
|
||||||
|
| first)
|
||||||
|
}}
|
||||||
|
attributes: >-
|
||||||
|
{{
|
||||||
|
( (KEYCLOAK_DICTIONARY_REALM.clients
|
||||||
|
| selectattr('clientId','equalto', KEYCLOAK_CLIENT_ID)
|
||||||
|
| list | first | default({}) ).attributes | default({}) )
|
||||||
|
| combine({'frontchannel.logout.url': KEYCLOAK_FRONTCHANNEL_LOGOUT_URL}, recursive=True)
|
||||||
|
}}
|
||||||
|
include_tasks: _update.yml
|
||||||
10
roles/web-app-keycloak/tasks/update/02_mail_realm.yml
Normal file
10
roles/web-app-keycloak/tasks/update/02_mail_realm.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
- name: "Update {{ KEYCLOAK_REALM }} REALM mail settings from realm dictionary"
|
||||||
|
include_tasks: _update.yml
|
||||||
|
vars:
|
||||||
|
kc_object_kind: "realm"
|
||||||
|
kc_lookup_field: "id"
|
||||||
|
kc_lookup_value: "{{ KEYCLOAK_REALM }}"
|
||||||
|
kc_desired:
|
||||||
|
smtpServer: "{{ KEYCLOAK_DICTIONARY_REALM.smtpServer | default({}, true) }}"
|
||||||
|
kc_merge_path: "smtpServer"
|
||||||
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||||
10
roles/web-app-keycloak/tasks/update/03_mail_master.yml
Normal file
10
roles/web-app-keycloak/tasks/update/03_mail_master.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
- name: "Update Master REALM mail settings from realm dictionary"
|
||||||
|
include_tasks: _update.yml
|
||||||
|
vars:
|
||||||
|
kc_object_kind: "realm"
|
||||||
|
kc_lookup_field: "id"
|
||||||
|
kc_lookup_value: "master"
|
||||||
|
kc_desired:
|
||||||
|
smtpServer: "{{ KEYCLOAK_DICTIONARY_REALM.smtpServer | default({}, true) }}"
|
||||||
|
kc_merge_path: "smtpServer"
|
||||||
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
# --- Ensure RBAC client scope exists (idempotent) ---
|
|
||||||
- name: Ensure RBAC client scope exists
|
- name: Ensure RBAC client scope exists
|
||||||
shell: |
|
shell: |
|
||||||
cat <<'JSON' | {{ KEYCLOAK_EXEC_KCADM }} create client-scopes -r {{ KEYCLOAK_REALM }} -f -
|
cat <<'JSON' | {{ KEYCLOAK_EXEC_KCADM }} create client-scopes -r {{ KEYCLOAK_REALM }} -f -
|
||||||
@@ -16,12 +15,10 @@
|
|||||||
('already exists' not in (create_rbac_scope.stderr | lower))
|
('already exists' not in (create_rbac_scope.stderr | lower))
|
||||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||||
|
|
||||||
# --- Get the scope id we will attach to the client ---
|
|
||||||
- name: Get all client scopes
|
- name: Get all client scopes
|
||||||
shell: "{{ KEYCLOAK_EXEC_KCADM }} get client-scopes -r {{ KEYCLOAK_REALM }} --format json"
|
shell: "{{ KEYCLOAK_EXEC_KCADM }} get client-scopes -r {{ KEYCLOAK_REALM }} --format json"
|
||||||
register: all_scopes
|
register: all_scopes
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: "'HTTP 401' in (all_scopes.stderr | default(''))"
|
|
||||||
|
|
||||||
- name: Extract RBAC scope id
|
- name: Extract RBAC scope id
|
||||||
set_fact:
|
set_fact:
|
||||||
@@ -10,19 +10,21 @@ KC_HTTP_ENABLED= true
|
|||||||
KC_HEALTH_ENABLED= {{ KEYCLOAK_HEALTH_ENABLED | lower }}
|
KC_HEALTH_ENABLED= {{ KEYCLOAK_HEALTH_ENABLED | lower }}
|
||||||
KC_METRICS_ENABLED= true
|
KC_METRICS_ENABLED= true
|
||||||
|
|
||||||
# Administrator
|
|
||||||
KEYCLOAK_ADMIN= "{{ KEYCLOAK_ADMIN }}"
|
|
||||||
KEYCLOAK_ADMIN_PASSWORD= "{{ KEYCLOAK_ADMIN_PASSWORD }}"
|
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
KC_DB= {{ database_type }}
|
KC_DB= {{ database_type }}
|
||||||
KC_DB_URL= {{ database_url_jdbc }}
|
KC_DB_URL= {{ database_url_jdbc }}
|
||||||
KC_DB_USERNAME= {{ database_username }}
|
KC_DB_USERNAME= {{ database_username }}
|
||||||
KC_DB_PASSWORD= {{ database_password }}
|
KC_DB_PASSWORD= {{ database_password }}
|
||||||
|
|
||||||
# If the initial administrator already exists and the environment variables are still present at startup, an error message stating the failed creation of the initial administrator is shown in the logs. Keycloak ignores the values and starts up correctly.
|
# Credentials
|
||||||
KC_BOOTSTRAP_ADMIN_USERNAME= "{{ KEYCLOAK_ADMIN }}"
|
|
||||||
KC_BOOTSTRAP_ADMIN_PASSWORD= "{{ KEYCLOAK_ADMIN_PASSWORD }}"
|
## Bootstrap
|
||||||
|
KC_BOOTSTRAP_ADMIN_USERNAME="{{ KEYCLOAK_BOOTSTRAP_ADMIN_USERNAME }}"
|
||||||
|
KC_BOOTSTRAP_ADMIN_PASSWORD="{{ KEYCLOAK_BOOTSTRAP_ADMIN_PASSWORD }}"
|
||||||
|
|
||||||
|
## Permanent
|
||||||
|
KEYCLOAK_PERMANENT_ADMIN_USERNAME="{{ KEYCLOAK_PERMANENT_ADMIN_USERNAME }}"
|
||||||
|
KEYCLOAK_PERMANENT_ADMIN_PASSWORD="{{ KEYCLOAK_PERMANENT_ADMIN_PASSWORD }}"
|
||||||
|
|
||||||
# Enable detailed logs
|
# Enable detailed logs
|
||||||
{% if MODE_DEBUG | bool %}
|
{% if MODE_DEBUG | bool %}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
users:
|
|
||||||
administrator:
|
|
||||||
username: "administrator"
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# General
|
# General
|
||||||
application_id: "web-app-keycloak" # Internal Infinito.Nexus application id
|
application_id: "web-app-keycloak" # Internal Infinito.Nexus application id
|
||||||
database_type: "postgres" # Database which will be used
|
database_type: "postgres" # Database which will be used
|
||||||
|
|
||||||
# Keycloak
|
# Keycloak
|
||||||
|
|
||||||
@@ -29,21 +29,22 @@ KEYCLOAK_REALM_IMPORT_FILE_SRC: "import/realm.json.j2"
|
|||||||
KEYCLOAK_REALM_IMPORT_FILE_DST: "{{ [KEYCLOAK_REALM_IMPORT_DIR_HOST,'realm.json'] | path_join }}"
|
KEYCLOAK_REALM_IMPORT_FILE_DST: "{{ [KEYCLOAK_REALM_IMPORT_DIR_HOST,'realm.json'] | path_join }}"
|
||||||
|
|
||||||
## Credentials
|
## Credentials
|
||||||
KEYCLOAK_ADMIN: "{{ applications | get_app_conf(application_id, 'users.administrator.username') }}"
|
|
||||||
KEYCLOAK_ADMIN_PASSWORD: "{{ applications | get_app_conf(application_id, 'credentials.administrator_password') }}"
|
### Bootstrap
|
||||||
|
KEYCLOAK_BOOTSTRAP_ADMIN_USERNAME: "{{ applications | get_app_conf(application_id, 'accounts.bootstrap.username') }}"
|
||||||
|
KEYCLOAK_BOOTSTRAP_ADMIN_PASSWORD: "{{ applications | get_app_conf(application_id, 'credentials.administrator_password') }}"
|
||||||
|
|
||||||
|
### Permanent
|
||||||
|
KEYCLOAK_PERMANENT_ADMIN_USERNAME: "{{ applications | get_app_conf(application_id, 'accounts.system.username') }}"
|
||||||
|
KEYCLOAK_PERMANENT_ADMIN_PASSWORD: "{{ applications | get_app_conf(application_id, 'credentials.administrator_password') }}"
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
KEYCLOAK_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.name') }}" # Name of the keycloak docker container
|
KEYCLOAK_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.name') }}"
|
||||||
KEYCLOAK_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.image') }}" # Keycloak docker image
|
KEYCLOAK_EXEC_CONTAINER: "docker exec -i {{ KEYCLOAK_CONTAINER }}"
|
||||||
KEYCLOAK_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.version') }}" # Keycloak docker version
|
KEYCLOAK_KCADM: "/opt/keycloak/bin/kcadm.sh"
|
||||||
KEYCLOAK_KCADM_CONFIG: "/opt/keycloak/data/kcadm.config"
|
KEYCLOAK_EXEC_KCADM: "{{ KEYCLOAK_EXEC_CONTAINER }} {{ KEYCLOAK_KCADM }}"
|
||||||
KEYCLOAK_EXEC_KCADM: "docker exec -i {{ KEYCLOAK_CONTAINER }} /opt/keycloak/bin/kcadm.sh --config {{ KEYCLOAK_KCADM_CONFIG }}"
|
KEYCLOAK_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.image') }}"
|
||||||
|
KEYCLOAK_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.version') }}"
|
||||||
## Automation Service Account (Option A)
|
|
||||||
KEYCLOAK_AUTOMATION_CLIENT_ID: "infinito-automation"
|
|
||||||
KEYCLOAK_AUTOMATION_GRANT_ROLE: "realm-admin" # or granular roles if you prefer
|
|
||||||
# Will be discovered dynamically and set as a fact during the run:
|
|
||||||
# KEYCLOAK_AUTOMATION_CLIENT_SECRET
|
|
||||||
|
|
||||||
## Server
|
## Server
|
||||||
KEYCLOAK_SERVER_HOST: "127.0.0.1:{{ ports.localhost.http[application_id] }}"
|
KEYCLOAK_SERVER_HOST: "127.0.0.1:{{ ports.localhost.http[application_id] }}"
|
||||||
@@ -76,11 +77,6 @@ KEYCLOAK_LDAP_USER_OBJECT_CLASSES: >
|
|||||||
) | join(', ')
|
) | join(', ')
|
||||||
}}
|
}}
|
||||||
|
|
||||||
## API
|
|
||||||
KEYCLOAK_MASTER_API_USER: "{{ applications | get_app_conf(application_id, 'users.administrator') }}" # Master Administrator
|
|
||||||
KEYCLOAK_MASTER_API_USER_NAME: "{{ KEYCLOAK_MASTER_API_USER.username }}" # Master Administrator Username
|
|
||||||
KEYCLOAK_MASTER_API_USER_PASSWORD: "{{ KEYCLOAK_MASTER_API_USER.password }}" # Master Administrator Password
|
|
||||||
|
|
||||||
# Dictionaries
|
# Dictionaries
|
||||||
KEYCLOAK_DICTIONARY_REALM_RAW: "{{ lookup('template', 'import/realm.json.j2') }}"
|
KEYCLOAK_DICTIONARY_REALM_RAW: "{{ lookup('template', 'import/realm.json.j2') }}"
|
||||||
KEYCLOAK_DICTIONARY_REALM: >-
|
KEYCLOAK_DICTIONARY_REALM: >-
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
features:
|
features:
|
||||||
matomo: true
|
matomo: true
|
||||||
css: true
|
css: true
|
||||||
desktop: true
|
desktop: true
|
||||||
logout: false
|
logout: false
|
||||||
server:
|
server:
|
||||||
csp:
|
csp:
|
||||||
whitelist:
|
whitelist:
|
||||||
@@ -16,14 +16,15 @@ server:
|
|||||||
font-src:
|
font-src:
|
||||||
- https://cdnjs.cloudflare.com
|
- https://cdnjs.cloudflare.com
|
||||||
frame-src:
|
frame-src:
|
||||||
- "{{ WEB_PROTOCOL }}://*.{{ PRIMARY_DOMAIN }}" # Makes sense that all of the website content is available in the navigator
|
# Makes sense that all of the website content is available in the navigator
|
||||||
|
- "{{ WEB_PROTOCOL }}://*.{{ PRIMARY_DOMAIN }}"
|
||||||
flags:
|
flags:
|
||||||
style-src:
|
style-src:
|
||||||
unsafe-inline: true
|
unsafe-inline: true
|
||||||
script-src:
|
script-src:
|
||||||
unsafe-eval: true
|
unsafe-eval: true
|
||||||
script-src-elem:
|
script-src-elem:
|
||||||
unsafe-inline: true
|
unsafe-inline: true
|
||||||
domains:
|
domains:
|
||||||
canonical:
|
canonical:
|
||||||
- "slides.{{ PRIMARY_DOMAIN }}"
|
- "slides.{{ PRIMARY_DOMAIN }}"
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
galaxy_info:
|
galaxy_info:
|
||||||
author: "Kevin Veen-Birkenbach"
|
author: "Kevin Veen-Birkenbach"
|
||||||
description: "An interactive presentation platform focused on guiding end-users through the practical use of the Infinito.Nexus software. Designed to demonstrate features, workflows, and real-world applications for Administrators, Developers, End-Users, Businesses, and Investors."
|
description: "An interactive presentation platform focused on guiding end-users through the practical use of the Infinito.Nexus software. Designed to demonstrate features, workflows, and real-world applications for Administrators, Developers, End-Users, Businesses, and Investors."
|
||||||
license: "Infinito.Nexus NonCommercial License"
|
license: "Infinito.Nexus NonCommercial License"
|
||||||
license_url: "https://s.infinito.nexus/license"
|
license_url: "https://s.infinito.nexus/license"
|
||||||
company: |
|
company: |
|
||||||
Kevin Veen-Birkenbach
|
Kevin Veen-Birkenbach
|
||||||
Consulting & Coaching Solutions
|
Consulting & Coaching Solutions
|
||||||
|
|||||||
@@ -28,14 +28,17 @@ BUILTIN_FILTERS: Set[str] = {
|
|||||||
"int", "join", "last", "length", "list", "lower", "map", "min", "max", "random",
|
"int", "join", "last", "length", "list", "lower", "map", "min", "max", "random",
|
||||||
"reject", "rejectattr", "replace", "reverse", "round", "safe", "select",
|
"reject", "rejectattr", "replace", "reverse", "round", "safe", "select",
|
||||||
"selectattr", "slice", "sort", "string", "striptags", "sum", "title", "trim",
|
"selectattr", "slice", "sort", "string", "striptags", "sum", "title", "trim",
|
||||||
"truncate", "unique", "upper", "urlencode", "urlize", "wordcount", "xmlattr",
|
"truncate", "unique", "upper", "urlencode", "urlize", "wordcount", "xmlattr","contains",
|
||||||
|
|
||||||
# Common Ansible filters (subset, extend as needed)
|
# Common Ansible filters (subset, extend as needed)
|
||||||
"b64decode", "b64encode", "basename", "dirname", "from_json", "to_json",
|
"b64decode", "b64encode", "basename", "dirname", "from_json", "to_json",
|
||||||
"from_yaml", "to_yaml", "combine", "difference", "intersect",
|
"from_yaml", "to_yaml", "combine", "difference", "intersect",
|
||||||
"flatten", "zip", "regex_search", "regex_replace", "bool",
|
"flatten", "zip", "regex_search", "regex_replace", "bool",
|
||||||
"type_debug", "json_query", "mandatory", "hash", "checksum",
|
"type_debug", "json_query", "mandatory", "hash", "checksum",
|
||||||
"lower", "upper", "capitalize", "unique", "dict2items", "items2dict", "password_hash", "path_join", "product", "quote", "split", "ternary", "to_nice_yaml", "tojson",
|
"lower", "upper", "capitalize", "unique", "dict2items", "items2dict",
|
||||||
|
"password_hash", "path_join", "product", "quote", "split", "ternary", "to_nice_yaml",
|
||||||
|
"tojson", "to_nice_json",
|
||||||
|
|
||||||
|
|
||||||
# Date/time-ish
|
# Date/time-ish
|
||||||
"strftime",
|
"strftime",
|
||||||
|
|||||||
Reference in New Issue
Block a user