mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-11-19 11:36:39 +00:00
Compare commits
1 Commits
3da645f3b8
...
feature/ke
| Author | SHA1 | Date | |
|---|---|---|---|
| 6fcf6a1ab6 |
@@ -5,6 +5,6 @@ MODE_DUMMY: false # Executes dummy/test routines instead
|
||||
MODE_UPDATE: true # Executes updates
|
||||
MODE_DEBUG: false # This enables debugging in ansible and in the apps, You SHOULD NOT enable this on production servers
|
||||
MODE_RESET: false # Cleans up all Infinito.Nexus files. It's necessary to run to whole playbook and not particial roles when using this function.
|
||||
MODE_CLEANUP: true # Cleanup unused files and configurations
|
||||
MODE_CLEANUP: "{{ MODE_DEBUG | bool }}" # Cleanup unused files and configurations
|
||||
MODE_ASSERT: "{{ MODE_DEBUG | bool }}" # Executes validation tasks during the run.
|
||||
MODE_BACKUP: true # Executes the Backup before the deployment
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
- name: Include dependencies
|
||||
include_role:
|
||||
name: "sys-svc-msmtp"
|
||||
when: run_once_sys_svc_msmtp is not defined or run_once_sys_svc_msmtp is false
|
||||
name: '{{ item }}'
|
||||
loop:
|
||||
- sys-svc-msmtp
|
||||
|
||||
- include_role:
|
||||
name: sys-service
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
name: sys-service
|
||||
vars:
|
||||
system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}"
|
||||
system_service_tpl_exec_start: "{{ system_service_script_exec }} --backups-folder-path {{ BACKUPS_FOLDER_PATH }} --maximum-backup-size-percent {{ SIZE_PERCENT_MAXIMUM_BACKUP }}"
|
||||
system_service_tpl_exec_start: "{{ system_service_script_exec }} --backups-folder-path {{ BACKUPS_FOLDER_PATH }} --maximum-backup-size-percent {{SIZE_PERCENT_MAXIMUM_BACKUP}}"
|
||||
system_service_tpl_exec_start_pre: '/usr/bin/python {{ PATH_SYSTEM_LOCK_SCRIPT }} {{ SYS_SERVICE_GROUP_MANIPULATION | join(" ") }} --ignore {{ SYS_SERVICE_GROUP_CLEANUP | join(" ") }} --timeout "{{ SYS_TIMEOUT_BACKUP_SERVICES }}"'
|
||||
system_service_copy_files: true
|
||||
system_service_force_linear_sync: false
|
||||
|
||||
@@ -39,18 +39,6 @@ if [ "$force_freeing" = true ]; then
|
||||
docker exec -u www-data $nextcloud_application_container /var/www/html/occ versions:cleanup || exit 6
|
||||
fi
|
||||
|
||||
# Mastodon cleanup (remote media cache)
|
||||
mastodon_application_container="{{ applications | get_app_conf('web-app-mastodon', 'docker.services.mastodon.name') }}"
|
||||
mastodon_cleanup_days="1"
|
||||
|
||||
if [ -n "$mastodon_application_container" ] && docker ps -a --format '{% raw %}{{.Names}}{% endraw %}' | grep -qw "$mastodon_application_container"; then
|
||||
echo "Cleaning up Mastodon media cache (older than ${mastodon_cleanup_days} days)" &&
|
||||
docker exec -u root "$mastodon_application_container" bash -lc "bin/tootctl media remove --days=${mastodon_cleanup_days}" || exit 8
|
||||
|
||||
# Optional: additionally remove local thumbnail/cache files older than X days
|
||||
# Warning: these will be regenerated when accessed, which may cause extra CPU/I/O load
|
||||
# docker exec -u root "$mastodon_application_container" bash -lc "find /mastodon/public/system/cache -type f -mtime +${mastodon_cleanup_days} -delete" || exit 9
|
||||
fi
|
||||
fi
|
||||
|
||||
if command -v pacman >/dev/null 2>&1 ; then
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
- name: Include dependency 'web-svc-logout'
|
||||
- name: Include dependency 'sys-svc-webserver-core'
|
||||
include_role:
|
||||
name: web-svc-logout
|
||||
name: sys-svc-webserver-core
|
||||
when:
|
||||
- run_once_web_svc_logout is not defined
|
||||
- run_once_sys_svc_webserver_core is not defined
|
||||
|
||||
- name: "deploy the logout.js"
|
||||
include_tasks: "02_deploy.yml"
|
||||
|
||||
- set_fact:
|
||||
run_once_sys_front_inj_logout: true
|
||||
changed_when: false
|
||||
include_tasks: "02_deploy.yml"
|
||||
@@ -1,5 +1,7 @@
|
||||
- name: "Load base for '{{ application_id }}'"
|
||||
include_tasks: 01_core.yml
|
||||
- block:
|
||||
- include_tasks: 01_core.yml
|
||||
- set_fact:
|
||||
run_once_sys_front_inj_logout: true
|
||||
when: run_once_sys_front_inj_logout is not defined
|
||||
|
||||
- name: "Load logout code for '{{ application_id }}'"
|
||||
|
||||
@@ -14,7 +14,4 @@
|
||||
|
||||
- include_role:
|
||||
name: sys-ctl-hlth-msmtp
|
||||
when: run_once_sys_ctl_hlth_msmtp is not defined
|
||||
|
||||
- set_fact:
|
||||
run_once_sys_svc_msmtp: true
|
||||
when: run_once_sys_ctl_hlth_msmtp is not defined
|
||||
@@ -1,6 +1,5 @@
|
||||
- name: "Load MSMTP Core Once"
|
||||
include_tasks: 01_core.yml
|
||||
when:
|
||||
- run_once_sys_svc_msmtp is not defined or run_once_sys_svc_msmtp is false
|
||||
# Just execute when mailu_token is defined
|
||||
- users['no-reply'].mailu_token is defined
|
||||
- block:
|
||||
- include_tasks: 01_core.yml
|
||||
- set_fact:
|
||||
run_once_sys_svc_msmtp: true
|
||||
when: run_once_sys_svc_msmtp is not defined
|
||||
@@ -5,7 +5,7 @@ users:
|
||||
username: "{{ PRIMARY_DOMAIN.split('.')[0] }}"
|
||||
tld:
|
||||
description: "Auto Generated Account to reserve the TLD"
|
||||
username: "{{ PRIMARY_DOMAIN.split('.')[1] if (PRIMARY_DOMAIN is defined and (PRIMARY_DOMAIN.split('.') | length) > 1) else (PRIMARY_DOMAIN ~ '_tld ') }}"
|
||||
username: "{{ PRIMARY_DOMAIN.split('.')[1] }}"
|
||||
root:
|
||||
username: root
|
||||
uid: 0
|
||||
|
||||
@@ -43,10 +43,9 @@ plugins:
|
||||
enabled: true
|
||||
discourse-akismet:
|
||||
enabled: true
|
||||
# The following plugins moved to the default setup
|
||||
# discourse-cakeday:
|
||||
# enabled: true
|
||||
# discourse-solved:
|
||||
discourse-cakeday:
|
||||
enabled: true
|
||||
# discourse-solved: Seems like this plugin is now also part of the default setup
|
||||
# enabled: true
|
||||
# discourse-voting:
|
||||
# enabled: true
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
#!/bin/sh
|
||||
# POSIX-safe entrypoint for EspoCRM container
|
||||
# Compatible with /bin/sh (dash/busybox). Avoids 'pipefail' and non-portable features.
|
||||
set -eu
|
||||
set -euo pipefail
|
||||
|
||||
log() { printf '%s %s\n' "[entrypoint]" "$*" >&2; }
|
||||
|
||||
# --- Simple boolean normalization --------------------------------------------
|
||||
bool_norm () {
|
||||
v="$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]' 2>/dev/null || true)"
|
||||
v="$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')"
|
||||
case "$v" in
|
||||
1|true|yes|on) echo "true" ;;
|
||||
0|false|no|off|"") echo "false" ;;
|
||||
@@ -15,45 +13,30 @@ bool_norm () {
|
||||
esac
|
||||
}
|
||||
|
||||
# --- Environment initialization ----------------------------------------------
|
||||
# Expected ENV (from env.j2)
|
||||
MAINTENANCE="$(bool_norm "${ESPO_INIT_MAINTENANCE_MODE:-false}")"
|
||||
CRON_DISABLED="$(bool_norm "${ESPO_INIT_CRON_DISABLED:-false}")"
|
||||
USE_CACHE="$(bool_norm "${ESPO_INIT_USE_CACHE:-true}")"
|
||||
|
||||
APP_DIR="/var/www/html"
|
||||
|
||||
# Provided by env.j2 (fallback ensures robustness)
|
||||
SET_FLAGS_SCRIPT="${ESPOCRM_SET_FLAGS_SCRIPT:-/usr/local/bin/set_flags.php}"
|
||||
if [ ! -f "$SET_FLAGS_SCRIPT" ]; then
|
||||
log "WARN: SET_FLAGS_SCRIPT '$SET_FLAGS_SCRIPT' not found; falling back to /usr/local/bin/set_flags.php"
|
||||
SET_FLAGS_SCRIPT="/usr/local/bin/set_flags.php"
|
||||
fi
|
||||
SET_FLAGS_SCRIPT="${ESPOCRM_SET_FLAGS_SCRIPT}"
|
||||
|
||||
# --- Wait for bootstrap.php (max 60s, e.g. fresh volume) ----------------------
|
||||
log "Waiting for ${APP_DIR}/bootstrap.php..."
|
||||
count=0
|
||||
while [ $count -lt 60 ] && [ ! -f "${APP_DIR}/bootstrap.php" ]; do
|
||||
for i in $(seq 1 60); do
|
||||
[ -f "${APP_DIR}/bootstrap.php" ] && break
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
done
|
||||
if [ ! -f "${APP_DIR}/bootstrap.php" ]; then
|
||||
log "ERROR: bootstrap.php missing after 60s"
|
||||
exit 1
|
||||
log "ERROR: bootstrap.php missing after 60s"; exit 1
|
||||
fi
|
||||
|
||||
# --- Apply config flags via set_flags.php ------------------------------------
|
||||
log "Applying runtime flags via set_flags.php..."
|
||||
if ! php "${SET_FLAGS_SCRIPT}"; then
|
||||
log "ERROR: set_flags.php execution failed"
|
||||
exit 1
|
||||
fi
|
||||
php "${SET_FLAGS_SCRIPT}"
|
||||
|
||||
# --- Clear cache (safe) -------------------------------------------------------
|
||||
if php "${APP_DIR}/clear_cache.php" 2>/dev/null; then
|
||||
log "Cache cleared successfully."
|
||||
else
|
||||
log "WARN: Cache clearing skipped or failed (non-critical)."
|
||||
fi
|
||||
php "${APP_DIR}/clear_cache.php" || true
|
||||
|
||||
# --- Hand off to CMD ----------------------------------------------------------
|
||||
if [ "$#" -gt 0 ]; then
|
||||
@@ -73,6 +56,5 @@ for cmd in apache2-foreground httpd-foreground php-fpm php-fpm8.3 php-fpm8.2 sup
|
||||
fi
|
||||
done
|
||||
|
||||
# --- Fallback ---------------------------------------------------------------
|
||||
log "No known server command found; tailing to keep container alive."
|
||||
exec tail -f /dev/null
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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:
|
||||
import_realm: True # Import REALM
|
||||
import_realm: True # Import REALM
|
||||
create_automation_client: True
|
||||
features:
|
||||
matomo: true
|
||||
css: true
|
||||
@@ -49,10 +50,4 @@ docker:
|
||||
credentials:
|
||||
recaptcha:
|
||||
website_key: "" # Required if you enabled recaptcha:
|
||||
secret_key: "" # Required if you enabled recaptcha:
|
||||
|
||||
accounts:
|
||||
bootstrap:
|
||||
username: "administrator"
|
||||
system:
|
||||
username: "{{ SOFTWARE_NAME | replace('.', '_') | lower }}"
|
||||
secret_key: "" # Required if you enabled recaptcha:
|
||||
@@ -1,89 +0,0 @@
|
||||
- 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,3 +1,4 @@
|
||||
# --- 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 -
|
||||
@@ -15,10 +16,12 @@
|
||||
('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
|
||||
changed_when: false
|
||||
failed_when: "'HTTP 401' in (all_scopes.stderr | default(''))"
|
||||
|
||||
- name: Extract RBAC scope id
|
||||
set_fact:
|
||||
63
roles/web-app-keycloak/tasks/05a_service_account.yml
Normal file
63
roles/web-app-keycloak/tasks/05a_service_account.yml
Normal file
@@ -0,0 +1,63 @@
|
||||
# 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,21 +13,118 @@
|
||||
include_tasks: 04_dependencies.yml
|
||||
when: KEYCLOAK_LOAD_DEPENDENCIES | bool
|
||||
|
||||
- name: "Load Login routines for '{{ application_id }}'"
|
||||
include_tasks: 05_login.yml
|
||||
- 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 Client Update routines for '{{ application_id }}'"
|
||||
include_tasks: update/01_client.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 Mail Update routines for '{{ application_id }} - {{ KEYCLOAK_REALM }}'"
|
||||
include_tasks: update/02_mail_realm.yml
|
||||
- name: Verify kcadm session works (quick read)
|
||||
shell: >
|
||||
{{ 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)
|
||||
|
||||
- name: "Load Mail Update routines for '{{ application_id }} - master'"
|
||||
include_tasks: update/03_mail_master.yml
|
||||
# --- Switch session to the service account for all subsequent API work ---
|
||||
- name: kcadm login (realm) using service account
|
||||
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: "Load RBAC Update routines for '{{ application_id }}'"
|
||||
include_tasks: update/04_rbac_client_scope.yml
|
||||
- name: Verify kcadm session works (exact realm via service account)
|
||||
shell: >
|
||||
{{ 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: "Load LDAP Update routines for '{{ application_id }}'"
|
||||
include_tasks: update/05_ldap.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: "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
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
- 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
|
||||
@@ -1,10 +0,0 @@
|
||||
- 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 }}"
|
||||
@@ -1,10 +0,0 @@
|
||||
- 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 }}"
|
||||
@@ -10,21 +10,19 @@ 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 }}
|
||||
|
||||
# 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 }}"
|
||||
# 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 }}"
|
||||
|
||||
# Enable detailed logs
|
||||
{% if MODE_DEBUG | bool %}
|
||||
|
||||
3
roles/web-app-keycloak/users/main.yml
Normal file
3
roles/web-app-keycloak/users/main.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
users:
|
||||
administrator:
|
||||
username: "administrator"
|
||||
@@ -1,6 +1,6 @@
|
||||
# General
|
||||
application_id: "web-app-keycloak" # Internal Infinito.Nexus application id
|
||||
database_type: "postgres" # Database which will be used
|
||||
application_id: "web-app-keycloak" # Internal Infinito.Nexus application id
|
||||
database_type: "postgres" # Database which will be used
|
||||
|
||||
# Keycloak
|
||||
|
||||
@@ -29,22 +29,21 @@ KEYCLOAK_REALM_IMPORT_FILE_SRC: "import/realm.json.j2"
|
||||
KEYCLOAK_REALM_IMPORT_FILE_DST: "{{ [KEYCLOAK_REALM_IMPORT_DIR_HOST,'realm.json'] | path_join }}"
|
||||
|
||||
## Credentials
|
||||
|
||||
### 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') }}"
|
||||
KEYCLOAK_ADMIN: "{{ applications | get_app_conf(application_id, 'users.administrator.username') }}"
|
||||
KEYCLOAK_ADMIN_PASSWORD: "{{ applications | get_app_conf(application_id, 'credentials.administrator_password') }}"
|
||||
|
||||
## Docker
|
||||
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') }}"
|
||||
KEYCLOAK_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.name') }}" # Name of the keycloak docker container
|
||||
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_KCADM_CONFIG: "/opt/keycloak/data/kcadm.config"
|
||||
KEYCLOAK_EXEC_KCADM: "docker exec -i {{ KEYCLOAK_CONTAINER }} /opt/keycloak/bin/kcadm.sh --config {{ KEYCLOAK_KCADM_CONFIG }}"
|
||||
|
||||
## 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
|
||||
KEYCLOAK_SERVER_HOST: "127.0.0.1:{{ ports.localhost.http[application_id] }}"
|
||||
@@ -77,6 +76,11 @@ 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: >-
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
meta: flush_handlers
|
||||
|
||||
- name: "Create Mailu accounts"
|
||||
include_tasks: 02_manage_user.yml
|
||||
include_tasks: 02_create-user.yml
|
||||
vars:
|
||||
MAILU_DOCKER_DIR: "{{ docker_compose.directories.instance }}"
|
||||
mailu_api_base_url: "http://127.0.0.1:8080/api/v1"
|
||||
|
||||
@@ -25,5 +25,5 @@
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: "Create Mailu API Token for {{ mailu_user_name }}"
|
||||
include_tasks: 03a_manage_user_token.yml
|
||||
when: "'mail-bot' in item.value.roles"
|
||||
include_tasks: 03_create-token.yml
|
||||
when: "{{ 'mail-bot' in item.value.roles }}"
|
||||
@@ -1,3 +1,26 @@
|
||||
|
||||
- name: "Fetch existing API tokens via curl inside admin container"
|
||||
command: >-
|
||||
{{ docker_compose_command_exec }} -T admin \
|
||||
curl -s -X GET {{ mailu_api_base_url }}/token \
|
||||
-H "Authorization: Bearer {{ MAILU_API_TOKEN }}"
|
||||
args:
|
||||
chdir: "{{ MAILU_DOCKER_DIR }}"
|
||||
register: mailu_tokens_cli
|
||||
changed_when: false
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: "Extract existing token info for '{{ mailu_user_key }};{{ mailu_user_name }}'"
|
||||
set_fact:
|
||||
mailu_user_existing_token: >-
|
||||
{{ (
|
||||
mailu_tokens_cli.stdout
|
||||
| default('[]')
|
||||
| from_json
|
||||
| selectattr('comment','equalto', mailu_user_key ~ " - ansible.infinito")
|
||||
| list
|
||||
).0 | default(None) }}
|
||||
|
||||
- name: "Delete existing API token for '{{ mailu_user_key }};{{ mailu_user_name }}' if local token missing but remote exists"
|
||||
command: >-
|
||||
{{ docker_compose_command_exec }} -T admin \
|
||||
@@ -6,6 +29,7 @@
|
||||
args:
|
||||
chdir: "{{ MAILU_DOCKER_DIR }}"
|
||||
when:
|
||||
- users[mailu_user_key].mailu_token is not defined
|
||||
- mailu_user_existing_token is not none
|
||||
- mailu_user_existing_token.id is defined
|
||||
register: mailu_token_delete
|
||||
@@ -19,12 +43,13 @@
|
||||
-H "Authorization: Bearer {{ MAILU_API_TOKEN }}"
|
||||
-H "Content-Type: application/json"
|
||||
-d '{{ {
|
||||
"comment": SOFTWARE_NAME,
|
||||
"comment": mailu_user_key ~ " - ansible.infinito",
|
||||
"email": users[mailu_user_key].email,
|
||||
"ip": mailu_token_ip
|
||||
} | to_json }}'
|
||||
args:
|
||||
chdir: "{{ MAILU_DOCKER_DIR }}"
|
||||
when: users[mailu_user_key].mailu_token is not defined
|
||||
register: mailu_token_creation
|
||||
# If curl sees 4xx/5xx it returns non-zero due to -f → fail the task.
|
||||
failed_when:
|
||||
@@ -32,7 +57,7 @@
|
||||
# Fallback: if some gateway returns 200 but embeds an error JSON.
|
||||
- mailu_token_creation.rc == 0 and
|
||||
(mailu_token_creation.stdout is search('"code"\\s*:\\s*4\\d\\d') or
|
||||
mailu_token_creation.stdout is search('cannot be found'))
|
||||
mailu_token_creation.stdout is search('cannot be found'))
|
||||
# Only mark changed when a token is actually present in the JSON.
|
||||
changed_when: mailu_token_creation.stdout is search('"token"\\s*:')
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
@@ -41,25 +66,14 @@
|
||||
set_fact:
|
||||
users: >-
|
||||
{{ users
|
||||
| combine({
|
||||
mailu_user_key: (
|
||||
users[mailu_user_key]
|
||||
| combine({
|
||||
'mailu_token': (mailu_token_creation.stdout | from_json).token
|
||||
})
|
||||
)
|
||||
}, recursive=True)
|
||||
| combine({
|
||||
mailu_user_key: (
|
||||
users[mailu_user_key]
|
||||
| combine({
|
||||
'mailu_token': (mailu_token_creation.stdout | from_json).token
|
||||
})
|
||||
)
|
||||
}, recursive=True)
|
||||
}}
|
||||
when: users[mailu_user_key].mailu_token is not defined
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: "Reset MSMTP Configuration if No-Reply User Token changed"
|
||||
when: users['no-reply'].username == mailu_user_name
|
||||
block:
|
||||
- name: "Set MSMTP run-once fact false"
|
||||
set_fact:
|
||||
run_once_sys_svc_msmtp: false
|
||||
changed_when: false
|
||||
|
||||
- name: Reload MSMTP role
|
||||
include_role:
|
||||
name: "sys-svc-msmtp"
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
- name: "Fetch existing API tokens via curl inside admin container"
|
||||
command: >-
|
||||
{{ docker_compose_command_exec }} -T admin \
|
||||
curl -s -X GET {{ mailu_api_base_url }}/token \
|
||||
-H "Authorization: Bearer {{ MAILU_API_TOKEN }}"
|
||||
args:
|
||||
chdir: "{{ MAILU_DOCKER_DIR }}"
|
||||
register: mailu_tokens_cli
|
||||
changed_when: false
|
||||
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||
|
||||
- name: "Extract existing token info for '{{ mailu_user_key }};{{ mailu_user_name }}'"
|
||||
set_fact:
|
||||
mailu_user_existing_token: >-
|
||||
{{ (
|
||||
mailu_tokens_cli.stdout
|
||||
| default('[]')
|
||||
| from_json
|
||||
| selectattr('comment','equalto', SOFTWARE_NAME)
|
||||
| list
|
||||
).0 | default(None) }}
|
||||
|
||||
- name: "Start Mailu token procedures for undefined tokens"
|
||||
when: users[mailu_user_key].mailu_token is not defined
|
||||
include_tasks: 03b_create_user_token.yml
|
||||
@@ -1,3 +1,6 @@
|
||||
- name: "Execute migration for '{{ application_id }}'"
|
||||
command:
|
||||
cmd: "docker exec {{ MASTODON_CONTAINER }} bundle exec rails db:migrate"
|
||||
|
||||
- name: "Include administrator routines for '{{ application_id }}'"
|
||||
include_tasks: 02_administrator.yml
|
||||
@@ -1,19 +0,0 @@
|
||||
- name: Check health status of '{{ item }}' container
|
||||
shell: |
|
||||
cid=$(docker compose ps -q {{ item }})
|
||||
docker inspect \
|
||||
--format '{{ "{{.State.Health.Status}}" }}' \
|
||||
$cid
|
||||
args:
|
||||
chdir: "{{ docker_compose.directories.instance }}"
|
||||
register: healthcheck
|
||||
retries: 60
|
||||
delay: 5
|
||||
until: healthcheck.stdout == "healthy"
|
||||
loop:
|
||||
- mastodon
|
||||
- streaming
|
||||
- sidekiq
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
changed_when: false
|
||||
@@ -1,5 +1,26 @@
|
||||
# Routines to create the administrator account
|
||||
# @see https://chatgpt.com/share/67b9b12c-064c-800f-9354-8e42e6459764
|
||||
|
||||
- name: Check health status of '{{ item }}' container
|
||||
shell: |
|
||||
cid=$(docker compose ps -q {{ item }})
|
||||
docker inspect \
|
||||
--format '{{ "{{.State.Health.Status}}" }}' \
|
||||
$cid
|
||||
args:
|
||||
chdir: "{{ docker_compose.directories.instance }}"
|
||||
register: healthcheck
|
||||
retries: 60
|
||||
delay: 5
|
||||
until: healthcheck.stdout == "healthy"
|
||||
loop:
|
||||
- mastodon
|
||||
- streaming
|
||||
- sidekiq
|
||||
loop_control:
|
||||
label: "{{ item }}"
|
||||
changed_when: false
|
||||
|
||||
- name: Remove line containing "- administrator" from config/settings.yml to allow creating administrator account
|
||||
command:
|
||||
cmd: "docker exec -u root {{ MASTODON_CONTAINER }} sed -i '/- administrator/d' config/settings.yml"
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
# Cleanup routine for Mastodon
|
||||
# Removes cached remote media older than 14 days when MODE_CLEANUP is enabled.
|
||||
- name: "Cleanup Mastodon media cache older than 14 days"
|
||||
command:
|
||||
cmd: "docker exec -u root {{ MASTODON_CONTAINER }} bin/tootctl media remove --days=14"
|
||||
register: mastodon_cleanup
|
||||
changed_when: mastodon_cleanup.rc == 0
|
||||
failed_when: mastodon_cleanup.rc != 0
|
||||
@@ -18,15 +18,5 @@
|
||||
vars:
|
||||
docker_compose_flush_handlers: true
|
||||
|
||||
- name: "Wait for Mastodon"
|
||||
include_tasks: 01_wait.yml
|
||||
|
||||
- name: "Cleanup Mastodon caches when MODE_CLEANUP is true"
|
||||
include_tasks: 02_cleanup.yml
|
||||
when: MODE_CLEANUP | bool
|
||||
|
||||
- name: "start setup procedures for mastodon"
|
||||
include_tasks: 03_setup.yml
|
||||
|
||||
- name: "Include administrator routines for '{{ application_id }}'"
|
||||
include_tasks: 04_administrator.yml
|
||||
include_tasks: 01_setup.yml
|
||||
@@ -1,8 +1,8 @@
|
||||
features:
|
||||
matomo: true
|
||||
css: true
|
||||
matomo: true
|
||||
css: true
|
||||
desktop: true
|
||||
logout: false
|
||||
logout: false
|
||||
server:
|
||||
csp:
|
||||
whitelist:
|
||||
@@ -16,15 +16,14 @@ server:
|
||||
font-src:
|
||||
- https://cdnjs.cloudflare.com
|
||||
frame-src:
|
||||
# Makes sense that all of the website content is available in the navigator
|
||||
- "{{ WEB_PROTOCOL }}://*.{{ PRIMARY_DOMAIN }}"
|
||||
- "{{ WEB_PROTOCOL }}://*.{{ PRIMARY_DOMAIN }}" # Makes sense that all of the website content is available in the navigator
|
||||
flags:
|
||||
style-src:
|
||||
unsafe-inline: true
|
||||
unsafe-inline: true
|
||||
script-src:
|
||||
unsafe-eval: true
|
||||
unsafe-eval: true
|
||||
script-src-elem:
|
||||
unsafe-inline: true
|
||||
unsafe-inline: true
|
||||
domains:
|
||||
canonical:
|
||||
- "slides.{{ PRIMARY_DOMAIN }}"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
galaxy_info:
|
||||
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."
|
||||
license: "Infinito.Nexus NonCommercial License"
|
||||
license_url: "https://s.infinito.nexus/license"
|
||||
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."
|
||||
license: "Infinito.Nexus NonCommercial License"
|
||||
license_url: "https://s.infinito.nexus/license"
|
||||
company: |
|
||||
Kevin Veen-Birkenbach
|
||||
Consulting & Coaching Solutions
|
||||
|
||||
@@ -13,3 +13,4 @@
|
||||
{% include 'roles/docker-container/templates/networks.yml.j2' %}
|
||||
|
||||
{% include 'roles/docker-compose/templates/networks.yml.j2' %}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
features:
|
||||
matomo: true
|
||||
css: true
|
||||
desktop: true
|
||||
javascript: false
|
||||
logout: false
|
||||
matomo: true
|
||||
css: true
|
||||
desktop: true
|
||||
javascript: false
|
||||
logout: false
|
||||
server:
|
||||
domains:
|
||||
canonical:
|
||||
@@ -19,11 +19,10 @@ server:
|
||||
connect-src:
|
||||
- "{{ WEB_PROTOCOL }}://*.{{ PRIMARY_DOMAIN }}"
|
||||
- "{{ WEB_PROTOCOL }}://{{ PRIMARY_DOMAIN }}"
|
||||
- "https://cdn.jsdelivr.net"
|
||||
script-src-elem:
|
||||
- "https://cdn.jsdelivr.net"
|
||||
- https://cdn.jsdelivr.net
|
||||
style-src-elem:
|
||||
- "https://cdn.jsdelivr.net"
|
||||
- https://cdn.jsdelivr.net
|
||||
frame-ancestors:
|
||||
- "{{ WEB_PROTOCOL }}://<< defaults_applications[web-app-keycloak].server.domains.canonical[0] >>"
|
||||
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
- name: "load docker, proxy for '{{ application_id }}'"
|
||||
include_role:
|
||||
name: sys-stk-full-stateless
|
||||
vars:
|
||||
aca_origin: "'{{ domains | get_url('web-svc-logout', WEB_PROTOCOL) }}' always"
|
||||
aca_credentials: "'true' always"
|
||||
aca_methods: "'GET, OPTIONS' always"
|
||||
aca_headers: "'Accept, Authorization' always"
|
||||
|
||||
- name: Create symbolic link from .env file to repository
|
||||
file:
|
||||
|
||||
@@ -8,11 +8,7 @@ location = /logout {
|
||||
proxy_http_version 1.1;
|
||||
|
||||
{# CORS headers – allow your central page to call this #}
|
||||
{%- set aca_origin = "'{{ domains | get_url('web-svc-logout', WEB_PROTOCOL) }}' always" -%}
|
||||
{%- set aca_credentials = "'true' always" -%}
|
||||
{%- set aca_methods = "'GET, OPTIONS' always" -%}
|
||||
{%- set aca_headers = "'Accept, Authorization' always" -%}
|
||||
{%- include 'roles/sys-svc-proxy/templates/headers/access_control_allow.conf.j2' -%}
|
||||
{% include 'roles/sys-svc-proxy/templates/headers/access_control_allow.conf.j2' %}
|
||||
|
||||
{# Disable caching absolutely #}
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0" always;
|
||||
|
||||
@@ -28,17 +28,14 @@ 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","contains",
|
||||
"truncate", "unique", "upper", "urlencode", "urlize", "wordcount", "xmlattr",
|
||||
|
||||
# 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", "to_nice_json",
|
||||
|
||||
"lower", "upper", "capitalize", "unique", "dict2items", "items2dict", "password_hash", "path_join", "product", "quote", "split", "ternary", "to_nice_yaml", "tojson",
|
||||
|
||||
# Date/time-ish
|
||||
"strftime",
|
||||
|
||||
Reference in New Issue
Block a user