mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-11-18 02:56:31 +00:00
Compare commits
7 Commits
feature/ke
...
ab48cf522f
| Author | SHA1 | Date | |
|---|---|---|---|
| ab48cf522f | |||
| 41c12bdc12 | |||
| aae463b602 | |||
| bb50551533 | |||
| 098099b41e | |||
| 0a7d767252 | |||
| d88599f76c |
@@ -1,6 +1,6 @@
|
||||
load_dependencies: True # When set to false the dependencies aren't loaded. Helpful for developing
|
||||
actions:
|
||||
import_realm: True # Import REALM
|
||||
import_realm: True # Import REALM
|
||||
features:
|
||||
matomo: true
|
||||
css: true
|
||||
@@ -49,4 +49,10 @@ docker:
|
||||
credentials:
|
||||
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 }}"
|
||||
78
roles/web-app-keycloak/tasks/05_login.yml
Normal file
78
roles/web-app-keycloak/tasks/05_login.yml
Normal file
@@ -0,0 +1,78 @@
|
||||
- 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 '
|
||||
# Try to create; if it already exists, Keycloak returns 409
|
||||
{{ 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 realm-admin role to permanent admin (by username)
|
||||
shell: |
|
||||
{{ KEYCLOAK_EXEC_CONTAINER }} sh -lc '
|
||||
{{ KEYCLOAK_KCADM }} add-roles -r master \
|
||||
--uusername "$KEYCLOAK_PERMANENT_ADMIN_USERNAME" \
|
||||
--cclientid realm-management \
|
||||
--rolename realm-admin
|
||||
'
|
||||
register: kc_grant_admin
|
||||
changed_when: (kc_grant_admin.stderr is defined and kc_grant_admin.stderr | length > 0) or
|
||||
(kc_grant_admin.stdout is defined and kc_grant_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
|
||||
@@ -13,82 +13,18 @@
|
||||
include_tasks: 04_dependencies.yml
|
||||
when: KEYCLOAK_LOAD_DEPENDENCIES | bool
|
||||
|
||||
- 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: "Load Login routines for '{{ application_id }}'"
|
||||
include_tasks: 05_login.yml
|
||||
|
||||
- name: kcadm login (master)
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
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: "Load Client Update routines for '{{ application_id }}'"
|
||||
include_tasks: update/01_client.yml
|
||||
|
||||
- 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
|
||||
- name: "Load Mail Update routines for '{{ application_id }}'"
|
||||
include_tasks: update/02_mail.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 }}"
|
||||
- name: "Load RBAC Update routines for '{{ application_id }}'"
|
||||
include_tasks: update/03_rbac_client_scope.yml
|
||||
|
||||
- include_tasks: 05_rbac_client_scope.yml
|
||||
|
||||
- include_tasks: 06_ldap.yml
|
||||
- name: "Load LDAP Update routines for '{{ application_id }}'"
|
||||
include_tasks: update/04_ldap.yml
|
||||
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.yml
Normal file
10
roles/web-app-keycloak/tasks/update/02_mail.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
- 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 }}"
|
||||
@@ -1,4 +1,3 @@
|
||||
# --- Ensure RBAC client scope exists (idempotent) ---
|
||||
- name: Ensure RBAC client scope exists
|
||||
shell: |
|
||||
cat <<'JSON' | {{ KEYCLOAK_EXEC_KCADM }} create client-scopes -r {{ KEYCLOAK_REALM }} -f -
|
||||
@@ -16,7 +15,6 @@
|
||||
('already exists' not in (create_rbac_scope.stderr | lower))
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
# --- Get the scope id we will attach to the client ---
|
||||
- name: Get all client scopes
|
||||
shell: "{{ KEYCLOAK_EXEC_KCADM }} get client-scopes -r {{ KEYCLOAK_REALM }} --format json"
|
||||
register: all_scopes
|
||||
@@ -10,19 +10,21 @@ KC_HTTP_ENABLED= true
|
||||
KC_HEALTH_ENABLED= {{ KEYCLOAK_HEALTH_ENABLED | lower }}
|
||||
KC_METRICS_ENABLED= true
|
||||
|
||||
# Administrator
|
||||
KEYCLOAK_ADMIN= "{{ KEYCLOAK_ADMIN }}"
|
||||
KEYCLOAK_ADMIN_PASSWORD= "{{ KEYCLOAK_ADMIN_PASSWORD }}"
|
||||
|
||||
# Database
|
||||
KC_DB= {{ database_type }}
|
||||
KC_DB_URL= {{ database_url_jdbc }}
|
||||
KC_DB_USERNAME= {{ database_username }}
|
||||
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.
|
||||
KC_BOOTSTRAP_ADMIN_USERNAME= "{{ KEYCLOAK_ADMIN }}"
|
||||
KC_BOOTSTRAP_ADMIN_PASSWORD= "{{ KEYCLOAK_ADMIN_PASSWORD }}"
|
||||
# Credentials
|
||||
|
||||
## 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
|
||||
{% if MODE_DEBUG | bool %}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
users:
|
||||
administrator:
|
||||
username: "administrator"
|
||||
@@ -29,14 +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 }}"
|
||||
|
||||
## 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
|
||||
KEYCLOAK_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.name') }}" # Name of the keycloak docker container
|
||||
KEYCLOAK_EXEC_KCADM: "docker exec -i {{ KEYCLOAK_CONTAINER }} /opt/keycloak/bin/kcadm.sh" # Init script for keycloak
|
||||
KEYCLOAK_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.image') }}" # Keycloak docker image
|
||||
KEYCLOAK_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.version') }}" # Keycloak docker version
|
||||
KEYCLOAK_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.name') }}"
|
||||
KEYCLOAK_EXEC_CONTAINER: "docker exec -i {{ KEYCLOAK_CONTAINER }}"
|
||||
KEYCLOAK_KCADM: "/opt/keycloak/bin/kcadm.sh"
|
||||
KEYCLOAK_EXEC_KCADM: "{{ KEYCLOAK_EXEC_CONTAINER }} {{ KEYCLOAK_KCADM }}"
|
||||
KEYCLOAK_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.image') }}"
|
||||
KEYCLOAK_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.version') }}"
|
||||
|
||||
## Server
|
||||
KEYCLOAK_SERVER_HOST: "127.0.0.1:{{ ports.localhost.http[application_id] }}"
|
||||
@@ -69,11 +77,6 @@ KEYCLOAK_LDAP_USER_OBJECT_CLASSES: >
|
||||
) | 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
|
||||
KEYCLOAK_DICTIONARY_REALM_RAW: "{{ lookup('template', 'import/realm.json.j2') }}"
|
||||
KEYCLOAK_DICTIONARY_REALM: >-
|
||||
|
||||
@@ -28,14 +28,17 @@ BUILTIN_FILTERS: Set[str] = {
|
||||
"int", "join", "last", "length", "list", "lower", "map", "min", "max", "random",
|
||||
"reject", "rejectattr", "replace", "reverse", "round", "safe", "select",
|
||||
"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)
|
||||
"b64decode", "b64encode", "basename", "dirname", "from_json", "to_json",
|
||||
"from_yaml", "to_yaml", "combine", "difference", "intersect",
|
||||
"flatten", "zip", "regex_search", "regex_replace", "bool",
|
||||
"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
|
||||
"strftime",
|
||||
|
||||
Reference in New Issue
Block a user