From 0de26fa6c79bce04816778928ab658aa23d4ff26 Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Sat, 16 Aug 2025 14:29:07 +0200 Subject: [PATCH] Solved bug existed due to difference between mailu domain and hostname difference. also refactored during this to find the bug --- filter_plugins/domain_tools.py | 19 ++++ group_vars/all/10_networks.yml | 4 +- group_vars/all/12_oidc.yml | 50 ++++----- group_vars/all/15_about.yml | 2 +- .../templates/keyboard-color.service.j2 | 2 +- roles/srv-proxy-6-6-tls-deploy/README.md | 67 ------------ .../handlers/main.yml | 7 -- .../tasks/01_core.yml | 10 -- roles/srv-proxy-6-6-tls-deploy/tasks/main.yml | 27 ----- .../srv-proxy-6-6-tls-deploy.service.j2 | 7 -- roles/srv-proxy-6-6-tls-deploy/vars/main.yml | 1 - .../srv-web-6-6-tls-renew.service.j2 | 2 +- .../templates/svc-bkp-loc-2-usb.service.j2 | 2 +- .../templates/sys-bkp-rmt-2-loc.service.j2 | 2 +- .../templates/svc-opt-ssd-hdd.service.j2 | 2 +- ...sys-bkp-docker-2-loc-everything.service.j2 | 2 +- .../templates/sys-bkp-docker-2-loc.service.j2 | 2 +- .../templates/sys-cln-backups.service.j2 | 2 +- .../templates/sys-cln-certs.service.j2 | 2 +- .../templates/sys-cln-disc-space.service.j2 | 2 +- .../templates/sys-cln-faild-bkps.service.j2 | 2 +- .../templates/sys-hlth-btrfs.service.j2 | 2 +- .../templates/sys-hlth-csp.service.j2 | 2 +- .../templates/sys-hlth-disc-space.service.j2 | 2 +- .../sys-hlth-docker-container.service.j2 | 2 +- .../sys-hlth-docker-volumes.service.j2 | 2 +- .../templates/sys-hlth-journalctl.service.j2 | 2 +- .../templates/sys-hlth-msmtp.service.j2 | 2 +- .../templates/sys-hlth-webserver.service.j2 | 2 +- .../templates/sys-rpr-btrfs-blnc.service.j2 | 2 +- .../templates/sys-rpr-docker-hard.service.j2 | 2 +- .../templates/sys-rpr-docker-soft.service.j2 | 2 +- .../templates/logout_one_liner.js.j2 | 2 +- roles/sys-svc-cert-sync-docker/README.md | 18 ++++ .../SETUP.md | 0 .../files/sys-svc-cert-sync-docker.sh} | 9 +- .../handlers/main.yml | 7 ++ .../meta/main.yml | 2 +- .../tasks/01_core.yml | 13 +++ roles/sys-svc-cert-sync-docker/tasks/main.yml | 27 +++++ .../sys-svc-cert-sync-docker.service.j2 | 7 ++ roles/sys-svc-cert-sync-docker/vars/main.yml | 3 + .../templates/update-docker.service.j2 | 2 +- roles/web-app-bigbluebutton/templates/env.j2 | 6 +- .../web-app-discourse/templates/config.yml.j2 | 6 +- roles/web-app-espocrm/templates/env.j2 | 14 +-- roles/web-app-gitea/tasks/cleanup/oidc.yml | 2 +- roles/web-app-gitea/tasks/setup/oidc.yml | 18 ++-- .../templates/import/realm.json.j2 | 6 +- roles/web-app-keycloak/vars/main.yml | 4 +- roles/web-app-listmonk/tasks/main.yml | 6 +- roles/web-app-listmonk/vars/main.yml | 6 +- roles/web-app-mailu/tasks/01_core.yml | 29 +++-- .../tasks/02_create-mailu-user.yml | 12 +-- .../tasks/03_create-mailu-token.yml | 12 +-- .../tasks/04_set-mailu-dns-records.yml | 101 ++++++++++-------- .../tasks/05_generate-and-read-dkim.yml | 6 +- .../templates/docker-compose.yml.j2 | 96 ++++++++--------- roles/web-app-mailu/templates/env.j2 | 34 +++--- roles/web-app-mailu/vars/mailu-dns.yml | 41 ------- roles/web-app-mailu/vars/main.yml | 80 ++++++++++---- roles/web-app-mastodon/templates/env.j2 | 10 +- .../templates/synapse/homeserver.yaml.j2 | 10 +- .../web-app-mobilizon/templates/config.exs.j2 | 14 +-- roles/web-app-moodle/tasks/03_oidc.yml | 18 ++-- .../templates/config/oidc.config.php.j2 | 10 +- .../vars/plugins/sociallogin.yml | 12 +-- .../templates/oauth2-proxy-keycloak.cfg.j2 | 12 +-- roles/web-app-peertube/vars/oidc-settings.yml | 12 +-- roles/web-app-pixelfed/templates/env.j2 | 16 +-- .../templates/menu/applications.yml.j2 | 4 +- roles/web-app-snipe-it/tasks/ldap.yml | 2 +- roles/web-app-taiga/templates/env.j2 | 26 ++--- roles/web-app-wordpress/vars/oidc.yml | 24 ++--- tasks/stages/01_constructor.yml | 4 +- .../unit/filter_plugins/test_domain_tools.py | 49 +++++++++ 76 files changed, 543 insertions(+), 487 deletions(-) create mode 100644 filter_plugins/domain_tools.py delete mode 100644 roles/srv-proxy-6-6-tls-deploy/README.md delete mode 100644 roles/srv-proxy-6-6-tls-deploy/handlers/main.yml delete mode 100644 roles/srv-proxy-6-6-tls-deploy/tasks/01_core.yml delete mode 100644 roles/srv-proxy-6-6-tls-deploy/tasks/main.yml delete mode 100644 roles/srv-proxy-6-6-tls-deploy/templates/srv-proxy-6-6-tls-deploy.service.j2 delete mode 100644 roles/srv-proxy-6-6-tls-deploy/vars/main.yml create mode 100644 roles/sys-svc-cert-sync-docker/README.md rename roles/{srv-proxy-6-6-tls-deploy => sys-svc-cert-sync-docker}/SETUP.md (100%) rename roles/{srv-proxy-6-6-tls-deploy/templates/srv-proxy-6-6-tls-deploy.sh.j2 => sys-svc-cert-sync-docker/files/sys-svc-cert-sync-docker.sh} (81%) create mode 100644 roles/sys-svc-cert-sync-docker/handlers/main.yml rename roles/{srv-proxy-6-6-tls-deploy => sys-svc-cert-sync-docker}/meta/main.yml (96%) create mode 100644 roles/sys-svc-cert-sync-docker/tasks/01_core.yml create mode 100644 roles/sys-svc-cert-sync-docker/tasks/main.yml create mode 100644 roles/sys-svc-cert-sync-docker/templates/sys-svc-cert-sync-docker.service.j2 create mode 100644 roles/sys-svc-cert-sync-docker/vars/main.yml delete mode 100644 roles/web-app-mailu/vars/mailu-dns.yml create mode 100644 tests/unit/filter_plugins/test_domain_tools.py diff --git a/filter_plugins/domain_tools.py b/filter_plugins/domain_tools.py new file mode 100644 index 00000000..ec55f814 --- /dev/null +++ b/filter_plugins/domain_tools.py @@ -0,0 +1,19 @@ +# filter_plugins/domain_tools.py +# Returns the DNS zone (SLD.TLD) from a hostname. +# Pure-Python, no external deps; handles simple cases. For exotic TLDs use tldextract (see note). +from ansible.errors import AnsibleFilterError + +def to_zone(hostname: str) -> str: + if not isinstance(hostname, str) or not hostname.strip(): + raise AnsibleFilterError("to_zone: hostname must be a non-empty string") + parts = hostname.strip(".").split(".") + if len(parts) < 2: + raise AnsibleFilterError(f"to_zone: '{hostname}' has no TLD part") + # naive default: last two labels -> SLD.TLD + return ".".join(parts[-2:]) + +class FilterModule(object): + def filters(self): + return { + "to_zone": to_zone, + } diff --git a/group_vars/all/10_networks.yml b/group_vars/all/10_networks.yml index 39930f81..381c84a6 100644 --- a/group_vars/all/10_networks.yml +++ b/group_vars/all/10_networks.yml @@ -44,8 +44,8 @@ defaults_networks: subnet: 192.168.102.0/28 web-app-mailu: # Use one of the last container ips for dns resolving so that it isn't used - dns: 192.168.102.29 - subnet: 192.168.102.16/28 + dns_resolver: 192.168.102.29 + subnet: 192.168.102.16/28 web-app-moodle: subnet: 192.168.102.32/28 web-app-mybb: diff --git a/group_vars/all/12_oidc.yml b/group_vars/all/12_oidc.yml index be43a63a..007d0c94 100644 --- a/group_vars/all/12_oidc.yml +++ b/group_vars/all/12_oidc.yml @@ -8,37 +8,37 @@ # @see https://en.wikipedia.org/wiki/OpenID_Connect ## Helper Variables: -_oidc_client_realm: "{{ oidc.client.realm if oidc.client is defined and oidc.client.realm is defined else SOFTWARE_NAME | lower }}" +_oidc_client_realm: "{{ OIDC.CLIENT.ISSUER_URL if OIDC.CLIENT is defined and OIDC.CLIENT.ISSUER_URL is defined else SOFTWARE_NAME | lower }}" _oidc_url: "{{ - (oidc.url - if (oidc is defined and oidc.url is defined) + (OIDC.URL + if (oidc is defined and OIDC.URL is defined) else WEB_PROTOCOL ~ '://' ~ (domains | get_domain('web-app-keycloak')) ) }}" _oidc_client_issuer_url: "{{ _oidc_url }}/realms/{{_oidc_client_realm}}" -_oidc_client_id: "{{ oidc.client.id if oidc.client is defined and oidc.client.id is defined else SOFTWARE_NAME | lower }}" +_oidc_client_id: "{{ OIDC.CLIENT.ID if OIDC.CLIENT is defined and OIDC.CLIENT.ID is defined else SOFTWARE_NAME | lower }}" defaults_oidc: - url: "{{ _oidc_url }}" - client: - id: "{{ _oidc_client_id }}" # Client identifier, typically matching your primary domain + URL: "{{ _oidc_url }}" + CLIENT: + ID: "{{ _oidc_client_id }}" # Client identifier, typically matching your primary domain # secret: # Client secret for authenticating with the OIDC provider (set in the inventory file). Recommend greater then 32 characters - realm: "{{_oidc_client_realm}}" # The realm to which the client belongs in the OIDC provider - issuer_url: "{{_oidc_client_issuer_url}}" # Base URL of the OIDC provider (issuer) - discovery_document: "{{_oidc_client_issuer_url}}/.well-known/openid-configuration" # URL for fetching the provider's configuration details - authorize_url: "{{_oidc_client_issuer_url}}/protocol/openid-connect/auth" # Endpoint to start the authorization process - token_url: "{{_oidc_client_issuer_url}}/protocol/openid-connect/token" # Endpoint to exchange authorization codes for tokens (note: 'token_url' may be a typo for 'token_url') - user_info_url: "{{_oidc_client_issuer_url}}/protocol/openid-connect/userinfo" # Endpoint to retrieve user information - logout_url: "{{_oidc_client_issuer_url}}/protocol/openid-connect/logout" # Endpoint to log out the user - change_credentials: "{{_oidc_client_issuer_url}}account/account-security/signing-in" # URL for managing or changing user credentials - certs: "{{_oidc_client_issuer_url}}/protocol/openid-connect/certs" # JSON Web Key Set (JWKS) - reset_credentials: "{{_oidc_client_issuer_url}}/login-actions/reset-credentials?client_id={{ _oidc_client_id }}" # Password reset url - button_text: "SSO Login ({{ PRIMARY_DOMAIN | upper }})" # Default button text - attributes: + REALM: "{{_oidc_client_realm}}" # The realm to which the client belongs in the OIDC provider + ISSUER_URL: "{{_oidc_client_issuer_url}}" # Base URL of the OIDC provider (issuer) + DISCOVERY_DOCUMENT: "{{_oidc_client_issuer_url}}/.well-known/openid-configuration" # URL for fetching the provider's configuration details + AUTHORIZE_URL: "{{_oidc_client_issuer_url}}/protocol/openid-connect/auth" # Endpoint to start the authorization process + TOKEN_URL: "{{_oidc_client_issuer_url}}/protocol/openid-connect/token" # Endpoint to exchange authorization codes for tokens (note: 'token_url' may be a typo for 'token_url') + USER_INFO_URL: "{{_oidc_client_issuer_url}}/protocol/openid-connect/userinfo" # Endpoint to retrieve user information + LOGOUT_URL: "{{_oidc_client_issuer_url}}/protocol/openid-connect/logout" # Endpoint to log out the user + CHANGE_CREDENTIALS: "{{_oidc_client_issuer_url}}account/account-security/signing-in" # URL for managing or changing user credentials + CERTS: "{{_oidc_client_issuer_url}}/protocol/openid-connect/certs" # JSON Web Key Set (JWKS) + RESET_CREDENTIALS: "{{_oidc_client_issuer_url}}/login-actions/reset-credentials?client_id={{ _oidc_client_id }}" # Password reset url + BUTTON_TEXT: "SSO Login ({{ PRIMARY_DOMAIN | upper }})" # Default button text + ATTRIBUTES: # Attribut to identify the user - username: "preferred_username" - given_name: "givenName" - family_name: "surname" - email: "email" - claims: - groups: "groups" + USERNAME: "preferred_username" + GIVEN_NAME: "givenName" + FAMILY_NAME: "surname" + EMAIL: "email" + CLAIMS: + GROUPS: "groups" diff --git a/group_vars/all/15_about.yml b/group_vars/all/15_about.yml index 0bf5a226..b61b6f8e 100644 --- a/group_vars/all/15_about.yml +++ b/group_vars/all/15_about.yml @@ -30,4 +30,4 @@ defaults_service_provider: legal: editorial_responsible: "Johannes Gutenberg" source_code: "https://s.{{ SOFTWARE_NAME | lower }}/code" - imprint: "{{WEB_PROTOCOL}}://{{ domains | get_domain('web-svc-html') }}/imprint.html" \ No newline at end of file + imprint: "{{ domains | get_url('web-svc-html', WEB_PROTOCOL) }}/imprint.html" \ No newline at end of file diff --git a/roles/drv-msi-keyboard-color/templates/keyboard-color.service.j2 b/roles/drv-msi-keyboard-color/templates/keyboard-color.service.j2 index bbaedeb6..4b06027e 100644 --- a/roles/drv-msi-keyboard-color/templates/keyboard-color.service.j2 +++ b/roles/drv-msi-keyboard-color/templates/keyboard-color.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=Keyboard Color Service -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/srv-proxy-6-6-tls-deploy/README.md b/roles/srv-proxy-6-6-tls-deploy/README.md deleted file mode 100644 index 6eb55439..00000000 --- a/roles/srv-proxy-6-6-tls-deploy/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# Nginx Docker Cert Deploy Role - -๐ŸŽ‰ **Author**: [Kevin Veen-Birkenbach](https://www.veen.world) - -This Ansible role simplifies the deployment of **Let's Encrypt certificates** into **Docker Compose** setups with Nginx. It supports both **individual certificates per subdomain** and a **single wildcard certificate** for all subdomains. - ---- - -## ๐Ÿš€ **Features** -- Automatically deploys **Let's Encrypt certificates** to Docker Compose setups. -- Supports both **single-domain certificates** and **one wildcard certificate** for all subdomains. -- **Copies certificates** to the target directory inside the container. -- Automatically **reloads or restarts Nginx services** when certificates are updated. -- **Configures and manages a `systemd` service** for automated certificate deployment. -- **Includes a `systemd` timer** for scheduled renewals. -- **Handles dependent services** like `sys-alm-compose`. - ---- - -## ๐Ÿ”ง **Tasks Overview** - -### **1๏ธโƒฃ Main Tasks** -1. **Add Deployment Script** - - Copies `srv-proxy-6-6-tls-deploy.sh` to the administrator scripts directory. - -2. **Create Certificate Directory** - - Ensures `cert_mount_directory` exists with proper permissions. - -3. **Configure `systemd` Service** - - Deploys a `systemd` service file for the deployment process. - -4. **Include `sys-timer` Role** - - Schedules automatic certificate deployment using a `systemd` timer. - -### **2๏ธโƒฃ Handlers** -- **Restart Nginx Service** - - Restarts `srv-proxy-6-6-tls-deploy` whenever a certificate update occurs. - ---- - -## **๐Ÿ”ง Deploying Certificates into Docker Containers** -The role **automates copying certificates** into Docker Compose setups. - -### **1๏ธโƒฃ Deployment Script (`srv-proxy-6-6-tls-deploy.sh`)** -This script: -- **Copies certificates** to the correct container directory. -- **Reloads Nginx** inside all running containers. -- **Restarts containers if needed**. - -**Usage:** -```sh -sh srv-proxy-6-6-tls-deploy.sh PRIMARY_DOMAIN /path/to/docker/compose -``` - ---- - -## ๐ŸŽฏ **Summary** -| Feature | Description | -|---------|------------| -| **Single-domain & wildcard support** | Use individual certs or a wildcard certificate | -| **Automated renewal** | Cronjob or systemd timer ensures auto-renewals | -| **Docker-ready** | Deploys certificates directly into Docker containers | -| **Supports Nginx & Mailu** | Compatible with multiple services | -| **Systemd integration** | Automates deployment via `systemd` | - -๐Ÿš€ **Now your Nginx setup is fully automated and secured with Let's Encrypt!** ๐ŸŽ‰ -``` \ No newline at end of file diff --git a/roles/srv-proxy-6-6-tls-deploy/handlers/main.yml b/roles/srv-proxy-6-6-tls-deploy/handlers/main.yml deleted file mode 100644 index 2403b797..00000000 --- a/roles/srv-proxy-6-6-tls-deploy/handlers/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -- name: "restart srv-proxy-6-6-tls-deploy service" - systemd: - name: srv-proxy-6-6-tls-deploy.{{ application_id }}{{ SYS_SERVICE_SUFFIX }} - state: restarted - enabled: yes - daemon_reload: yes \ No newline at end of file diff --git a/roles/srv-proxy-6-6-tls-deploy/tasks/01_core.yml b/roles/srv-proxy-6-6-tls-deploy/tasks/01_core.yml deleted file mode 100644 index b4ed8c03..00000000 --- a/roles/srv-proxy-6-6-tls-deploy/tasks/01_core.yml +++ /dev/null @@ -1,10 +0,0 @@ -- name: Include dependency 'sys-alm-compose' - include_role: - name: sys-alm-compose - when: run_once_sys_alm_compose is not defined - -- name: add srv-proxy-6-6-tls-deploy.sh - template: - src: "srv-proxy-6-6-tls-deploy.sh.j2" - dest: "{{nginx_docker_cert_deploy_script}}" - notify: restart srv-proxy-6-6-tls-deploy service \ No newline at end of file diff --git a/roles/srv-proxy-6-6-tls-deploy/tasks/main.yml b/roles/srv-proxy-6-6-tls-deploy/tasks/main.yml deleted file mode 100644 index 8ce2cd69..00000000 --- a/roles/srv-proxy-6-6-tls-deploy/tasks/main.yml +++ /dev/null @@ -1,27 +0,0 @@ -- block: - - include_tasks: 01_core.yml - - set_fact: - run_once_srv_proxy_6_6_tls_deploy: true - when: run_once_srv_proxy_6_6_tls_deploy is not defined - -- name: "create {{cert_mount_directory}}" - file: - path: "{{cert_mount_directory}}" - state: directory - mode: "0755" - notify: restart srv-proxy-6-6-tls-deploy service - -- name: configure srv-proxy-6-6-tls-deploy service - template: - src: "srv-proxy-6-6-tls-deploy.service.j2" - dest: "/etc/systemd/system/srv-proxy-6-6-tls-deploy.{{ application_id }}{{ SYS_SERVICE_SUFFIX }}" - notify: restart srv-proxy-6-6-tls-deploy service - -- name: "include role for sys-timer for {{ service_name }}" - include_role: - name: sys-timer - vars: - on_calendar: "{{on_calendar_deploy_certificates}}" - service_name: "srv-proxy-6-6-tls-deploy.{{ application_id }}" - persistent: "true" - diff --git a/roles/srv-proxy-6-6-tls-deploy/templates/srv-proxy-6-6-tls-deploy.service.j2 b/roles/srv-proxy-6-6-tls-deploy/templates/srv-proxy-6-6-tls-deploy.service.j2 deleted file mode 100644 index 3d9da477..00000000 --- a/roles/srv-proxy-6-6-tls-deploy/templates/srv-proxy-6-6-tls-deploy.service.j2 +++ /dev/null @@ -1,7 +0,0 @@ -[Unit] -Description=Let's Encrypt deploy to {{ docker_compose.directories.instance }} -OnFailure=sys-alm-compose.infinito@%n.service - -[Service] -Type=oneshot -ExecStart=/usr/bin/bash {{ PATH_ADMINISTRATOR_SCRIPTS }}/srv-proxy-6-6-tls-deploy.sh {{ssl_cert_folder}} {{ docker_compose.directories.instance }} diff --git a/roles/srv-proxy-6-6-tls-deploy/vars/main.yml b/roles/srv-proxy-6-6-tls-deploy/vars/main.yml deleted file mode 100644 index f67072c1..00000000 --- a/roles/srv-proxy-6-6-tls-deploy/vars/main.yml +++ /dev/null @@ -1 +0,0 @@ -nginx_docker_cert_deploy_script: "{{ PATH_ADMINISTRATOR_SCRIPTS }}srv-proxy-6-6-tls-deploy.sh" \ No newline at end of file diff --git a/roles/srv-web-6-6-tls-renew/templates/srv-web-6-6-tls-renew.service.j2 b/roles/srv-web-6-6-tls-renew/templates/srv-web-6-6-tls-renew.service.j2 index 3d84999f..e51f8708 100644 --- a/roles/srv-web-6-6-tls-renew/templates/srv-web-6-6-tls-renew.service.j2 +++ b/roles/srv-web-6-6-tls-renew/templates/srv-web-6-6-tls-renew.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=Let's Encrypt renewal -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/svc-bkp-loc-2-usb/templates/svc-bkp-loc-2-usb.service.j2 b/roles/svc-bkp-loc-2-usb/templates/svc-bkp-loc-2-usb.service.j2 index 3473078d..f751dce2 100644 --- a/roles/svc-bkp-loc-2-usb/templates/svc-bkp-loc-2-usb.service.j2 +++ b/roles/svc-bkp-loc-2-usb/templates/svc-bkp-loc-2-usb.service.j2 @@ -1,7 +1,7 @@ [Unit] Description=Backup to USB when mounted to {{ backup_to_usb_mount }} Wants={{systemctl_mount_service_name}} -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/svc-bkp-rmt-2-loc/templates/sys-bkp-rmt-2-loc.service.j2 b/roles/svc-bkp-rmt-2-loc/templates/sys-bkp-rmt-2-loc.service.j2 index 919ac087..ad118810 100644 --- a/roles/svc-bkp-rmt-2-loc/templates/sys-bkp-rmt-2-loc.service.j2 +++ b/roles/svc-bkp-rmt-2-loc/templates/sys-bkp-rmt-2-loc.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=pull remote backups -OnFailure=sys-alm-compose.infinito@%n.service sys-cln-faild-bkps{{ SYS_SERVICE_SUFFIX }} +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service sys-cln-faild-bkps{{ SYS_SERVICE_SUFFIX }} [Service] Type=oneshot diff --git a/roles/svc-opt-ssd-hdd/templates/svc-opt-ssd-hdd.service.j2 b/roles/svc-opt-ssd-hdd/templates/svc-opt-ssd-hdd.service.j2 index 5c632011..80817fb0 100644 --- a/roles/svc-opt-ssd-hdd/templates/svc-opt-ssd-hdd.service.j2 +++ b/roles/svc-opt-ssd-hdd/templates/svc-opt-ssd-hdd.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=Optimize storage paths -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-bkp-docker-2-loc/templates/sys-bkp-docker-2-loc-everything.service.j2 b/roles/sys-bkp-docker-2-loc/templates/sys-bkp-docker-2-loc-everything.service.j2 index cd9f1dd3..a958b204 100644 --- a/roles/sys-bkp-docker-2-loc/templates/sys-bkp-docker-2-loc-everything.service.j2 +++ b/roles/sys-bkp-docker-2-loc/templates/sys-bkp-docker-2-loc-everything.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=backup all docker volumes to local folder -OnFailure=sys-alm-compose.infinito@%n.service sys-cln-faild-bkps{{ SYS_SERVICE_SUFFIX }} +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service sys-cln-faild-bkps{{ SYS_SERVICE_SUFFIX }} [Service] Type=oneshot diff --git a/roles/sys-bkp-docker-2-loc/templates/sys-bkp-docker-2-loc.service.j2 b/roles/sys-bkp-docker-2-loc/templates/sys-bkp-docker-2-loc.service.j2 index 1dcfbde7..0cb2942c 100644 --- a/roles/sys-bkp-docker-2-loc/templates/sys-bkp-docker-2-loc.service.j2 +++ b/roles/sys-bkp-docker-2-loc/templates/sys-bkp-docker-2-loc.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=backup docker volumes to local folder -OnFailure=sys-alm-compose.infinito@%n.service sys-cln-faild-bkps{{ SYS_SERVICE_SUFFIX }} +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service sys-cln-faild-bkps{{ SYS_SERVICE_SUFFIX }} [Service] Type=oneshot diff --git a/roles/sys-cln-bkps-service/templates/sys-cln-backups.service.j2 b/roles/sys-cln-bkps-service/templates/sys-cln-backups.service.j2 index c1a6b2e9..60b31d63 100644 --- a/roles/sys-cln-bkps-service/templates/sys-cln-backups.service.j2 +++ b/roles/sys-cln-bkps-service/templates/sys-cln-backups.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=delete old backups -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-cln-certs/templates/sys-cln-certs.service.j2 b/roles/sys-cln-certs/templates/sys-cln-certs.service.j2 index e882a5fd..34629a8c 100644 --- a/roles/sys-cln-certs/templates/sys-cln-certs.service.j2 +++ b/roles/sys-cln-certs/templates/sys-cln-certs.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=Detect, revoke, and delete unused Let's Encrypt certificates based on active NGINX configuration files. -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-cln-disc-space/templates/sys-cln-disc-space.service.j2 b/roles/sys-cln-disc-space/templates/sys-cln-disc-space.service.j2 index 7a00f0fd..90a0047f 100644 --- a/roles/sys-cln-disc-space/templates/sys-cln-disc-space.service.j2 +++ b/roles/sys-cln-disc-space/templates/sys-cln-disc-space.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=freeing disc space -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-cln-faild-bkps/templates/sys-cln-faild-bkps.service.j2 b/roles/sys-cln-faild-bkps/templates/sys-cln-faild-bkps.service.j2 index 021bf34e..7d8a165b 100644 --- a/roles/sys-cln-faild-bkps/templates/sys-cln-faild-bkps.service.j2 +++ b/roles/sys-cln-faild-bkps/templates/sys-cln-faild-bkps.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=Cleaning up failed docker volume backups -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-hlth-btrfs/templates/sys-hlth-btrfs.service.j2 b/roles/sys-hlth-btrfs/templates/sys-hlth-btrfs.service.j2 index d1b593cd..8027fed0 100644 --- a/roles/sys-hlth-btrfs/templates/sys-hlth-btrfs.service.j2 +++ b/roles/sys-hlth-btrfs/templates/sys-hlth-btrfs.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=Check btrfs status -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-hlth-csp/templates/sys-hlth-csp.service.j2 b/roles/sys-hlth-csp/templates/sys-hlth-csp.service.j2 index 88b1a20c..24ec51ab 100644 --- a/roles/sys-hlth-csp/templates/sys-hlth-csp.service.j2 +++ b/roles/sys-hlth-csp/templates/sys-hlth-csp.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=Check for CSP-blocked resources via Puppeteer -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-hlth-disc-space/templates/sys-hlth-disc-space.service.j2 b/roles/sys-hlth-disc-space/templates/sys-hlth-disc-space.service.j2 index 6cf34b84..5b463b06 100644 --- a/roles/sys-hlth-disc-space/templates/sys-hlth-disc-space.service.j2 +++ b/roles/sys-hlth-disc-space/templates/sys-hlth-disc-space.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=checking disc space -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-hlth-docker-container/templates/sys-hlth-docker-container.service.j2 b/roles/sys-hlth-docker-container/templates/sys-hlth-docker-container.service.j2 index fd94cb6e..06a946e2 100644 --- a/roles/sys-hlth-docker-container/templates/sys-hlth-docker-container.service.j2 +++ b/roles/sys-hlth-docker-container/templates/sys-hlth-docker-container.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=Checking docker health -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-hlth-docker-volumes/templates/sys-hlth-docker-volumes.service.j2 b/roles/sys-hlth-docker-volumes/templates/sys-hlth-docker-volumes.service.j2 index 2e74c5b1..adb161ca 100644 --- a/roles/sys-hlth-docker-volumes/templates/sys-hlth-docker-volumes.service.j2 +++ b/roles/sys-hlth-docker-volumes/templates/sys-hlth-docker-volumes.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=Checking docker health -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-hlth-journalctl/templates/sys-hlth-journalctl.service.j2 b/roles/sys-hlth-journalctl/templates/sys-hlth-journalctl.service.j2 index f2cd2907..dd4dd602 100644 --- a/roles/sys-hlth-journalctl/templates/sys-hlth-journalctl.service.j2 +++ b/roles/sys-hlth-journalctl/templates/sys-hlth-journalctl.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=checking journalctl health -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-hlth-msmtp/templates/sys-hlth-msmtp.service.j2 b/roles/sys-hlth-msmtp/templates/sys-hlth-msmtp.service.j2 index b7e3abfc..6b2d0253 100644 --- a/roles/sys-hlth-msmtp/templates/sys-hlth-msmtp.service.j2 +++ b/roles/sys-hlth-msmtp/templates/sys-hlth-msmtp.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=Check msmtp liveliness -OnFailure=sys-alm-telegram.infinito@%n.service +OnFailure=sys-alm-telegram.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-hlth-webserver/templates/sys-hlth-webserver.service.j2 b/roles/sys-hlth-webserver/templates/sys-hlth-webserver.service.j2 index fba3d6b1..35f40b50 100644 --- a/roles/sys-hlth-webserver/templates/sys-hlth-webserver.service.j2 +++ b/roles/sys-hlth-webserver/templates/sys-hlth-webserver.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=Check nginx configuration status -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-rpr-btrfs-blnc/templates/sys-rpr-btrfs-blnc.service.j2 b/roles/sys-rpr-btrfs-blnc/templates/sys-rpr-btrfs-blnc.service.j2 index 29e7d3ba..9b54c842 100644 --- a/roles/sys-rpr-btrfs-blnc/templates/sys-rpr-btrfs-blnc.service.j2 +++ b/roles/sys-rpr-btrfs-blnc/templates/sys-rpr-btrfs-blnc.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=auto balance btrfs -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-rpr-docker-hard/templates/sys-rpr-docker-hard.service.j2 b/roles/sys-rpr-docker-hard/templates/sys-rpr-docker-hard.service.j2 index 143d7cc5..e094a657 100644 --- a/roles/sys-rpr-docker-hard/templates/sys-rpr-docker-hard.service.j2 +++ b/roles/sys-rpr-docker-hard/templates/sys-rpr-docker-hard.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=Restart Docker Instances -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-rpr-docker-soft/templates/sys-rpr-docker-soft.service.j2 b/roles/sys-rpr-docker-soft/templates/sys-rpr-docker-soft.service.j2 index f140901d..c7125165 100644 --- a/roles/sys-rpr-docker-soft/templates/sys-rpr-docker-soft.service.j2 +++ b/roles/sys-rpr-docker-soft/templates/sys-rpr-docker-soft.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=restart unhealthy docker containers -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/sys-srv-web-inj-logout/templates/logout_one_liner.js.j2 b/roles/sys-srv-web-inj-logout/templates/logout_one_liner.js.j2 index c9146729..58db21d6 100644 --- a/roles/sys-srv-web-inj-logout/templates/logout_one_liner.js.j2 +++ b/roles/sys-srv-web-inj-logout/templates/logout_one_liner.js.j2 @@ -1,6 +1,6 @@ document.addEventListener('DOMContentLoaded', function() { initLogoutPatch( - '{{ oidc.client.logout_url }}', + '{{ OIDC.CLIENT.LOGOUT_URL }}', '{{ WEB_PROTOCOL }}', '{{ PRIMARY_DOMAIN }}' ); diff --git a/roles/sys-svc-cert-sync-docker/README.md b/roles/sys-svc-cert-sync-docker/README.md new file mode 100644 index 00000000..9b46d76f --- /dev/null +++ b/roles/sys-svc-cert-sync-docker/README.md @@ -0,0 +1,18 @@ +# Docker Compose Certificate Sync Service + +## Description +Keeps Docker Compose services updated with fresh Letโ€™s Encrypt certificates via a systemd oneshot service and timer. + +## Overview +Installs a small script and a systemd unit that copy certificates into your Compose project and trigger an Nginx hot-reload (fallback: restart) to minimize downtime. + +## Features +- Automatic certificate sync into the Compose project +- Mailu-friendly filenames (`key.pem`, `cert.pem`) +- Nginx hot-reload if available, otherwise restart +- Runs on a schedule you define + +## Further Resources +- [Wildcard Certificate Setup (SETUP.md)](./SETUP.md) +- [Role Documentation](https://s.infinito.nexus/code/tree/main/roles/sys-svc-cert-sync-docker) +- [Issue Tracker](https://s.infinito.nexus/issues) diff --git a/roles/srv-proxy-6-6-tls-deploy/SETUP.md b/roles/sys-svc-cert-sync-docker/SETUP.md similarity index 100% rename from roles/srv-proxy-6-6-tls-deploy/SETUP.md rename to roles/sys-svc-cert-sync-docker/SETUP.md diff --git a/roles/srv-proxy-6-6-tls-deploy/templates/srv-proxy-6-6-tls-deploy.sh.j2 b/roles/sys-svc-cert-sync-docker/files/sys-svc-cert-sync-docker.sh similarity index 81% rename from roles/srv-proxy-6-6-tls-deploy/templates/srv-proxy-6-6-tls-deploy.sh.j2 rename to roles/sys-svc-cert-sync-docker/files/sys-svc-cert-sync-docker.sh index a353604f..09e749c4 100644 --- a/roles/srv-proxy-6-6-tls-deploy/templates/srv-proxy-6-6-tls-deploy.sh.j2 +++ b/roles/sys-svc-cert-sync-docker/files/sys-svc-cert-sync-docker.sh @@ -1,7 +1,7 @@ #!/bin/sh # Check if the necessary parameters are provided -if [ "$#" -ne 2 ]; then +if [ "$#" -ne 3 ]; then echo "Usage: $0 " exit 1 fi @@ -9,14 +9,15 @@ fi # Assign parameters ssl_cert_folder="$1" docker_compose_instance_directory="$2" +letsencrypt_live_path="$3" docker_compose_cert_directory="$docker_compose_instance_directory/volumes/certs" # Copy certificates -cp -RvL "{{ LETSENCRYPT_LIVE_PATH }}/$ssl_cert_folder/"* "$docker_compose_cert_directory" || exit 1 +cp -RvL "$letsencrypt_live_path/$ssl_cert_folder/"* "$docker_compose_cert_directory" || exit 1 # This code is optimized for mailu -cp -v "{{ LETSENCRYPT_LIVE_PATH }}/$ssl_cert_folder/privkey.pem" "$docker_compose_cert_directory/key.pem" || exit 1 -cp -v "{{ LETSENCRYPT_LIVE_PATH }}/$ssl_cert_folder/fullchain.pem" "$docker_compose_cert_directory/cert.pem" || exit 1 +cp -v "$letsencrypt_live_path/$ssl_cert_folder/privkey.pem" "$docker_compose_cert_directory/key.pem" || exit 1 +cp -v "$letsencrypt_live_path/$ssl_cert_folder/fullchain.pem" "$docker_compose_cert_directory/cert.pem" || exit 1 # Set correct reading rights chmod a+r -v "$docker_compose_cert_directory/"* diff --git a/roles/sys-svc-cert-sync-docker/handlers/main.yml b/roles/sys-svc-cert-sync-docker/handlers/main.yml new file mode 100644 index 00000000..05305c94 --- /dev/null +++ b/roles/sys-svc-cert-sync-docker/handlers/main.yml @@ -0,0 +1,7 @@ +--- +- name: "restart tls deploy to docker service" + systemd: + name: "{{ CERT_SYNC_DOCKER_SERVICE_NAME }}" + state: restarted + enabled: yes + daemon_reload: yes \ No newline at end of file diff --git a/roles/srv-proxy-6-6-tls-deploy/meta/main.yml b/roles/sys-svc-cert-sync-docker/meta/main.yml similarity index 96% rename from roles/srv-proxy-6-6-tls-deploy/meta/main.yml rename to roles/sys-svc-cert-sync-docker/meta/main.yml index f6d95e64..ae7b0331 100644 --- a/roles/srv-proxy-6-6-tls-deploy/meta/main.yml +++ b/roles/sys-svc-cert-sync-docker/meta/main.yml @@ -14,7 +14,7 @@ galaxy_info: - systemd repository: "https://s.infinito.nexus/code" issue_tracker_url: "https://s.infinito.nexus/issues" - documentation: "https://s.infinito.nexus/code/tree/main/roles/srv-proxy-6-6-tls-deploy" + documentation: "https://s.infinito.nexus/code/tree/main/roles/sys-svc-cert-sync-docker" min_ansible_version: "2.9" platforms: - name: Any diff --git a/roles/sys-svc-cert-sync-docker/tasks/01_core.yml b/roles/sys-svc-cert-sync-docker/tasks/01_core.yml new file mode 100644 index 00000000..5493895a --- /dev/null +++ b/roles/sys-svc-cert-sync-docker/tasks/01_core.yml @@ -0,0 +1,13 @@ +- name: Include dependency 'sys-alm-compose' + include_role: + name: sys-alm-compose + when: run_once_sys_alm_compose is not defined + +- name: "Install '{{ CERT_SYNC_DOCKER_SCRIPT_FILE }}'" + ansible.builtin.copy: + src: "{{ CERT_SYNC_DOCKER_SCRIPT_FILE }}" + dest: "{{ CERT_SYNC_DOCKER_SCRIPT_PATH }}" + mode: "0755" + owner: root + group: root + notify: restart tls deploy to docker service \ No newline at end of file diff --git a/roles/sys-svc-cert-sync-docker/tasks/main.yml b/roles/sys-svc-cert-sync-docker/tasks/main.yml new file mode 100644 index 00000000..229c564d --- /dev/null +++ b/roles/sys-svc-cert-sync-docker/tasks/main.yml @@ -0,0 +1,27 @@ +- block: + - include_tasks: 01_core.yml + - set_fact: + run_once_sys_svc_cert_sync_docker: true + when: run_once_sys_svc_cert_sync_docker is not defined + +- name: "create {{ cert_mount_directory }}" + file: + path: "{{ cert_mount_directory }}" + state: directory + mode: "0755" + notify: restart tls deploy to docker service + +- name: configure sys-svc-cert-sync-docker service + template: + src: "sys-svc-cert-sync-docker.service.j2" + dest: "/etc/systemd/system/{{ CERT_SYNC_DOCKER_SERVICE_NAME }}" + notify: restart tls deploy to docker service + +- name: "include role for sys-timer for {{ service_name }}" + include_role: + name: sys-timer + vars: + on_calendar: "{{ on_calendar_deploy_certificates }}" + service_name: "{{ CERT_SYNC_DOCKER_SERVICE_NAME }}" + persistent: "true" + diff --git a/roles/sys-svc-cert-sync-docker/templates/sys-svc-cert-sync-docker.service.j2 b/roles/sys-svc-cert-sync-docker/templates/sys-svc-cert-sync-docker.service.j2 new file mode 100644 index 00000000..64cf266a --- /dev/null +++ b/roles/sys-svc-cert-sync-docker/templates/sys-svc-cert-sync-docker.service.j2 @@ -0,0 +1,7 @@ +[Unit] +Description=Let's Encrypt deploy to {{ docker_compose.directories.instance }} +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service + +[Service] +Type=oneshot +ExecStart={{ PATH_ADMINISTRATOR_SCRIPTS }}/{{ CERT_SYNC_DOCKER_SCRIPT_FILE }} {{ ssl_cert_folder }} {{ docker_compose.directories.instance }} {{ LETSENCRYPT_LIVE_PATH }} diff --git a/roles/sys-svc-cert-sync-docker/vars/main.yml b/roles/sys-svc-cert-sync-docker/vars/main.yml new file mode 100644 index 00000000..3e8dbf06 --- /dev/null +++ b/roles/sys-svc-cert-sync-docker/vars/main.yml @@ -0,0 +1,3 @@ +CERT_SYNC_DOCKER_SCRIPT_FILE: "sys-svc-cert-sync-docker.sh" +CERT_SYNC_DOCKER_SCRIPT_PATH: "{{ PATH_ADMINISTRATOR_SCRIPTS }}{{ CERT_SYNC_DOCKER_SCRIPT_FILE }}" +CERT_SYNC_DOCKER_SERVICE_NAME: "sys-svc-cert-sync-docker.{{ application_id }}{{ SYS_SERVICE_SUFFIX }}" \ No newline at end of file diff --git a/roles/update-docker/templates/update-docker.service.j2 b/roles/update-docker/templates/update-docker.service.j2 index 6f8c40da..d7e517d4 100644 --- a/roles/update-docker/templates/update-docker.service.j2 +++ b/roles/update-docker/templates/update-docker.service.j2 @@ -1,6 +1,6 @@ [Unit] Description=Updates Docker Instances -OnFailure=sys-alm-compose.infinito@%n.service +OnFailure=sys-alm-compose.{{ SOFTWARE_NAME }}@%n.service [Service] Type=oneshot diff --git a/roles/web-app-bigbluebutton/templates/env.j2 b/roles/web-app-bigbluebutton/templates/env.j2 index 490d0047..7a625347 100644 --- a/roles/web-app-bigbluebutton/templates/env.j2 +++ b/roles/web-app-bigbluebutton/templates/env.j2 @@ -287,9 +287,9 @@ DEFAULT_REGISTRATION=invite ### EXTERNAL AUTHENTICATION METHODS # @See https://docs.bigbluebutton.org/greenlight/v3/external-authentication/ # -OPENID_CONNECT_CLIENT_ID={{ oidc.client.id }} -OPENID_CONNECT_CLIENT_SECRET={{ oidc.client.secret }} -OPENID_CONNECT_ISSUER={{ oidc.client.issuer_url }} +OPENID_CONNECT_CLIENT_ID={{ OIDC.CLIENT.ID }} +OPENID_CONNECT_CLIENT_SECRET={{ OIDC.CLIENT.SECRET }} +OPENID_CONNECT_ISSUER={{ OIDC.CLIENT.ISSUER_URL }} OPENID_CONNECT_REDIRECT={{ domains | get_url(application_id, WEB_PROTOCOL) }} # OPENID_CONNECT_UID_FIELD=sub default {% endif %} \ No newline at end of file diff --git a/roles/web-app-discourse/templates/config.yml.j2 b/roles/web-app-discourse/templates/config.yml.j2 index a7df4837..3db314d3 100644 --- a/roles/web-app-discourse/templates/config.yml.j2 +++ b/roles/web-app-discourse/templates/config.yml.j2 @@ -136,9 +136,9 @@ run: # OIDC Activation - exec: rails r "SiteSetting.openid_connect_enabled = true" - - exec: rails r "SiteSetting.openid_connect_discovery_document = '{{oidc.client.discovery_document}}'" - - exec: rails r "SiteSetting.openid_connect_client_id = '{{ oidc.client.id }}'" - - exec: rails r "SiteSetting.openid_connect_client_secret = '{{ oidc.client.secret }}'" + - exec: rails r "SiteSetting.openid_connect_discovery_document = '{{OIDC.CLIENT.DISCOVERY_DOCUMENT}}'" + - exec: rails r "SiteSetting.openid_connect_client_id = '{{ OIDC.CLIENT.ID }}'" + - exec: rails r "SiteSetting.openid_connect_client_secret = '{{ OIDC.CLIENT.SECRET }}'" - exec: rails r "SiteSetting.openid_connect_rp_initiated_logout_redirect = 'https://{{ domains | get_domain(application_id) }}'" - exec: rails r "SiteSetting.openid_connect_allow_association_change = false" - exec: rails r "SiteSetting.openid_connect_rp_initiated_logout = true" diff --git a/roles/web-app-espocrm/templates/env.j2 b/roles/web-app-espocrm/templates/env.j2 index 2c8c417d..bb76118f 100644 --- a/roles/web-app-espocrm/templates/env.j2 +++ b/roles/web-app-espocrm/templates/env.j2 @@ -86,20 +86,20 @@ ESPOCRM_CONFIG_OIDC_ALLOW_ADMIN_USER=true ESPOCRM_CONFIG_AUTHENTICATION_METHOD=Oidc ESPOCRM_CONFIG_OIDC_FALLBACK=false # set true if you want LDAP as fallback -ESPOCRM_CONFIG_OIDC_CLIENT_ID={{ oidc.client.id }} -ESPOCRM_CONFIG_OIDC_CLIENT_SECRET={{ oidc.client.secret }} +ESPOCRM_CONFIG_OIDC_CLIENT_ID={{ OIDC.CLIENT.ID }} +ESPOCRM_CONFIG_OIDC_CLIENT_SECRET={{ OIDC.CLIENT.SECRET }} -ESPOCRM_CONFIG_OIDC_AUTHORIZATION_ENDPOINT={{ oidc.client.authorize_url }} -ESPOCRM_CONFIG_OIDC_TOKEN_ENDPOINT={{ oidc.client.token_url }} -ESPOCRM_CONFIG_OIDC_USER_INFO_ENDPOINT={{ oidc.client.user_info_url }} -ESPOCRM_CONFIG_OIDC_JWKS_ENDPOINT={{ oidc.client.certs }} +ESPOCRM_CONFIG_OIDC_AUTHORIZATION_ENDPOINT={{ OIDC.CLIENT.AUTHORIZE_URL }} +ESPOCRM_CONFIG_OIDC_TOKEN_ENDPOINT={{ OIDC.CLIENT.TOKEN_URL }} +ESPOCRM_CONFIG_OIDC_USER_INFO_ENDPOINT={{ OIDC.CLIENT.USER_INFO_URL }} +ESPOCRM_CONFIG_OIDC_JWKS_ENDPOINT={{ OIDC.CLIENT.CERTS }} ESPOCRM_CONFIG_OIDC_AUTHORIZATION_REDIRECT_URI={{ espocrm_url }}/oidc/callback #ESPOCRM_CONFIG_OIDC_SCOPES=openid,profile,email # Defined in main.yml ESPOCRM_CONFIG_OIDC_CREATE_USER=true ESPOCRM_CONFIG_OIDC_SYNC=true -ESPOCRM_CONFIG_OIDC_USERNAME_CLAIM={{oidc.attributes.username}} +ESPOCRM_CONFIG_OIDC_USERNAME_CLAIM={{OIDC.ATTRIBUTES.USERNAME}} # ESPOCRM_CONFIG_OIDC_SYNC_TEAMS=true # ESPOCRM_CONFIG_OIDC_GROUP_CLAIM=group {% endif %} diff --git a/roles/web-app-gitea/tasks/cleanup/oidc.yml b/roles/web-app-gitea/tasks/cleanup/oidc.yml index 7af308ba..75b49c1b 100644 --- a/roles/web-app-gitea/tasks/cleanup/oidc.yml +++ b/roles/web-app-gitea/tasks/cleanup/oidc.yml @@ -3,7 +3,7 @@ shell: | docker exec -i --user {{ gitea_user }} {{ gitea_container }} \ gitea admin auth list \ - | awk -v name="{{ oidc.button_text }}" '$0 ~ name {print $1; exit}' + | awk -v name="{{ OIDC.BUTTON_TEXT }}" '$0 ~ name {print $1; exit}' args: chdir: "{{ docker_compose.directories.instance }}" register: oidc_source_id_raw diff --git a/roles/web-app-gitea/tasks/setup/oidc.yml b/roles/web-app-gitea/tasks/setup/oidc.yml index 55513d37..c2b04dec 100644 --- a/roles/web-app-gitea/tasks/setup/oidc.yml +++ b/roles/web-app-gitea/tasks/setup/oidc.yml @@ -3,10 +3,10 @@ docker exec -i --user {{ gitea_user }} {{ gitea_container }} \ gitea admin auth add-oauth \ --provider openidConnect \ - --name "{{ oidc.button_text }}" \ - --key "{{ oidc.client.id }}" \ - --secret "{{ oidc.client.secret }}" \ - --auto-discover-url "{{ oidc.client.discovery_document }}" \ + --name "{{ OIDC.BUTTON_TEXT }}" \ + --key "{{ OIDC.CLIENT.ID }}" \ + --secret "{{ OIDC.CLIENT.SECRET }}" \ + --auto-discover-url "{{ OIDC.CLIENT.DISCOVERY_DOCUMENT }}" \ --scopes "openid profile email" args: chdir: "{{ docker_compose.directories.instance }}" @@ -18,7 +18,7 @@ docker exec -i --user {{ gitea_user }} {{ gitea_container }} \ /app/gitea/gitea admin auth list \ | tail -n +2 \ - | grep -F "{{ oidc.button_text }}" \ + | grep -F "{{ OIDC.BUTTON_TEXT }}" \ | awk '{print $1; exit}' args: chdir: "{{ docker_compose.directories.instance }}" @@ -38,10 +38,10 @@ gitea admin auth update-oauth \ --id {{ oidc_source_id }}\ --provider openidConnect \ - --name "{{ oidc.button_text }}" \ - --key "{{ oidc.client.id }}" \ - --secret "{{ oidc.client.secret }}" \ - --auto-discover-url "{{ oidc.client.discovery_document }}" \ + --name "{{ OIDC.BUTTON_TEXT }}" \ + --key "{{ OIDC.CLIENT.ID }}" \ + --secret "{{ OIDC.CLIENT.SECRET }}" \ + --auto-discover-url "{{ OIDC.CLIENT.DISCOVERY_DOCUMENT }}" \ --scopes "openid profile email" args: chdir: "{{ docker_compose.directories.instance }}" diff --git a/roles/web-app-keycloak/templates/import/realm.json.j2 b/roles/web-app-keycloak/templates/import/realm.json.j2 index fb3a4970..d07c9cf0 100644 --- a/roles/web-app-keycloak/templates/import/realm.json.j2 +++ b/roles/web-app-keycloak/templates/import/realm.json.j2 @@ -832,7 +832,7 @@ "enabled": true, "alwaysDisplayInConsole": false, "clientAuthenticatorType": "desktop-secret", - "secret": "{{ oidc.client.secret }}", + "secret": "{{ OIDC.CLIENT.SECRET }}", {# The following line should be covered by 02_update_client_redirects.yml #} "redirectUris": {{ domains | redirect_uris(applications, WEB_PROTOCOL) | tojson }}, "webOrigins": [ @@ -1261,7 +1261,7 @@ "id.token.claim": "true", "lightweight.claim": "false", "access.token.claim": "true", - "claim.name": "{{ oidc.claims.groups }}" + "claim.name": "{{ OIDC.CLAIMS.GROUPS }}" } } ] @@ -1520,7 +1520,7 @@ "user.attribute": "username", "id.token.claim": "true", "access.token.claim": "true", - "claim.name": "{{oidc.attributes.username}}", + "claim.name": "{{OIDC.ATTRIBUTES.USERNAME}}", "jsonType.label": "String" } }, diff --git a/roles/web-app-keycloak/vars/main.yml b/roles/web-app-keycloak/vars/main.yml index ec7dbbbe..3f84865f 100644 --- a/roles/web-app-keycloak/vars/main.yml +++ b/roles/web-app-keycloak/vars/main.yml @@ -5,7 +5,7 @@ database_type: "postgres" # Keycloak keycloak_container: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.name') }}" # Name of the keycloak docker container keycloak_docker_import_directory: "/opt/keycloak/data/import/" # Directory in which keycloak import files are placed in the running docker container -keycloak_realm: "{{ oidc.client.realm }}" # This is the name of the default realm which is used by the applications +keycloak_realm: "{{ OIDC.CLIENT.ISSUER_URL }}" # This is the name of the default realm which is used by the applications 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 @@ -17,7 +17,7 @@ keycloak_image: "{{ applications | get_app_conf(application_ keycloak_version: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.version') }}" # Keycloak docker version keycloak_debug_enabled: "{{ MODE_DEBUG }}" keycloak_redirect_features: ["features.oauth2","features.oidc"] -keycloak_client_id: "{{ oidc.client.id }}" +keycloak_client_id: "{{ OIDC.CLIENT.ID }}" keycloak_ldap_component_name: "{{ ldap.server.domain }}" # Name of the LDAP User Federation component in Keycloak (as shown in UI) keycloak_import_realm: "{{ applications | get_app_conf(application_id, 'actions.import_realm') }}" # Activate realm import keycloak_update_ldap_bind: "{{ applications | get_app_conf(application_id, 'actions.update_ldap_bind') }}" # Toggle the LDAP bind update step diff --git a/roles/web-app-listmonk/tasks/main.yml b/roles/web-app-listmonk/tasks/main.yml index b15c09a8..9b705b4f 100644 --- a/roles/web-app-listmonk/tasks/main.yml +++ b/roles/web-app-listmonk/tasks/main.yml @@ -35,9 +35,9 @@ oidc_settings_json: >- {{ { "enabled": True, - "client_id": oidc.client.id, - "provider_url": oidc.client.issuer_url, - "client_secret": oidc.client.secret + "client_id": OIDC.CLIENT.ID, + "provider_url": OIDC.CLIENT.ISSUER_URL, + "client_secret": OIDC.CLIENT.SECRET } | to_json }} - name: Update administrator email and password login in Listmonk diff --git a/roles/web-app-listmonk/vars/main.yml b/roles/web-app-listmonk/vars/main.yml index 20bcb3b6..77d9976d 100644 --- a/roles/web-app-listmonk/vars/main.yml +++ b/roles/web-app-listmonk/vars/main.yml @@ -24,9 +24,9 @@ LISTMONK_SETTINGS: value: >- {{ { "enabled": True, - "client_id": oidc.client.id, - "provider_url": oidc.client.issuer_url, - "client_secret": oidc.client.secret + "client_id": OIDC.CLIENT.ID, + "provider_url": OIDC.CLIENT.ISSUER_URL, + "client_secret": OIDC.CLIENT.SECRET } | to_json }} when: applications | get_app_conf(application_id, 'features.oidc', False) diff --git a/roles/web-app-mailu/tasks/01_core.yml b/roles/web-app-mailu/tasks/01_core.yml index 1943b8ec..5b387fba 100644 --- a/roles/web-app-mailu/tasks/01_core.yml +++ b/roles/web-app-mailu/tasks/01_core.yml @@ -1,10 +1,23 @@ -- name: "load docker, db and proxy for {{ application_id }}" - include_role: - name: cmp-db-docker-proxy +- name: Ensure MAILU_HOSTNAMES is a list with max 1 entry + ansible.builtin.assert: + that: + - MAILU_HOSTNAMES is iterable + - MAILU_HOSTNAMES is sequence + - MAILU_HOSTNAMES | length <= 1 + fail_msg: "MAILU_HOSTNAMES must be a list with at most one entry (only one host is supported). You can set the other ones as alias." + success_msg: "MAILU_HOSTNAMES is valid." -- name: "Include the srv-proxy-6-6-tls-deploy role" - include_role: - name: srv-proxy-6-6-tls-deploy +- name: "Mailu Docker and Webserver Setup" + block: + - name: "load docker, db and proxy for {{ application_id }}" + include_role: + name: cmp-db-docker-proxy + + - name: "Include the sys-svc-cert-sync-docker role" + include_role: + name: sys-svc-cert-sync-docker + vars: + domain: "{{ MAILU_HOSTNAME }}" - name: Flush docker service handlers meta: flush_handlers @@ -12,10 +25,8 @@ - name: "Create Mailu accounts" include_tasks: 02_create-mailu-user.yml vars: - mailu_compose_dir: "{{ docker_compose.directories.instance }}" - mailu_domain: "{{ PRIMARY_DOMAIN }}" + MAILU_DOCKER_DIR: "{{ docker_compose.directories.instance }}" mailu_api_base_url: "http://127.0.0.1:8080/api/v1" - mailu_global_api_token: "{{ applications | get_app_conf(application_id, 'credentials.api_token') }}" mailu_action: >- {{ ( diff --git a/roles/web-app-mailu/tasks/02_create-mailu-user.yml b/roles/web-app-mailu/tasks/02_create-mailu-user.yml index 11b325a7..19a16315 100644 --- a/roles/web-app-mailu/tasks/02_create-mailu-user.yml +++ b/roles/web-app-mailu/tasks/02_create-mailu-user.yml @@ -1,9 +1,9 @@ -- name: "Ensure Mailu user '{{ mailu_user_key }};{{ mailu_user_name }}@{{ mailu_domain }}'' exists" +- name: "Ensure Mailu user '{{ mailu_user_key }};{{ mailu_user_name }}@{{ MAILU_DOMAIN }}'' exists" command: > docker compose exec admin flask mailu {{ mailu_action }} - {{ mailu_user_name }} {{ mailu_domain }} '{{ mailu_password }}' + {{ mailu_user_name }} {{ MAILU_DOMAIN }} '{{ mailu_password }}' args: - chdir: "{{ mailu_compose_dir }}" + chdir: "{{ MAILU_DOCKER_DIR }}" register: mailu_user_result failed_when: > mailu_user_result.rc != 0 and @@ -15,12 +15,12 @@ when: "'mail-bot' in item.value.roles or 'administrator' in item.value.roles" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" -- name: "Change password for user '{{ mailu_user_key }};{{ mailu_user_name }}@{{ mailu_domain }}'" +- name: "Change password for user '{{ mailu_user_key }};{{ mailu_user_name }}@{{ MAILU_DOMAIN }}'" command: > docker compose exec admin flask mailu password - {{ mailu_user_name }} {{ mailu_domain }} '{{ mailu_password }}' + {{ mailu_user_name }} {{ MAILU_DOMAIN }} '{{ mailu_password }}' args: - chdir: "{{ mailu_compose_dir }}" + chdir: "{{ MAILU_DOCKER_DIR }}" when: "'mail-bot' in item.value.roles or 'administrator' in item.value.roles" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" diff --git a/roles/web-app-mailu/tasks/03_create-mailu-token.yml b/roles/web-app-mailu/tasks/03_create-mailu-token.yml index cfeeca58..53cb4a59 100644 --- a/roles/web-app-mailu/tasks/03_create-mailu-token.yml +++ b/roles/web-app-mailu/tasks/03_create-mailu-token.yml @@ -3,9 +3,9 @@ command: >- docker compose exec -T admin \ curl -s -X GET {{ mailu_api_base_url }}/token \ - -H "Authorization: Bearer {{ mailu_global_api_token }}" + -H "Authorization: Bearer {{ MAILU_API_TOKEN }}" args: - chdir: "{{ mailu_compose_dir }}" + chdir: "{{ MAILU_DOCKER_DIR }}" register: mailu_tokens_cli changed_when: false no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" @@ -25,9 +25,9 @@ command: >- docker compose exec -T admin \ curl -s -X DELETE {{ mailu_api_base_url }}/token/{{ mailu_user_existing_token.id }} \ - -H "Authorization: Bearer {{ mailu_global_api_token }}" + -H "Authorization: Bearer {{ MAILU_API_TOKEN }}" args: - chdir: "{{ mailu_compose_dir }}" + chdir: "{{ MAILU_DOCKER_DIR }}" when: - users[mailu_user_key].mailu_token is not defined - mailu_user_existing_token is not none @@ -40,7 +40,7 @@ command: >- docker compose exec -T admin \ curl -s -X POST {{ mailu_api_base_url }}/token \ - -H "Authorization: Bearer {{ mailu_global_api_token }}" \ + -H "Authorization: Bearer {{ MAILU_API_TOKEN }}" \ -H "Content-Type: application/json" \ -d '{{ { "comment": mailu_user_key ~ " - ansible.infinito", @@ -48,7 +48,7 @@ "ip": mailu_token_ip } | to_json }}' args: - chdir: "{{ mailu_compose_dir }}" + chdir: "{{ MAILU_DOCKER_DIR }}" when: users[mailu_user_key].mailu_token is not defined register: mailu_token_creation changed_when: mailu_token_creation.rc == 0 diff --git a/roles/web-app-mailu/tasks/04_set-mailu-dns-records.yml b/roles/web-app-mailu/tasks/04_set-mailu-dns-records.yml index b6dab8c4..96649061 100644 --- a/roles/web-app-mailu/tasks/04_set-mailu-dns-records.yml +++ b/roles/web-app-mailu/tasks/04_set-mailu-dns-records.yml @@ -1,108 +1,125 @@ -- name: "Load Mailu DNS variables" - include_vars: vars/mailu-dns.yml - - name: Generate DKIM public key include_tasks: 05_generate-and-read-dkim.yml -- name: "Set A record for mail server" +# A/AAAA record for the mail host in the **Hostname Zone** +- name: "Set A record for Mailu host" community.general.cloudflare_dns: - api_token: "{{ cloudflare_record_api_token }}" - zone: "{{ mailu_dns_zone }}" + api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}" + zone: "{{ MAILU_HOSTNAME_DNS_ZONE }}" type: A - name: "{{ domain }}" - content: "{{ mailu_dns_ip }}" + name: "{{ MAILU_HOSTNAME }}" # Fully Qualified Domain Name of the mail host + content: "{{ MAILU_IP4_PUBLIC }}" proxied: false ttl: 1 state: present async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}" - poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" + poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" +- name: "Set AAAA record for Mailu host" + community.general.cloudflare_dns: + api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}" + zone: "{{ MAILU_HOSTNAME_DNS_ZONE }}" + type: AAAA + name: "{{ MAILU_HOSTNAME }}" + content: "{{ MAILU_IP6_PUBLIC }}" + proxied: false + ttl: 1 + state: present + when: MAILU_IP6_PUBLIC is defined and MAILU_IP6_PUBLIC | length > 0 + async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}" + poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" + no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" + +# Autoconfig CNAME record in the **Mail Domain Zone** - name: "Set CNAME record for autoconfig" community.general.cloudflare_dns: - api_token: "{{ cloudflare_record_api_token }}" - zone: "{{ mailu_dns_zone }}" + api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}" + zone: "{{ MAILU_DOMAIN_DNS_ZONE }}" type: CNAME - name: "autoconfig.{{ mailu_dns_zone }}" - value: "{{ domain }}" + name: "autoconfig.{{ MAILU_DOMAIN_DNS_ZONE }}" + value: "{{ MAILU_HOSTNAME }}" # Points to the Mailu host FQDN proxied: false ttl: 1 state: present async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}" - poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" + poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" +# MX record in the **Mail Domain Zone** - name: "Set MX record" community.general.cloudflare_dns: - api_token: "{{ cloudflare_record_api_token }}" - zone: "{{ mailu_dns_zone }}" + api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}" + zone: "{{ MAILU_DOMAIN_DNS_ZONE }}" type: MX - name: "{{ mailu_dns_zone }}" - value: "{{ domain }}" + name: "{{ MAILU_DOMAIN }}" # Root mail domain + value: "{{ MAILU_HOSTNAME }}" # Points to the Mailu host priority: 10 ttl: 1 state: present async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}" - poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" + poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" +# SRV records in the **Mail Domain Zone** - name: "Set SRV records" community.general.cloudflare_dns: - api_token: "{{ cloudflare_record_api_token }}" - zone: "{{ mailu_dns_zone }}" + api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}" + zone: "{{ MAILU_DOMAIN_DNS_ZONE }}" type: SRV service: "_{{ item.key }}" proto: "_tcp" priority: "{{ item.value.priority }}" weight: "{{ item.value.weight }}" port: "{{ item.value.port }}" - value: "{{ domain }}" + value: "{{ MAILU_HOSTNAME }}" # Target = Mailu host FQDN ttl: 1 state: present - loop: "{{ mailu_dns_srv_records | dict2items }}" + name: "{{ MAILU_DOMAIN }}" + loop: "{{ MAILU_DNS_SRV_RECORDS | dict2items }}" ignore_errors: true - #register: srv_result - #failed_when: srv_result.rc != 0 and ("An identical record already exists" not in srv_result.stdout) - #changed_when: srv_result.rc == 0 and ("An identical record already exists" not in srv_result.stdout) async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}" - poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" + poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" +# SPF TXT record in the **Mail Domain Zone** - name: "Set SPF TXT record" community.general.cloudflare_dns: - api_token: "{{ cloudflare_record_api_token }}" - zone: "{{ mailu_dns_zone }}" + api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}" + zone: "{{ MAILU_DOMAIN_DNS_ZONE }}" type: TXT - name: "{{ mailu_dns_zone }}" - value: "v=spf1 mx a:{{ domain }} ~all" + name: "{{ MAILU_DOMAIN }}" + value: "v=spf1 mx a:{{ MAILU_HOSTNAME }} ~all" ttl: 1 state: present async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}" - poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" + poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" +# DMARC TXT record in the **Mail Domain Zone** - name: "Set DMARC TXT record" community.general.cloudflare_dns: - api_token: "{{ cloudflare_record_api_token }}" - zone: "{{ mailu_dns_zone }}" + api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}" + zone: "{{ MAILU_DOMAIN_DNS_ZONE }}" type: TXT - name: "_dmarc.{{ mailu_dns_zone }}" - value: "v=DMARC1; p=reject; ruf=mailto:{{ mailu_dmarc_ruf }}; adkim=s; aspf=s" + name: "_dmarc.{{ MAILU_DOMAIN_DNS_ZONE }}" + value: "v=DMARC1; p=reject; ruf=mailto:{{ MAILU_DMARC_RUF }}; adkim=s; aspf=s" ttl: 1 state: present async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}" - poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" + poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" +# DKIM TXT record in the **Mail Domain Zone** - name: "Set DKIM TXT record" community.general.cloudflare_dns: - api_token: "{{ cloudflare_record_api_token }}" - zone: "{{ mailu_dns_zone }}" + api_token: "{{ MAILU_CLOUDFLARE_API_TOKEN }}" + zone: "{{ MAILU_DOMAIN_DNS_ZONE }}" type: TXT - name: "dkim._domainkey.{{ mailu_dns_zone }}" + name: "dkim._domainkey.{{ MAILU_DOMAIN_DNS_ZONE }}" value: "{{ mailu_dkim_public_key }}" ttl: 1 state: present async: "{{ ASYNC_TIME if ASYNC_ENABLED | bool else omit }}" - poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" - no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" \ No newline at end of file + poll: "{{ ASYNC_POLL if ASYNC_ENABLED | bool else omit }}" + no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" diff --git a/roles/web-app-mailu/tasks/05_generate-and-read-dkim.yml b/roles/web-app-mailu/tasks/05_generate-and-read-dkim.yml index 110e6eb3..66789f59 100644 --- a/roles/web-app-mailu/tasks/05_generate-and-read-dkim.yml +++ b/roles/web-app-mailu/tasks/05_generate-and-read-dkim.yml @@ -1,7 +1,7 @@ - name: Check if DKIM private key file exists in the antispam container command: > docker compose exec -T antispam - test -f {{ mailu_dkim_key_path }} + test -f {{ MAILU_DKIM_KEY_PATH }} register: dkim_key_file_stat failed_when: false changed_when: false @@ -11,7 +11,7 @@ - name: Generate DKIM key command: > docker compose exec -T antispam - rspamadm dkim_keygen -s dkim -d {{ applications | get_app_conf(application_id, 'domain', True) }} -k {{ mailu_dkim_key_path }} + rspamadm dkim_keygen -s dkim -d {{ MAILU_DOMAIN }} -k {{ MAILU_DKIM_KEY_PATH }} register: dkim_keygen_output when: dkim_key_file_stat.rc != 0 args: @@ -21,7 +21,7 @@ - name: Fetch DKIM private key from antispam container shell: > docker compose exec -T antispam - cat {{ mailu_dkim_key_path }} + cat {{ MAILU_DKIM_KEY_PATH }} args: chdir: "{{ docker_compose.directories.instance }}" register: dkim_priv_content diff --git a/roles/web-app-mailu/templates/docker-compose.yml.j2 b/roles/web-app-mailu/templates/docker-compose.yml.j2 index 97909808..25bdc36d 100644 --- a/roles/web-app-mailu/templates/docker-compose.yml.j2 +++ b/roles/web-app-mailu/templates/docker-compose.yml.j2 @@ -2,29 +2,29 @@ # Core services resolver: - image: {{docker_source}}/unbound:{{ mailu_version }} - container_name: {{mailu_name}}_resolver + image: {{ MAILU_DOCKER_FLAVOR }}/unbound:{{ MAILU_VERSION }} + container_name: {{ MAILU_CONTAINER }}_resolver {% include 'roles/docker-container/templates/base.yml.j2' %} {% include 'roles/docker-container/templates/networks.yml.j2' %} - ipv4_address: {{networks.local['web-app-mailu'].dns}} + ipv4_address: {{ MAILU_DNS_RESOLVER }} front: - container_name: {{mailu_name}}_front - image: {{docker_source}}/nginx:{{ mailu_version }} + container_name: {{ MAILU_CONTAINER }}_front + image: {{ MAILU_DOCKER_FLAVOR }}/nginx:{{ MAILU_VERSION }} {% include 'roles/docker-container/templates/base.yml.j2' %} ports: - "127.0.0.1:{{ports.localhost.http[application_id]}}:80" - - "{{ networks.internet.ip4 }}:25:25" - - "{{ networks.internet.ip4 }}:465:465" - - "{{ networks.internet.ip4 }}:587:587" - - "{{ networks.internet.ip4 }}:110:110" - - "{{ networks.internet.ip4 }}:995:995" - - "{{ networks.internet.ip4 }}:143:143" - - "{{ networks.internet.ip4 }}:993:993" - - "{{ networks.internet.ip4 }}:4190:4190" + - "{{ MAILU_IP4_PUBLIC }}:25:25" + - "{{ MAILU_IP4_PUBLIC }}:465:465" + - "{{ MAILU_IP4_PUBLIC }}:587:587" + - "{{ MAILU_IP4_PUBLIC }}:110:110" + - "{{ MAILU_IP4_PUBLIC }}:995:995" + - "{{ MAILU_IP4_PUBLIC }}:143:143" + - "{{ MAILU_IP4_PUBLIC }}:993:993" + - "{{ MAILU_IP4_PUBLIC }}:4190:4190" volumes: - "{{docker_compose.directories.volumes}}overrides/nginx:/overrides:ro" - - "{{cert_mount_directory}}:/certs:ro" + - "{{ cert_mount_directory }}:/certs:ro" {% include 'roles/docker-container/templates/depends_on/dmbs_incl.yml.j2' %} resolver: condition: service_started @@ -32,11 +32,11 @@ webmail: radicale: dns: - - {{networks.local['web-app-mailu'].dns}} + - {{ MAILU_DNS_RESOLVER }} admin: - container_name: {{mailu_name}}_admin - image: {{docker_source}}/admin:{{ mailu_version }} + container_name: {{ MAILU_CONTAINER }}_admin + image: {{ MAILU_DOCKER_FLAVOR }}/admin:{{ MAILU_VERSION }} {% include 'roles/docker-container/templates/base.yml.j2' %} volumes: - "admin_data:/data" @@ -47,12 +47,12 @@ front: condition: service_started dns: - - {{networks.local['web-app-mailu'].dns}} + - {{ MAILU_DNS_RESOLVER }} {% include 'roles/docker-container/templates/networks.yml.j2' %} imap: - container_name: {{mailu_name}}_imap - image: {{docker_source}}/dovecot:{{ mailu_version }} + container_name: {{ MAILU_CONTAINER }}_imap + image: {{ MAILU_DOCKER_FLAVOR }}/dovecot:{{ MAILU_VERSION }} {% include 'roles/docker-container/templates/base.yml.j2' %} volumes: - "dovecot_mail:/mail" @@ -61,12 +61,12 @@ - front - resolver dns: - - {{networks.local['web-app-mailu'].dns}} + - {{ MAILU_DNS_RESOLVER }} {% include 'roles/docker-container/templates/networks.yml.j2' %} smtp: - container_name: {{mailu_name}}_smtp - image: {{docker_source}}/postfix:{{ mailu_version }} + container_name: {{ MAILU_CONTAINER }}_smtp + image: {{ MAILU_DOCKER_FLAVOR }}/postfix:{{ MAILU_VERSION }} {% include 'roles/docker-container/templates/base.yml.j2' %} volumes: - "{{docker_compose.directories.volumes}}overrides:/overrides:ro" @@ -75,24 +75,24 @@ - front - resolver dns: - - {{networks.local['web-app-mailu'].dns}} + - {{ MAILU_DNS_RESOLVER }} {% include 'roles/docker-container/templates/networks.yml.j2' %} oletools: - container_name: {{mailu_name}}_oletools - image: {{docker_source}}/oletools:{{ mailu_version }} + container_name: {{ MAILU_CONTAINER }}_oletools + image: {{ MAILU_DOCKER_FLAVOR }}/oletools:{{ MAILU_VERSION }} hostname: oletools restart: {{ DOCKER_RESTART_POLICY }} depends_on: - resolver dns: - - {{networks.local['web-app-mailu'].dns}} + - {{ MAILU_DNS_RESOLVER }} {% include 'roles/docker-container/templates/networks.yml.j2' %} noinet: antispam: - container_name: {{mailu_name}}_antispam - image: {{docker_source}}/rspamd:{{ mailu_version }} + container_name: {{ MAILU_CONTAINER }}_antispam + image: {{ MAILU_DOCKER_FLAVOR }}/rspamd:{{ MAILU_VERSION }} {% include 'roles/docker-container/templates/base.yml.j2' %} volumes: - "filter:/var/lib/rspamd" @@ -104,14 +104,14 @@ - antivirus - resolver dns: - - {{networks.local['web-app-mailu'].dns}} + - {{ MAILU_DNS_RESOLVER }} {% include 'roles/docker-container/templates/networks.yml.j2' %} noinet: # Optional services antivirus: - container_name: {{mailu_name}}_antivirus + container_name: {{ MAILU_CONTAINER }}_antivirus image: clamav/clamav-debian:latest {% include 'roles/docker-container/templates/base.yml.j2' %} volumes: @@ -119,25 +119,25 @@ depends_on: - resolver dns: - - {{networks.local['web-app-mailu'].dns}} + - {{ MAILU_DNS_RESOLVER }} {% include 'roles/docker-container/templates/networks.yml.j2' %} webdav: - container_name: {{mailu_name}}_webdav - image: {{docker_source}}/radicale:{{ mailu_version }} + container_name: {{ MAILU_CONTAINER }}_webdav + image: {{ MAILU_DOCKER_FLAVOR }}/radicale:{{ MAILU_VERSION }} {% include 'roles/docker-container/templates/base.yml.j2' %} volumes: - "webdav_data:/data" depends_on: - resolver dns: - - {{networks.local['web-app-mailu'].dns}} + - {{ MAILU_DNS_RESOLVER }} {% include 'roles/docker-container/templates/networks.yml.j2' %} radicale: fetchmail: - container_name: {{mailu_name}}_fetchmail - image: {{docker_source}}/fetchmail:{{ mailu_version }} + container_name: {{ MAILU_CONTAINER }}_fetchmail + image: {{ MAILU_DOCKER_FLAVOR }}/fetchmail:{{ MAILU_VERSION }} volumes: - "admin_data:/data" {% include 'roles/docker-container/templates/base.yml.j2' %} @@ -147,12 +147,12 @@ - imap - resolver dns: - - {{networks.local['web-app-mailu'].dns}} + - {{ MAILU_DNS_RESOLVER }} {% include 'roles/docker-container/templates/networks.yml.j2' %} webmail: - container_name: {{mailu_name}}_webmail - image: {{docker_source}}/webmail:{{ mailu_version }} + container_name: {{ MAILU_CONTAINER }}_webmail + image: {{ MAILU_DOCKER_FLAVOR }}/webmail:{{ MAILU_VERSION }} {% include 'roles/docker-container/templates/base.yml.j2' %} volumes: - "webmail_data:/data" @@ -162,25 +162,25 @@ - front - resolver dns: - - {{networks.local['web-app-mailu'].dns}} + - {{ MAILU_DNS_RESOLVER }} {% include 'roles/docker-container/templates/networks.yml.j2' %} webmail: {% include 'roles/docker-compose/templates/volumes.yml.j2' %} smtp_queue: - name: {{ mailu_smtp_queue }} + name: {{ MAILU_SMTP_QUEUE_VOLUME }} admin_data: - name: {{ mailu_admin_data }} + name: {{ MAILU_ADMIN_DATA_VOLUME }} webdav_data: - name: {{ mailu_webdav_data }} + name: {{ MAILU_WEBDAV_DATA }} webmail_data: - name: {{ mailu_webmail_data }} + name: {{ MAILU_WEBMAIL_DATA }} filter: - name: {{ mailu_filter }} + name: {{ MAILU_FILTER_VOLUME }} dkim: - name: {{ mailu_dkim }} + name: {{ MAILU_DKIM_VOLUME }} dovecot_mail: - name: {{ mailu_dovecot_mail }} + name: {{ MAILU_DOVECOT_MAIL_VOLUME }} {% include 'roles/docker-compose/templates/networks.yml.j2' %} radicale: diff --git a/roles/web-app-mailu/templates/env.j2 b/roles/web-app-mailu/templates/env.j2 index 3f12a89d..da4598a9 100644 --- a/roles/web-app-mailu/templates/env.j2 +++ b/roles/web-app-mailu/templates/env.j2 @@ -11,16 +11,16 @@ LD_PRELOAD=/usr/lib/libhardened_malloc.so # Set to a randomly generated 16 bytes string -SECRET_KEY={{applications | get_app_conf(application_id,'credentials.secret_key')}} +SECRET_KEY={{ MAILU_SECRET_KEY }} # Subnet of the docker network. This should not conflict with any networks to which your system is connected. (Internal and external!) -SUBNET={{networks.local['web-app-mailu'].subnet}} +SUBNET={{ MAILU_SUBNET }} # Main mail domain -DOMAIN={{ applications | get_app_conf(application_id,'domain') }} +DOMAIN={{ MAILU_DOMAIN }} # Hostnames for this server, separated with comas -HOSTNAMES={{ domains[application_id] | join(',') }} +HOSTNAMES={{ MAILU_HOSTNAMES | join(',') }} # Postmaster local part (will append the main mail domain) POSTMASTER=admin @@ -105,7 +105,7 @@ WEB_WEBMAIL=/webmail SITENAME=Mailservices # Linked Website URL -WEBSITE={{ domains | get_url(application_id, WEB_PROTOCOL) }} +WEBSITE={{ MAILU_WEBSITE }} @@ -151,34 +151,34 @@ SQLALCHEMY_DATABASE_URI=mysql+mysqlconnector://{{ database_username }}:{{ databa API=true WEB_API=/api # Configures the authentication token. The minimum length is 3 characters. This token must be passed as request header to the API as authentication token. This is a mandatory setting for using the RESTful API. -API_TOKEN={{ applications | get_app_conf(application_id, 'credentials.api_token')}} +API_TOKEN={{ MAILU_API_TOKEN}} # Activated https://mailu.io/master/configuration.html#advanced-settings AUTH_REQUIRE_TOKENS=True -{% if applications | get_app_conf(application_id, 'features.oidc', False) %} +{% if MAILU_OIDC_ENABLED | bool %} ################################### # OpenID Connect settings ################################### # @see https://github.com/heviat/Mailu-OIDC/tree/master # Enable OpenID Connect. Possible values: True, False -OIDC_ENABLED={{ applications | get_app_conf(application_id, 'features.oidc', False) | string | capitalize }} +OIDC_ENABLED={{ MAILU_OIDC_ENABLED | string | capitalize }} # OpenID Connect provider configuration URL -OIDC_PROVIDER_INFO_URL={{ oidc.client.issuer_url }} +OIDC_PROVIDER_INFO_URL={{ OIDC.CLIENT.ISSUER_URL }} # OpenID Connect Client ID for Mailu -OIDC_CLIENT_ID={{ oidc.client.id }} +OIDC_CLIENT_ID={{ OIDC.CLIENT.ID }} # OpenID Connect Client secret for Mailu -OIDC_CLIENT_SECRET={{ oidc.client.secret }} +OIDC_CLIENT_SECRET={{ OIDC.CLIENT.SECRET }} # Label text for OpenID Connect login button. Default: OpenID Connect -OIDC_BUTTON_NAME={{ oidc.button_text }} +OIDC_BUTTON_NAME={{ OIDC.BUTTON_TEXT }} # Disable TLS certificate verification for the OIDC client. Possible values: True, False OIDC_VERIFY_SSL=True @@ -187,17 +187,17 @@ OIDC_VERIFY_SSL=True OIDC_CHANGE_PASSWORD_REDIRECT_ENABLED=True # Redirect URL for password change. Defaults to provider issuer url appended by /.well-known/change-password -OIDC_CHANGE_PASSWORD_REDIRECT_URL={{oidc.client.change_credentials}} +OIDC_CHANGE_PASSWORD_REDIRECT_URL={{ OIDC.CLIENT.CHANGE_CREDENTIALS }} -{% if applications | get_app_conf(application_id, 'oidc.email_by_username', True) | bool %} +{% if MAILU_OIDC_EMAIL_BY_USERNAME_ENABLED | bool %} # The OIDC claim used as the username. If the selected claim contains an email address, it will be used as is. If it is not an email (e.g., sub), the email address will be constructed as @. Defaults to email. -OIDC_USERNAME_CLAIM={{oidc.attributes.username}} +OIDC_USERNAME_CLAIM={{ OIDC.ATTRIBUTES.USERNAME }} # The domain used when constructing an email from a non-email username (e.g., when OIDC_USERNAME_CLAIM=sub). Ignored if OIDC_USERNAME_CLAIM is already an email. Defaults to the value of DOMAIN. -OIDC_USER_DOMAIN={{ PRIMARY_DOMAIN }} +OIDC_USER_DOMAIN={{ MAILU_DOMAIN }} {% endif %} # If enabled, users who authenticate successfully but do not yet have an account will have one created for them. If disabled, only existing users can log in, and authentication will fail for users without a pre-existing account. Defaults to True. -OIDC_ENABLE_USER_CREATION={{ applications | get_app_conf(application_id, 'oidc.enable_user_creation', True) | string | capitalize }} +OIDC_ENABLE_USER_CREATION={{ MAILU_OIDC_ENABLE_USER_CREATION }} {% endif %} \ No newline at end of file diff --git a/roles/web-app-mailu/vars/mailu-dns.yml b/roles/web-app-mailu/vars/mailu-dns.yml deleted file mode 100644 index 36e4c936..00000000 --- a/roles/web-app-mailu/vars/mailu-dns.yml +++ /dev/null @@ -1,41 +0,0 @@ -# vars/mailu-dns.yml - -mailu_dns_zone: "{{ applications | get_app_conf(application_id, 'domain', True) }}" -mailu_dns_ip: "{{ networks.internet.ip4 }}" - -cloudflare_record_api_token: "{{ CERTBOT_DNS_API_TOKEN }}" - -mailu_dmarc_ruf: "{{ applications | get_app_conf(application_id, 'users.administrator.email', True) }}" - -mailu_dkim_key_file: "{{ applications | get_app_conf(application_id, 'domain', True) }}.dkim.key" -mailu_dkim_key_path: "/dkim/{{ mailu_dkim_key_file }}" - -mailu_dns_srv_records: - submission: - port: 587 - priority: 20 - weight: 1 - submissions: - port: 465 - priority: 20 - weight: 1 - imaps: - port: 993 - priority: 20 - weight: 1 - imap: - port: 143 - priority: 20 - weight: 1 - pop3s: - port: 995 - priority: 20 - weight: 1 - pop3: - port: 110 - priority: 20 - weight: 1 - autodiscover: - port: "{{ WEB_PORT }}" - priority: 20 - weight: 1 \ No newline at end of file diff --git a/roles/web-app-mailu/vars/main.yml b/roles/web-app-mailu/vars/main.yml index 78919ce5..ee9c0baf 100644 --- a/roles/web-app-mailu/vars/main.yml +++ b/roles/web-app-mailu/vars/main.yml @@ -1,26 +1,70 @@ # General -application_id: "web-app-mailu" -domain: "{{ domains | get_domain(application_id) }}" -http_port: "{{ ports.localhost.http[application_id] }}" -proxy_extra_configuration: "client_max_body_size 31M;" +application_id: "web-app-mailu" +http_port: "{{ ports.localhost.http[application_id] }}" +proxy_extra_configuration: "client_max_body_size 31M;" # Database Configuration -database_password: "{{ applications | get_app_conf(application_id, ' credentials.database_password') }}" -database_type: "mariadb" +database_password: "{{ applications | get_app_conf(application_id, 'credentials.database_password') }}" +database_type: "mariadb" -cert_mount_directory: "{{ docker_compose.directories.volumes }}certs/" +# Cert Mount +cert_mount_directory: "{{ docker_compose.directories.volumes }}certs/" + +# Mailu + +## Meta +MAILU_WEBSITE: "{{ domains | get_url(application_id, WEB_PROTOCOL) }}" + +## Domains +MAILU_DOMAIN: "{{ applications | get_app_conf(application_id, 'domain') }}" +MAILU_DOMAIN_DNS_ZONE: "{{ MAILU_DOMAIN | to_zone }}" +MAILU_HOSTNAMES: "{{ domains[application_id] }}" +MAILU_HOSTNAME: "{{ domains | get_domain(application_id) }}" +MAILU_HOSTNAME_DNS_ZONE: "{{ MAILU_HOSTNAME | to_zone }}" + +## Docker +MAILU_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.mailu.version') }}" +MAILU_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.mailu.name') }}" + +## Volumes +MAILU_SMTP_QUEUE_VOLUME: "mailu_smtp_queue" +MAILU_ADMIN_DATA_VOLUME: "mailu_admin_data" +MAILU_WEBDAV_DATA: "mailu_webdav_data" +MAILU_WEBMAIL_DATA: "mailu_webmail_data" +MAILU_FILTER_VOLUME: "mailu_filter" +MAILU_DKIM_VOLUME: "mailu_dkim" +MAILU_DOVECOT_MAIL_VOLUME: "mailu_dovecot_mail" + +## Network +MAILU_DNS_RESOLVER: "{{ networks.local['web-app-mailu'].dns_resolver }}" +MAILU_IP4_PUBLIC: "{{ networks.internet.ip4 }}" +MAILU_IP6_PUBLIC: false #Deactivated atm. but cloudflare logic present +MAILU_SUBNET: "{{ networks.local['web-app-mailu'].subnet }}" + +## Credentials +MAILU_SECRET_KEY: "{{ applications | get_app_conf(application_id,'credentials.secret_key') }}" +MAILU_CLOUDFLARE_API_TOKEN: "{{ CERTBOT_DNS_API_TOKEN }}" +MAILU_API_TOKEN: "{{ applications | get_app_conf(application_id, 'credentials.api_token') }}" + +## OIDC +MAILU_OIDC_ENABLED: "{{ applications | get_app_conf(application_id, 'features.oidc', False) }}" +MAILU_OIDC_EMAIL_BY_USERNAME_ENABLED: "{{ applications | get_app_conf(application_id, 'oidc.email_by_username') }}" +MAILU_OIDC_ENABLE_USER_CREATION: "{{ applications | get_app_conf(application_id, 'oidc.enable_user_creation') | string | capitalize }}" # Use dedicated source for oidc if activated # @see https://github.com/heviat/Mailu-OIDC/tree/2024.06 -docker_source: "{{ 'ghcr.io/heviat' if applications | get_app_conf(application_id, 'features.oidc', False) else 'ghcr.io/mailu' }}" +MAILU_DOCKER_FLAVOR: "{{ 'ghcr.io/heviat' if MAILU_OIDC_ENABLED | bool else 'ghcr.io/mailu' }}" -# Mailu Specific -mailu_version: "{{ applications | get_app_conf(application_id, 'docker.services.mailu.version', True) }}" -mailu_name: "{{ applications | get_app_conf(application_id, 'docker.services.mailu.name', True) }}" -mailu_smtp_queue: "mailu_smtp_queue" -mailu_admin_data: "mailu_admin_data" -mailu_webdav_data: "mailu_webdav_data" -mailu_webmail_data: "mailu_webmail_data" -mailu_filter: "mailu_filter" -mailu_dkim: "mailu_dkim" -mailu_dovecot_mail: "mailu_dovecot_mail" +MAILU_DMARC_RUF: "{{ applications | get_app_conf(application_id, 'users.administrator.email') }}" + +MAILU_DKIM_KEY_FILE: "{{ MAILU_DOMAIN }}.dkim.key" +MAILU_DKIM_KEY_PATH: "/dkim/{{ MAILU_DKIM_KEY_FILE }}" + +MAILU_DNS_SRV_RECORDS: + submission: { port: 587, priority: 20, weight: 1 } + submissions: { port: 465, priority: 20, weight: 1 } + imaps: { port: 993, priority: 20, weight: 1 } + imap: { port: 143, priority: 20, weight: 1 } + pop3s: { port: 995, priority: 20, weight: 1 } + pop3: { port: 110, priority: 20, weight: 1 } + autodiscover: { port: 443, priority: 20, weight: 1 } \ No newline at end of file diff --git a/roles/web-app-mastodon/templates/env.j2 b/roles/web-app-mastodon/templates/env.j2 index 032f96eb..a9c7a917 100644 --- a/roles/web-app-mastodon/templates/env.j2 +++ b/roles/web-app-mastodon/templates/env.j2 @@ -60,16 +60,16 @@ SMTP_FROM_ADDRESS=Mastodon <{{ users['no-reply'].email }}> # @see https://stackoverflow.com/questions/72081776/how-mastodon-configured-login-using-sso OIDC_ENABLED={{ applications | get_app_conf(application_id, 'features.oidc', False) | string | lower }} -OIDC_DISPLAY_NAME="{{ oidc.button_text }}" -OIDC_ISSUER={{ oidc.client.issuer_url }} +OIDC_DISPLAY_NAME="{{ OIDC.BUTTON_TEXT }}" +OIDC_ISSUER={{ OIDC.CLIENT.ISSUER_URL }} OIDC_DISCOVERY=true OIDC_SCOPE="openid,profile,email" # @see https://stackoverflow.com/questions/72108087/how-to-set-the-username-of-mastodon-by-log-in-via-keycloak -OIDC_UID_FIELD={{oidc.attributes.username}} -OIDC_CLIENT_ID={{ oidc.client.id }} +OIDC_UID_FIELD={{OIDC.ATTRIBUTES.USERNAME}} +OIDC_CLIENT_ID={{ OIDC.CLIENT.ID }} OIDC_REDIRECT_URI=https://{{ domains | get_domain(application_id) }}/auth/auth/openid_connect/callback OIDC_SECURITY_ASSUME_EMAIL_IS_VERIFIED=true -OIDC_CLIENT_SECRET={{ oidc.client.secret }} +OIDC_CLIENT_SECRET={{ OIDC.CLIENT.SECRET }} # uncomment to only use OIDC for login / registration buttons OMNIAUTH_ONLY=true ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH=true diff --git a/roles/web-app-matrix/templates/synapse/homeserver.yaml.j2 b/roles/web-app-matrix/templates/synapse/homeserver.yaml.j2 index 4100c170..1a44548c 100644 --- a/roles/web-app-matrix/templates/synapse/homeserver.yaml.j2 +++ b/roles/web-app-matrix/templates/synapse/homeserver.yaml.j2 @@ -50,14 +50,14 @@ email: # @See https://matrix-org.github.io/synapse/latest/openid.html oidc_providers: - idp_id: keycloak - idp_name: "{{ oidc.button_text }}" - issuer: "{{ oidc.client.issuer_url }}" - client_id: "{{ oidc.client.id }}" - client_secret: "{{ oidc.client.secret }}" + idp_name: "{{ OIDC.BUTTON_TEXT }}" + issuer: "{{ OIDC.CLIENT.ISSUER_URL }}" + client_id: "{{ OIDC.CLIENT.ID }}" + client_secret: "{{ OIDC.CLIENT.SECRET }}" scopes: ["openid", "profile"] user_mapping_provider: config: - localpart_template: "{% raw %}{{ user.{% endraw %}{{oidc.attributes.username}}{% raw %}}}{% endraw %}" + localpart_template: "{% raw %}{{ user.{% endraw %}{{OIDC.ATTRIBUTES.USERNAME}}{% raw %}}}{% endraw %}" display_name_template: "{% raw %}{{ user.name }}{% endraw %}" backchannel_logout_enabled: true {% endif %} diff --git a/roles/web-app-mobilizon/templates/config.exs.j2 b/roles/web-app-mobilizon/templates/config.exs.j2 index d7f1a7cd..a4e6be97 100644 --- a/roles/web-app-mobilizon/templates/config.exs.j2 +++ b/roles/web-app-mobilizon/templates/config.exs.j2 @@ -264,15 +264,15 @@ config :ueberauth, config :mobilizon, :auth, oauth_consumer_strategies: [ - {:keycloak, "{{ oidc.button_text }}"} + {:keycloak, "{{ OIDC.BUTTON_TEXT }}"} ] config :ueberauth, Ueberauth.Strategy.Keycloak.OAuth, - client_id: "{{ oidc.client.id }}", - client_secret: "{{ oidc.client.secret }}", - site: "{{ oidc.url }}", - authorize_url: "{{ oidc.client.authorize_url }}", - token_url: "{{ oidc.client.token_url }}", - userinfo_url: "{{ oidc.client.user_info_url }}", + client_id: "{{ OIDC.CLIENT.ID }}", + client_secret: "{{ OIDC.CLIENT.SECRET }}", + site: "{{ OIDC.URL }}", + authorize_url: "{{ OIDC.CLIENT.AUTHORIZE_URL }}", + token_url: "{{ OIDC.CLIENT.TOKEN_URL }}", + userinfo_url: "{{ OIDC.CLIENT.USER_INFO_URL }}", token_method: :post {% endif %} \ No newline at end of file diff --git a/roles/web-app-moodle/tasks/03_oidc.yml b/roles/web-app-moodle/tasks/03_oidc.yml index 41d2c5bb..192f494d 100644 --- a/roles/web-app-moodle/tasks/03_oidc.yml +++ b/roles/web-app-moodle/tasks/03_oidc.yml @@ -23,19 +23,19 @@ loop: - { name: "idptype", value: 3 } - { name: "clientauthmethod", value: 1 } - - { name: "clientid", value: "{{ oidc.client.id }}" } - - { name: "clientsecret", value: "{{ oidc.client.secret }}" } - - { name: "opname", value: "{{ oidc.button_text }}" } + - { name: "clientid", value: "{{ OIDC.CLIENT.ID }}" } + - { name: "clientsecret", value: "{{ OIDC.CLIENT.SECRET }}" } + - { name: "opname", value: "{{ OIDC.BUTTON_TEXT }}" } - { name: "oidcscope", value: "openid profile email" } - - { name: "authendpoint", value: "{{ oidc.client.authorize_url }}" } - - { name: "tokenendpoint", value: "{{ oidc.client.token_url }}" } - - { name: "bindingusernameclaim", value: "{{ oidc.attributes.username }}" } + - { name: "authendpoint", value: "{{ OIDC.CLIENT.AUTHORIZE_URL }}" } + - { name: "tokenendpoint", value: "{{ OIDC.CLIENT.TOKEN_URL }}" } + - { name: "bindingusernameclaim", value: "{{ OIDC.ATTRIBUTES.USERNAME }}" } - { name: "single_sign_off", value: 1 } # Logs the user out from the IDP - - { name: "logouturi", value: "{{ oidc.client.logout_url }}" } + - { name: "logouturi", value: "{{ OIDC.CLIENT.LOGOUT_URL }}" } - { name: "icon", value: "moodle:t/lock" } - - { name: "field_map_firstname", value: "{{ oidc.attributes.given_name }}" } + - { name: "field_map_firstname", value: "{{ OIDC.ATTRIBUTES.GIVEN_NAME }}" } - { name: "field_lock_firstname", value: "locked" } - - { name: "field_map_lastname", value: "{{ oidc.attributes.family_name }}" } + - { name: "field_map_lastname", value: "{{ OIDC.ATTRIBUTES.FAMILY_NAME }}" } - { name: "field_lock_lastname", value: "locked" } - { name: "field_map_email", value: "locked" } #- { name: "showloginform", value: 0 } # Deactivate if OIDC is active diff --git a/roles/web-app-nextcloud/templates/config/oidc.config.php.j2 b/roles/web-app-nextcloud/templates/config/oidc.config.php.j2 index e41cc506..18796348 100644 --- a/roles/web-app-nextcloud/templates/config/oidc.config.php.j2 +++ b/roles/web-app-nextcloud/templates/config/oidc.config.php.j2 @@ -11,11 +11,11 @@ return array ( 'lost_password_link' => 'disabled', // URL of provider. All other URLs are auto-discovered from .well-known - 'oidc_login_provider_url' => '{{ oidc.client.issuer_url }}', + 'oidc_login_provider_url' => '{{ OIDC.CLIENT.ISSUER_URL }}', // Client ID and secret registered with the provider - 'oidc_login_client_id' => '{{ oidc.client.id }}', - 'oidc_login_client_secret' => '{{ oidc.client.secret }}', + 'oidc_login_client_id' => '{{ OIDC.CLIENT.ID }}', + 'oidc_login_client_secret' => '{{ OIDC.CLIENT.SECRET }}', // Automatically redirect the login page to the provider 'oidc_login_auto_redirect' => true, @@ -36,7 +36,7 @@ return array ( 'oidc_login_default_quota' => '{{applications | get_app_conf(application_id, 'default_quota', True)}}', // Login button text - 'oidc_login_button_text' => '{{ oidc.button_text }}', + 'oidc_login_button_text' => '{{ OIDC.BUTTON_TEXT }}', // Hide the NextCloud password change form. 'oidc_login_hide_password_form' => true, @@ -102,7 +102,7 @@ return array ( 'mail' => 'email', 'quota' => '{{ ldap.user.attributes.nextcloud_quota }}', # 'home' => 'homeDirectory', # Not implemented yet - 'ldap_uid' => '{{oidc.attributes.username}}', + 'ldap_uid' => '{{OIDC.ATTRIBUTES.USERNAME}}', # 'groups' => 'ownCloudGroups', # Not implemented yet # 'login_filter' => 'realm_access_roles', // 'photoURL' => 'picture', diff --git a/roles/web-app-nextcloud/vars/plugins/sociallogin.yml b/roles/web-app-nextcloud/vars/plugins/sociallogin.yml index f73ec5d0..66a92ed6 100644 --- a/roles/web-app-nextcloud/vars/plugins/sociallogin.yml +++ b/roles/web-app-nextcloud/vars/plugins/sociallogin.yml @@ -28,13 +28,13 @@ plugin_configuration: - name: "{{ domains | get_domain('web-app-keycloak') }}" title: "keycloak" style: "keycloak" - authorizeUrl: "{{ oidc.client.authorize_url }}" - tokenUrl: "{{ oidc.client.token_url }}" + authorizeUrl: "{{ OIDC.CLIENT.AUTHORIZE_URL }}" + tokenUrl: "{{ OIDC.CLIENT.TOKEN_URL }}" displayNameClaim: "" - userInfoUrl: "{{ oidc.client.user_info_url }}" - logoutUrl: "{{ oidc.client.logout_url }}" - clientId: "{{ oidc.client.id }}" - clientSecret: "{{ oidc.client.secret }}" + userInfoUrl: "{{ OIDC.CLIENT.USER_INFO_URL }}" + logoutUrl: "{{ OIDC.CLIENT.LOGOUT_URL }}" + clientId: "{{ OIDC.CLIENT.ID }}" + clientSecret: "{{ OIDC.CLIENT.SECRET }}" scope: "openid" groupsClaim: "" defaultGroup: "" diff --git a/roles/web-app-oauth2-proxy/templates/oauth2-proxy-keycloak.cfg.j2 b/roles/web-app-oauth2-proxy/templates/oauth2-proxy-keycloak.cfg.j2 index 099f3a8d..be00a741 100644 --- a/roles/web-app-oauth2-proxy/templates/oauth2-proxy-keycloak.cfg.j2 +++ b/roles/web-app-oauth2-proxy/templates/oauth2-proxy-keycloak.cfg.j2 @@ -6,17 +6,17 @@ cookie_domains = ["{{ domains | get_domain(oauth2_proxy_application_i whitelist_domains = [".{{ PRIMARY_DOMAIN }}"] # Required to allow redirection back to original requested target. # keycloak provider -client_secret = "{{ oidc.client.secret }}" -client_id = "{{ oidc.client.id }}" +client_secret = "{{ OIDC.CLIENT.SECRET }}" +client_id = "{{ OIDC.CLIENT.ID }}" redirect_url = "{{ WEB_PROTOCOL }}://{{ domains | get_domain(oauth2_proxy_application_id) }}/oauth2/callback" -oidc_issuer_url = "{{ oidc.client.issuer_url }}" +oidc_issuer_url = "{{ OIDC.CLIENT.ISSUER_URL }}" provider = "oidc" -provider_display_name = "{{ oidc.button_text }}" +provider_display_name = "{{ OIDC.BUTTON_TEXT }}" {% if applications | get_app_conf(oauth2_proxy_application_id, 'oauth2_proxy.allowed_groups', False) %} {# role based restrictions #} -scope = "openid email profile {{ oidc.claims.groups }}" -oidc_groups_claim = "{{ oidc.claims.groups }}" +scope = "openid email profile {{ OIDC.CLAIMS.GROUPS }}" +oidc_groups_claim = "{{ OIDC.CLAIMS.GROUPS }}" allowed_groups = {{ applications | get_app_conf(oauth2_proxy_application_id, 'oauth2_proxy.allowed_groups', True) | tojson }} email_domains = ["*"] {% else %} diff --git a/roles/web-app-peertube/vars/oidc-settings.yml b/roles/web-app-peertube/vars/oidc-settings.yml index 9d0adaa1..fc309e37 100644 --- a/roles/web-app-peertube/vars/oidc-settings.yml +++ b/roles/web-app-peertube/vars/oidc-settings.yml @@ -1,12 +1,12 @@ oidc_settings: | { "scope": "openid email profile", - "desk-id": "{{ oidc.client.id }}", - "discover-url": "{{ oidc.client.discovery_document }}", - "desk-secret": "{{ oidc.client.secret }}", + "desk-id": "{{ OIDC.CLIENT.ID }}", + "discover-url": "{{ OIDC.CLIENT.DISCOVERY_DOCUMENT }}", + "desk-secret": "{{ OIDC.CLIENT.SECRET }}", "mail-property": "email", - "auth-display-name": "{{ oidc.button_text }}", - "username-property": "{{ oidc.attributes.username }}", + "auth-display-name": "{{ OIDC.BUTTON_TEXT }}", + "username-property": "{{ OIDC.ATTRIBUTES.USERNAME }}", "signature-algorithm": "RS256", - "display-name-property": "{{ oidc.attributes.username }}" + "display-name-property": "{{ OIDC.ATTRIBUTES.USERNAME }}" } diff --git a/roles/web-app-pixelfed/templates/env.j2 b/roles/web-app-pixelfed/templates/env.j2 index 39d92cc5..ace99537 100644 --- a/roles/web-app-pixelfed/templates/env.j2 +++ b/roles/web-app-pixelfed/templates/env.j2 @@ -141,14 +141,14 @@ ENABLE_CONFIG_CACHE=true # @see https://github.com/pixelfed/pixelfed/commit/b3c27815788e4b47e7eb3fca727d817512cf26c2#diff-66e408190a301e81b5f1c079463487c54a6452c4944dc5ae80770f50101283ff PF_OIDC_ENABLED={{ applications | get_app_conf(application_id, 'features.oidc', False) | string | lower }} -PF_OIDC_AUTHORIZE_URL="{{oidc.client.authorize_url}}" -PF_OIDC_TOKEN_URL="{{oidc.client.token_url}}" -PF_OIDC_PROFILE_URL="{{ oidc.client.user_info_url }}" -PF_OIDC_LOGOUT_URL="{{oidc.client.logout_url}}" -PF_OIDC_USERNAME_FIELD="{{oidc.attributes.username}}" -PF_OIDC_FIELD_ID="{{oidc.attributes.username}}" -PF_OIDC_CLIENT_SECRET={{ oidc.client.secret }} -PF_OIDC_CLIENT_ID={{ oidc.client.id }} +PF_OIDC_AUTHORIZE_URL="{{ OIDC.CLIENT.AUTHORIZE_URL }}" +PF_OIDC_TOKEN_URL="{{OIDC.CLIENT.TOKEN_URL}}" +PF_OIDC_PROFILE_URL="{{ OIDC.CLIENT.USER_INFO_URL }}" +PF_OIDC_LOGOUT_URL="{{OIDC.CLIENT.LOGOUT_URL}}" +PF_OIDC_USERNAME_FIELD="{{OIDC.ATTRIBUTES.USERNAME}}" +PF_OIDC_FIELD_ID="{{OIDC.ATTRIBUTES.USERNAME}}" +PF_OIDC_CLIENT_SECRET={{ OIDC.CLIENT.SECRET }} +PF_OIDC_CLIENT_ID={{ OIDC.CLIENT.ID }} PF_OIDC_SCOPES="openid profile email" {% endif %} \ No newline at end of file diff --git a/roles/web-app-port-ui/templates/menu/applications.yml.j2 b/roles/web-app-port-ui/templates/menu/applications.yml.j2 index 363b8a62..837d73f7 100644 --- a/roles/web-app-port-ui/templates/menu/applications.yml.j2 +++ b/roles/web-app-port-ui/templates/menu/applications.yml.j2 @@ -38,13 +38,13 @@ applications: description: Update your personal admin settings icon: class: fa-solid fa-user-gear - url: {{ keycloak_url }}/realms/{{ oidc.client.id }}/account + url: {{ keycloak_url }}/realms/{{ OIDC.CLIENT.ID }}/account iframe: {{ applications | get_app_conf( 'web-app-keycloak', 'features.desktop', False) }} - name: Logout description: End your admin session securely icon: class: fa-solid fa-right-from-bracket - url: {{ keycloak_url }}/realms/{{ oidc.client.id }}/protocol/openid-connect/logout + url: {{ keycloak_url }}/realms/{{ OIDC.CLIENT.ID }}/protocol/openid-connect/logout iframe: false {% endif %} diff --git a/roles/web-app-snipe-it/tasks/ldap.yml b/roles/web-app-snipe-it/tasks/ldap.yml index ddc24b4f..ddbae533 100644 --- a/roles/web-app-snipe-it/tasks/ldap.yml +++ b/roles/web-app-snipe-it/tasks/ldap.yml @@ -36,7 +36,7 @@ $s->ad_domain = ""; $s->ldap_default_group = ""; $s->ldap_email = "{{ ldap.user.attributes.mail }}"; - $s->custom_forgot_pass_url = "{{ oidc.client.reset_credentials }}"; + $s->custom_forgot_pass_url = "{{ OIDC.CLIENT.RESET_CREDENTIALS }}"; $s->save(); EOF' args: diff --git a/roles/web-app-taiga/templates/env.j2 b/roles/web-app-taiga/templates/env.j2 index 6a2dd6c3..7c0bc164 100644 --- a/roles/web-app-taiga/templates/env.j2 +++ b/roles/web-app-taiga/templates/env.j2 @@ -54,14 +54,14 @@ ENABLE_TELEMETRY = True # OIDC via taigaio official contrib # @See https://github.com/taigaio/taiga-contrib-oidc-auth -OIDC_RP_CLIENT_ID="{{ oidc.client.id }}" -OIDC_RP_CLIENT_SECRET="{{ oidc.client.secret }}" -OIDC_OP_AUTHORIZATION_ENDPOINT="{{ oidc.client.authorize_url }}" -OIDC_OP_TOKEN_ENDPOINT="{{ oidc.client.token_url }}" -OIDC_OP_USER_ENDPOINT="{{ oidc.client.user_info_url }}" +OIDC_RP_CLIENT_ID="{{ OIDC.CLIENT.ID }}" +OIDC_RP_CLIENT_SECRET="{{ OIDC.CLIENT.SECRET }}" +OIDC_OP_AUTHORIZATION_ENDPOINT="{{ OIDC.CLIENT.AUTHORIZE_URL }}" +OIDC_OP_TOKEN_ENDPOINT="{{ OIDC.CLIENT.TOKEN_URL }}" +OIDC_OP_USER_ENDPOINT="{{ OIDC.CLIENT.USER_INFO_URL }}" OIDC_RP_SIGN_ALGO="RS256" OIDC_RP_SCOPES="openid profile email" -OIDC_OP_JWKS_ENDPOINT="{{ oidc.client.certs }}" +OIDC_OP_JWKS_ENDPOINT="{{ OIDC.CLIENT.CERTS }}" {% endif %} @@ -70,13 +70,13 @@ OIDC_OP_JWKS_ENDPOINT="{{ oidc.client.certs }}" # OIDC via robrotheram # @see https://github.com/robrotheram/taiga-contrib-openid-auth ENABLE_OPENID=True -OPENID_URL="{{oidc.client.authorize_url}}" -OPENID_USER_URL="{{oidc.client.user_info_url}}" -OPENID_TOKEN_URL="{{oidc.client.token_url}}" -OPENID_CLIENT_ID="{{ oidc.client.id }}" -OPENID_CLIENT_SECRET="{{ oidc.client.secret }}" -OPENID_NAME="{{ oidc.button_text }}" -OPENID_USERNAME_FIELD="{{oidc.attributes.username}}" +OPENID_URL="{{ OIDC.CLIENT.AUTHORIZE_URL }}" +OPENID_USER_URL="{{OIDC.CLIENT.USER_INFO_URL}}" +OPENID_TOKEN_URL="{{OIDC.CLIENT.TOKEN_URL}}" +OPENID_CLIENT_ID="{{ OIDC.CLIENT.ID }}" +OPENID_CLIENT_SECRET="{{ OIDC.CLIENT.SECRET }}" +OPENID_NAME="{{ OIDC.BUTTON_TEXT }}" +OPENID_USERNAME_FIELD="{{OIDC.ATTRIBUTES.USERNAME}}" # Optional: # OPENID_ID_FIELD="sub" # OPENID_FULLNAME_FIELD="name" diff --git a/roles/web-app-wordpress/vars/oidc.yml b/roles/web-app-wordpress/vars/oidc.yml index ac84481b..4c423db4 100644 --- a/roles/web-app-wordpress/vars/oidc.yml +++ b/roles/web-app-wordpress/vars/oidc.yml @@ -3,12 +3,12 @@ # @see https://github.com/oidc-wp/openid-connect-generic/blob/develop/includes/openid-connect-dev-option-settings.php oidc_settings: - client_id: "{{ oidc.client.id }}" # The client ID that identifies WordPress as the OIDC client. - client_secret: "{{ oidc.client.secret }}" # The secret key used by WordPress to authenticate to the OIDC provider. - endpoint_login: "{{ oidc.client.authorize_url }}" # URL of the authorization endpoint to initiate the login flow. - endpoint_token: "{{ oidc.client.token_url }}" # URL of the token endpoint for exchanging authorization codes for tokens. - endpoint_userinfo: "{{ oidc.client.user_info_url }}" # URL of the userinfo endpoint to retrieve user profile data. - endpoint_end_session: "{{ oidc.client.logout_url }}" # URL of the end-session endpoint to log users out of the IDP. + client_id: "{{ OIDC.CLIENT.ID }}" # The client ID that identifies WordPress as the OIDC client. + client_secret: "{{ OIDC.CLIENT.SECRET }}" # The secret key used by WordPress to authenticate to the OIDC provider. + endpoint_login: "{{ OIDC.CLIENT.AUTHORIZE_URL }}" # URL of the authorization endpoint to initiate the login flow. + endpoint_token: "{{ OIDC.CLIENT.TOKEN_URL }}" # URL of the token endpoint for exchanging authorization codes for tokens. + endpoint_userinfo: "{{ OIDC.CLIENT.USER_INFO_URL }}" # URL of the userinfo endpoint to retrieve user profile data. + endpoint_end_session: "{{ OIDC.CLIENT.LOGOUT_URL }}" # URL of the end-session endpoint to log users out of the IDP. login_type: "auto" # Determines how the login interface is rendered (e.g., button or form). scope: "openid profile email" # Scopes requested from the OIDC provider during authentication. create_if_does_not_exist: true # Auto-create a new WP user if one doesnโ€™t exist. @@ -16,14 +16,14 @@ oidc_settings: link_existing_users: true # Link OIDC login to existing WP users by matching email. redirect_on_logout: true # Redirect users after logout to the login screen or homepage. redirect_user_back: true # Return users to their original URL after successful login. - #acr_values: "{{ oidc.client.acr_values | default('') }}" # ACR values defining required authentication context (e.g., MFA level). + #acr_values: "{{ OIDC.CLIENT.acr_values | default('') }}" # ACR values defining required authentication context (e.g., MFA level). enable_logging: "{{ MODE_DEBUG }}" # Enable detailed plugin logging for debugging and auditing. -# log_limit: "{{ oidc.client.log_limit | default('') }}" # Maximum number of log entries to retain before pruning. +# log_limit: "{{ OIDC.CLIENT.log_limit | default('') }}" # Maximum number of log entries to retain before pruning. no_sslverify: false # The flag to enable/disable SSL verification during authorization. http_request_timeout: 5 # The timeout for requests made to the IDP. Default value is 5. - identity_key: "{{ oidc.attributes.username }}" # The key in the user claim array to find the user's identification data. - nickname_key: "{{ oidc.attributes.username }}" # The key in the user claim array to find the user's nickname. - email_format: "{{ oidc.attributes.email }}" # The key(s) in the user claim array to formulate the user's email address. - displayname_format: "{{ oidc.attributes.given_name }} {{ oidc.attributes.family_name }}" # The key(s) in the user claim array to formulate the user's display name. + identity_key: "{{ OIDC.ATTRIBUTES.USERNAME }}" # The key in the user claim array to find the user's identification data. + nickname_key: "{{ OIDC.ATTRIBUTES.USERNAME }}" # The key in the user claim array to find the user's nickname. + email_format: "{{ OIDC.ATTRIBUTES.EMAIL }}" # The key(s) in the user claim array to formulate the user's email address. + displayname_format: "{{ OIDC.ATTRIBUTES.GIVEN_NAME }} {{ OIDC.ATTRIBUTES.FAMILY_NAME }}" # The key(s) in the user claim array to formulate the user's display name. identify_with_username: true # The flag which indicates how the user's identity will be determined. state_time_limit: 180 # The valid time limit of the state, in seconds. Defaults to 180 seconds. \ No newline at end of file diff --git a/tasks/stages/01_constructor.yml b/tasks/stages/01_constructor.yml index 8157637d..d3e21f49 100644 --- a/tasks/stages/01_constructor.yml +++ b/tasks/stages/01_constructor.yml @@ -83,9 +83,9 @@ set_fact: networks: "{{ defaults_networks | combine(networks | default({}, true), recursive=True) }}" - - name: Merge oidc configuration + - name: Merge OIDC configuration set_fact: - oidc: "{{ defaults_oidc | combine(oidc | default({}, true), recursive=True) }}" + OIDC: "{{ defaults_oidc | combine(OIDC | default({}, true), recursive=True) }}" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" - name: Merge design configuration diff --git a/tests/unit/filter_plugins/test_domain_tools.py b/tests/unit/filter_plugins/test_domain_tools.py new file mode 100644 index 00000000..23878680 --- /dev/null +++ b/tests/unit/filter_plugins/test_domain_tools.py @@ -0,0 +1,49 @@ +import os +import sys +import unittest + +# Make project root importable so "filter_plugins.domain_tools" works no matter where tests run from +THIS_DIR = os.path.dirname(os.path.abspath(__file__)) +PROJECT_ROOT = os.path.abspath(os.path.join(THIS_DIR, '..', '..', '..')) +if PROJECT_ROOT not in sys.path: + sys.path.insert(0, PROJECT_ROOT) + +from ansible.errors import AnsibleFilterError # noqa: E402 +from filter_plugins.domain_tools import to_zone, FilterModule # noqa: E402 + + +class TestDomainTools(unittest.TestCase): + def test_to_zone_basic(self): + self.assertEqual(to_zone("example.com"), "example.com") + self.assertEqual(to_zone("mail.example.com"), "example.com") + self.assertEqual(to_zone("a.b.c.example.com"), "example.com") + + def test_to_zone_trailing_and_leading_dots(self): + self.assertEqual(to_zone("example.com."), "example.com") + self.assertEqual(to_zone(".mail.example.com."), "example.com") + + def test_to_zone_keeps_two_last_labels(self): + # Naive behavior by design: last two labels only + self.assertEqual(to_zone("service.co.uk"), "co.uk") + self.assertEqual(to_zone("mx.mail.service.co.uk"), "co.uk") + self.assertEqual(to_zone("uni.edu.pl"), "edu.pl") + + def test_to_zone_invalid_inputs(self): + with self.assertRaises(AnsibleFilterError): + to_zone("") # empty + with self.assertRaises(AnsibleFilterError): + to_zone(" ") # whitespace + with self.assertRaises(AnsibleFilterError): + to_zone("localhost") # no TLD part + with self.assertRaises(AnsibleFilterError): + to_zone(None) # type: ignore + + def test_filtermodule_exports(self): + fm = FilterModule() + filters = fm.filters() + self.assertIn("to_zone", filters) + self.assertIs(filters["to_zone"], to_zone) + + +if __name__ == "__main__": + unittest.main()