Compare commits

...

8 Commits

Author SHA1 Message Date
3df511aee9 Changed constructor order. emails need to be defned before users 2025-08-20 18:54:44 +02:00
c27d16322b Optimized variables 2025-08-20 18:17:13 +02:00
7a6e273ea4 In between commit, updated matrix and optimized mailu 2025-08-20 17:51:17 +02:00
384beae7c1 Added task to update default email settings 2025-08-20 16:41:53 +02:00
ad7e61e8b1 Set default buffer level for proxy basic conf, which are necessary for OIDC login 2025-08-20 15:56:32 +02:00
fa46523433 Update trusted domains for matomo 2025-08-20 15:35:08 +02:00
f4a380d802 Optimized alarm and system handlers 2025-08-20 15:17:04 +02:00
42d6c1799b sys-service: add systemd_directive filter and refactor service template
Introduced custom filter plugin to render optional systemd directives, refactored template to loop over directives, and adjusted default vars (TimeoutStartSec, RuntimeMaxSec handling).

Details: see ChatGPT conversation
https://chatgpt.com/share/68a5a730-6344-800f-b9a3-dc62d5902e9b
2025-08-20 12:46:07 +02:00
36 changed files with 182 additions and 64 deletions

View File

@@ -5,4 +5,4 @@ DEFAULT_SYSTEM_EMAIL:
PORT: 465 PORT: 465
TLS: true # true for TLS and false for SSL TLS: true # true for TLS and false for SSL
START_TLS: false START_TLS: false
SMTP: true SMTP: true

View File

@@ -10,6 +10,7 @@
- docker compose up - docker compose up
- docker compose restart - docker compose restart
- docker compose just up - docker compose just up
when: MODE_ASSERT | bool
- name: docker compose pull - name: docker compose pull
shell: | shell: |

View File

@@ -0,0 +1,6 @@
# Raise the maximal header size to allow huge headers Keycloak for authentification
proxy_buffer_size 16k;
proxy_buffers 8 16k;
proxy_busy_buffers_size 16k;
client_header_buffer_size 8k;
large_client_header_buffers 8 32k;

View File

@@ -1,5 +1,4 @@
{% set location = location | default("/")%} {% set location = location | default("/")%}
location {{location}} location {{location}}
{ {
{% if oauth2_proxy_enabled | default(false) | bool %} {% if oauth2_proxy_enabled | default(false) | bool %}

View File

@@ -1,7 +1,8 @@
server server
{ {
server_name {{ domain }}; server_name {{ domain }};
{% include 'roles/srv-proxy-core/templates/headers/buffers.conf.j2' %}
{% if applications | get_app_conf(application_id, 'features.oauth2', False) %} {% if applications | get_app_conf(application_id, 'features.oauth2', False) %}
{% include 'roles/web-app-oauth2-proxy/templates/endpoint.conf.j2'%} {% include 'roles/web-app-oauth2-proxy/templates/endpoint.conf.j2'%}
{% endif %} {% endif %}

View File

@@ -6,5 +6,7 @@
- include_role: - include_role:
name: sys-service name: sys-service
vars:
# If the email notifier fails, trigger the Telegram notifier,
# passing the failing unit's name as the instance text.
system_service_tpl_on_failure: "{{ ('sys-ctl-alm-telegram@') | get_service_name(SOFTWARE_NAME, False) }}%n.service"

View File

@@ -12,6 +12,10 @@
- include_role: - include_role:
name: sys-service name: sys-service
vars:
# If the Telegram notifier fails, trigger the Email notifier,
# passing the failing unit's name as the instance text.
system_service_tpl_on_failure: "{{ ('sys-ctl-alm-email@') | get_service_name(SOFTWARE_NAME, False) }}%n.service"
- name: install curl - name: install curl
community.general.pacman: community.general.pacman:

View File

@@ -15,4 +15,4 @@ fi
/usr/bin/curl -s -X POST \ /usr/bin/curl -s -X POST \
"https://api.telegram.org/bot{{ telegram_bot_token }}/sendMessage" \ "https://api.telegram.org/bot{{ telegram_bot_token }}/sendMessage" \
-d chat_id="{{ telegram_chat_id }}" \ -d chat_id="{{ telegram_chat_id }}" \
--data-urlencode text="service ${friendly} on ${host} failed" --data-urlencode text="service ${friendly//\//-} on ${host} failed"

View File

View File

@@ -1,3 +1,3 @@
SYS_SERVICE_ALL_ENABLED: "{{ not MODE_DEBUG }}" SYS_SERVICE_ALL_ENABLED: "{{ MODE_DEBUG }}"
SYS_SERVICE_DEFAULT_STATE: "{{ 'restarted' if MODE_DEBUG else omit }}" SYS_SERVICE_DEFAULT_STATE: "{{ 'restarted' if MODE_DEBUG else omit }}"
SYS_SERVICE_DEFAULT_RUNTIME: "86400s" # Maximum total runtime a service is allowed to run before being stopped SYS_SERVICE_DEFAULT_RUNTIME: "86400s" # Maximum total runtime a service is allowed to run before being stopped

View File

@@ -0,0 +1,17 @@
def systemd_directive(value, key: str) -> str:
"""
Render a single systemd directive line if value is non-empty.
Example: {{ myval | systemd_directive('ExecStart') }}
"""
if value is None:
return ""
sval = str(value).strip()
if not sval:
return ""
return f"{key}={sval}"
class FilterModule(object):
def filters(self):
return {
"systemd_directive": systemd_directive,
}

View File

@@ -42,3 +42,4 @@
notify: refresh systemctl service notify: refresh systemctl service
when: not system_service_uses_at when: not system_service_uses_at
when: SYS_SERVICE_ALL_ENABLED | bool when: SYS_SERVICE_ALL_ENABLED | bool

View File

@@ -1,3 +1,9 @@
- name: "Reload sys-daemon handlers"
include_tasks: "{{ playbook_dir }}/tasks/utils/load_handlers.yml"
vars:
handler_role_name: "sys-daemon"
when: run_once_sys_service is defined
- block: - block:
- include_tasks: 01_core.yml - include_tasks: 01_core.yml
- include_tasks: utils/run_once.yml - include_tasks: utils/run_once.yml
@@ -7,6 +13,6 @@
block: block:
- name: "Load base routine for '{{ system_service_id }}'" - name: "Load base routine for '{{ system_service_id }}'"
include_tasks: 03_base.yml include_tasks: 03_base.yml
- name: "Flush system handlers for '{{ system_service_id }}'" - name: "Flush system service handlers for '{{ system_service_id }}'"
meta: flush_handlers meta: flush_handlers
when: system_service_id is defined when: system_service_id is defined

View File

@@ -1,15 +1,17 @@
[Unit] [Unit]
Description={{ SOFTWARE_NAME }} - Service for role '{{ system_service_id }}' Description={{ SOFTWARE_NAME }} - Service for role '{{ system_service_id }}'
{% if system_service_tpl_on_failure |length > 0 %} {{- system_service_tpl_on_failure | systemd_directive('OnFailure') }}
OnFailure={{ system_service_tpl_on_failure }} StartLimitIntervalSec=60
{% endif %} StartLimitBurst=3
OnFailureJobMode=replace-irreversibly
[Service] [Service]
Type={{ system_service_tpl_type }} Type={{ system_service_tpl_type }}
{% if system_service_tpl_exec_start_pre |length > 0 %} {% for key, val in [
ExecStartPre={{ system_service_tpl_exec_start_pre }} ('TimeoutStartSec', system_service_tpl_timeout_start_sec),
{% endif %} ('ExecStartPre', system_service_tpl_exec_start_pre),
ExecStart={{ system_service_tpl_exec_start }} ('ExecStart', system_service_tpl_exec_start),
{% if system_service_tpl_runtime |length > 0 %} ('RuntimeMaxSec', system_service_tpl_runtime)
RuntimeMaxSec={{ system_service_tpl_runtime }} ] %}
{% endif %} {{ val | systemd_directive(key) }}
{% endfor %}

View File

@@ -17,8 +17,9 @@ system_service_script_inter: "/bin/{{ 'bash' if system_service_script_type ==
system_service_script_exec: "{{ system_service_script_inter }} {{ system_service_id | get_service_script_path( system_service_script_type ) }}" system_service_script_exec: "{{ system_service_script_inter }} {{ system_service_id | get_service_script_path( system_service_script_type ) }}"
# Service template # Service template
system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}" system_service_tpl_on_failure: "{{ SYS_SERVICE_ON_FAILURE_COMPOSE }}"
system_service_tpl_type: "oneshot" system_service_tpl_type: "oneshot"
system_service_tpl_exec_start: "{{ system_service_script_exec }}" system_service_tpl_exec_start: "{{ system_service_script_exec }}"
system_service_tpl_runtime: "{{ SYS_SERVICE_DEFAULT_RUNTIME }}" system_service_tpl_runtime: "{{ '' if system_service_tpl_type == 'oneshot' else SYS_SERVICE_DEFAULT_RUNTIME }}"
system_service_tpl_exec_start_pre: "" system_service_tpl_exec_start_pre: ""
system_service_tpl_timeout_start_sec: "60s"

View File

@@ -4,4 +4,4 @@
- name: Prune Docker resources - name: Prune Docker resources
become: true become: true
ansible.builtin.command: docker system prune -f ansible.builtin.command: docker system prune -f

View File

@@ -58,6 +58,24 @@
}} }}
include_tasks: _update.yml include_tasks: _update.yml
- name: "Update REALM mail settings"
include_tasks: _update.yml
vars:
kc_object_kind: "realm"
kc_lookup_field: "id"
kc_lookup_value: "{{ KEYCLOAK_REALM }}"
kc_desired:
smtpServer:
from: "no-reply@{{ DEFAULT_SYSTEM_EMAIL.DOMAIN }}"
fromDisplayName: "{{ SOFTWARE_NAME | default('Infinito.Nexus') }}"
host: "{{ DEFAULT_SYSTEM_EMAIL.HOST }}"
port: "{{ DEFAULT_SYSTEM_EMAIL.PORT }}"
# Keycloak expects strings "true"/"false"
ssl: "{{ 'true' if not DEFAULT_SYSTEM_EMAIL.START_TLS and DEFAULT_SYSTEM_EMAIL.TLS else 'false' }}"
starttls: "{{ 'true' if DEFAULT_SYSTEM_EMAIL.START_TLS else 'false' }}"
user: "{{ DEFAULT_SYSTEM_EMAIL.USER | default('') }}"
password: "{{ DEFAULT_SYSTEM_EMAIL.PASSWORD | default('') }}"
- include_tasks: 05_rbac_client_scope.yml - include_tasks: 05_rbac_client_scope.yml
- include_tasks: 06_ldap.yml - include_tasks: 06_ldap.yml

View File

@@ -1452,7 +1452,7 @@
"replyTo": "", "replyTo": "",
"host": "{{ SYSTEM_EMAIL.HOST }}", "host": "{{ SYSTEM_EMAIL.HOST }}",
"from": "{{ users['no-reply'].email }}", "from": "{{ users['no-reply'].email }}",
"fromDisplayName": "Keycloak Authentification System - {{domains | get_domain('web-app-keycloak')}}", "fromDisplayName": "Keycloak Authentification System - {{ KEYCLOAK_DOMAIN | upper }}",
"envelopeFrom": "", "envelopeFrom": "",
"ssl": "true", "ssl": "true",
"user": "{{ users['no-reply'].email }}" "user": "{{ users['no-reply'].email }}"

View File

@@ -12,9 +12,10 @@ KEYCLOAK_DEBUG_ENABLED: "{{ MODE_DEBUG }}"
KEYCLOAK_CLIENT_ID: "{{ OIDC.CLIENT.ID }}" KEYCLOAK_CLIENT_ID: "{{ OIDC.CLIENT.ID }}"
KEYCLOAK_SERVER_INTERNAL_URL: "http://127.0.0.1:8080" KEYCLOAK_SERVER_INTERNAL_URL: "http://127.0.0.1:8080"
KEYCLOAK_LOAD_DEPENDENCIES: "{{ applications | get_app_conf(application_id, 'load_dependencies') }}" KEYCLOAK_LOAD_DEPENDENCIES: "{{ applications | get_app_conf(application_id, 'load_dependencies') }}"
KEYCLOAK_DOMAIN: "{{ domains | get_domain('web-app-keycloak') }}"
# RBAC # RBAC
KEYCLOAK_RBAC_GROUP_CLAIM: "{{ RBAC.GROUP.CLAIM }}" KEYCLOAK_RBAC_GROUP_CLAIM: "{{ RBAC.GROUP.CLAIM }}"
KEYCLOAK_RBAC_GROUP_NAME: "{{ RBAC.GROUP.NAME }}" KEYCLOAK_RBAC_GROUP_NAME: "{{ RBAC.GROUP.NAME }}"
## Health ## Health

View File

@@ -8,6 +8,21 @@
success_msg: "MAILU_HOSTNAMES is valid." success_msg: "MAILU_HOSTNAMES is valid."
when: MODE_ASSERT | bool when: MODE_ASSERT | bool
- name: "load variables from {{ DOCKER_VARS_FILE }}"
include_vars: "{{ DOCKER_VARS_FILE }}"
- name: Ensure Rspamd overrides directory exists (host)
file:
path: "{{ MAILU_RSPAMD_HOST_DIR }}"
state: directory
mode: "0755"
- name: Render ratelimit.conf
template:
src: ratelimit.conf.j2
dest: "{{ MAILU_RSPAMD_HOST_FILE }}"
mode: "0644"
- name: "Mailu Docker and Webserver Setup" - name: "Mailu Docker and Webserver Setup"
block: block:
- name: "load docker, db and proxy for {{ application_id }}" - name: "load docker, db and proxy for {{ application_id }}"

View File

@@ -97,7 +97,7 @@
volumes: volumes:
- "filter:/var/lib/rspamd" - "filter:/var/lib/rspamd"
- "dkim:/dkim" - "dkim:/dkim"
- "{{ docker_compose.directories.volumes }}overrides/rspamd:/overrides:ro" - "{{ MAILU_RSPAMD_HOST_DIR }}:/overrides:ro"
depends_on: depends_on:
- front - front
- redis - redis

View File

@@ -0,0 +1,24 @@
# AUTOGENERATED by Ansible Rspamd ratelimits
# Mount path in container: /overrides/ratelimit.conf (read-only)
rates {
{# Optional global defaults for authenticated SMTP senders #}
authenticated = {
bucket = [{
burst = {{ MAILU_RSPAMD_LIMITS_DEFAULTS.BURST | int }};
rate = "{{ MAILU_RSPAMD_LIMITS_DEFAULTS.RATE }}";
}];
}
{# Per-user limits: require both .limits.rate and .limits.burst #}
{% for uname, u in users.items() %}
{% if (u.limits.rate | default(false) and u.limits.burst | default(false)) %}
"user={{ u.email }}" = {
bucket = [{
burst = {{ u.limits.burst | int }};
rate = "{{ u.limits.rate }}";
}];
};
{% endif %}
{% endfor %}
}

View File

@@ -58,3 +58,10 @@ MAILU_DMARC_RUF: "{{ applications | get_app_conf(applicatio
MAILU_DKIM_KEY_FILE: "{{ MAILU_DOMAIN }}.dkim.key" MAILU_DKIM_KEY_FILE: "{{ MAILU_DOMAIN }}.dkim.key"
MAILU_DKIM_KEY_PATH: "/dkim/{{ MAILU_DKIM_KEY_FILE }}" MAILU_DKIM_KEY_PATH: "/dkim/{{ MAILU_DKIM_KEY_FILE }}"
## Rspamd
MAILU_RSPAMD_HOST_DIR: "{{ [ docker_compose.directories.volumes, 'overrides/rspamd' ] | path_join }}"
MAILU_RSPAMD_HOST_FILE: "{{ [ MAILU_RSPAMD_HOST_DIR,'ratelimit.conf' ] | path_join }}"
MAILU_RSPAMD_LIMITS_DEFAULTS:
RATE: "30 / 1min"
BURST: 50

View File

@@ -2,8 +2,8 @@
include_role: include_role:
name: cmp-db-docker-proxy name: cmp-db-docker-proxy
- name: "Patch Matomo config.ini.php with updated DB credentials" - name: "Patch Matomo config.ini.php"
include_tasks: database.yml include_tasks: 02_configuration.yml
- name: flush docker service - name: flush docker service
meta: flush_handlers meta: flush_handlers

View File

@@ -18,3 +18,8 @@
docker exec --user root {{ matomo_name }} docker exec --user root {{ matomo_name }}
sed -i "s/^password *=.*/password = {{ database_password }}/" {{ matomo_config }} sed -i "s/^password *=.*/password = {{ database_password }}/" {{ matomo_config }}
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: Update trusted host
command: >
docker exec --user root {{ matomo_name }}
sed -i "s|^trusted_hosts\[\].*|trusted_hosts[] = \"{{ domain }}\"|" {{ matomo_config }}

View File

@@ -1,6 +1,6 @@
--- ---
- name: "construct {{ role_name }}" - name: "construct {{ role_name }}"
include_tasks: constructor.yml include_tasks: 01_core.yml
when: run_once_web_app_matomo is not defined when: run_once_web_app_matomo is not defined
- name: run the docker matomo tasks once - name: run the docker matomo tasks once

View File

@@ -5,9 +5,10 @@
"server_name": "{{ MATRIX_SYNAPSE_DOMAIN }}" "server_name": "{{ MATRIX_SYNAPSE_DOMAIN }}"
}, },
"m.identity_server": { "m.identity_server": {
"base_url": "{{ WEB_PROTOCOL }}://{{ PRIMARY_DOMAIN }}" "base_url": "{{ MATRIX_BASE_URL }}"
} }
}, },
"logout_redirect_url": "{{ OIDC.CLIENT.LOGOUT_URL if MATRIX_OIDC_ENABLED else MATRIX_BASE_URL }}",
"brand": "Element", "brand": "Element",
"integrations_ui_url": "https://scalar.vector.im/", "integrations_ui_url": "https://scalar.vector.im/",
"integrations_rest_url": "https://scalar.vector.im/api", "integrations_rest_url": "https://scalar.vector.im/api",

View File

@@ -3,8 +3,8 @@ server {
{% include 'roles/srv-letsencrypt/templates/ssl_header.j2' %} {% include 'roles/srv-letsencrypt/templates/ssl_header.j2' %}
# For the federation port # For the federation port
listen {{ FEDERATION_PORT }} ssl default_server; listen {{ MATRIX_FEDERATION_PORT }} ssl default_server;
listen [::]:{{ FEDERATION_PORT }} ssl default_server; listen [::]:{{ MATRIX_FEDERATION_PORT }} ssl default_server;
{% include 'roles/sys-srv-web-inj-compose/templates/server.conf.j2'%} {% include 'roles/sys-srv-web-inj-compose/templates/server.conf.j2'%}

View File

@@ -17,7 +17,9 @@ MATRIX_WELL_KNOWN_FILE: "{{ MATRIX_WELL_KNOWN_DIRECTORY }}server"
MATRIX_PROJECT: "{{ application_id | get_entity_name }}" MATRIX_PROJECT: "{{ application_id | get_entity_name }}"
MATRIX_REGISTRATION_FILE_FOLDER: "/data/" MATRIX_REGISTRATION_FILE_FOLDER: "/data/"
MATRIX_REGISTRATION_SHARED_SECRET: "{{ applications | get_app_conf(application_id, 'credentials.registration_shared_secret') }}" MATRIX_REGISTRATION_SHARED_SECRET: "{{ applications | get_app_conf(application_id, 'credentials.registration_shared_secret') }}"
FEDERATION_PORT: "{{ ports.public.federation['web-app-matrix_synapse'] }}" MATRIX_FEDERATION_PORT: "{{ ports.public.federation['web-app-matrix_synapse'] }}"
MATRIX_OIDC_ENABLED: "{{ applications | get_app_conf(application_id, 'features.oidc', False) }}"
MATRIX_BASE_URL: "{{ WEB_PROTOCOL }}://{{ PRIMARY_DOMAIN }}"
## Synapse ## Synapse
MATRIX_SYNAPSE_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.synapse.version') }}" MATRIX_SYNAPSE_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.synapse.version') }}"
@@ -38,4 +40,4 @@ MATRIX_ELEMENT_IMAGE: "{{ applications | get_app_conf(applicatio
MATRIX_ELEMENT_NAME: "{{ applications | get_app_conf(application_id, 'docker.services.element.name') }}" MATRIX_ELEMENT_NAME: "{{ applications | get_app_conf(application_id, 'docker.services.element.name') }}"
MATRIX_ELEMENT_DOMAIN: "{{ domains[application_id].element }}" MATRIX_ELEMENT_DOMAIN: "{{ domains[application_id].element }}"
MATRIX_ELEMENT_PORT: "{{ ports.localhost.http['web-app-matrix_element'] }}" MATRIX_ELEMENT_PORT: "{{ ports.localhost.http['web-app-matrix_element'] }}"
MATRIX_ELEMENT_CONFIG_PATH_HOST: "{{ docker_compose.directories.config }}element-config.json" MATRIX_ELEMENT_CONFIG_PATH_HOST: "{{ docker_compose.directories.config }}element-config.json"

View File

@@ -1,5 +1,3 @@
{# This is the nginx configuration file for the proxy server #}
server server
{ {
server_name {{ domain }}; server_name {{ domain }};

View File

@@ -1,7 +1,17 @@
users: users:
administrator: administrator:
username: "administrator" username: "administrator"
no-reply: no-reply:
username: "no-reply" username: "no-reply"
roles: roles:
- mail-bot - mail-bot
limits:
rate: "60 / 1min"
burst: 3600
test12345:
username: "treset12345"
roles:
- mail-bot
limits:
rate: "60 / 1min"
burst: 3600

View File

@@ -5,7 +5,7 @@
command: --config /oauth2-proxy.cfg command: --config /oauth2-proxy.cfg
hostname: oauth2-proxy hostname: oauth2-proxy
ports: ports:
- {{ports.localhost.oauth2_proxy[application_id]}}:4180/tcp - {{ ports.localhost.oauth2_proxy[application_id] }}:4180/tcp
volumes: volumes:
- "{{ docker_compose.directories.volumes }}{{applications | get_app_conf('web-app-oauth2-proxy','configuration_file')}}:/oauth2-proxy.cfg" - "{{ docker_compose.directories.volumes }}{{applications | get_app_conf('web-app-oauth2-proxy','configuration_file')}}:/oauth2-proxy.cfg"
{% endif %} {% endif %}

View File

@@ -1,16 +1,8 @@
{# Include OAuth2 Proxy #} # OAuth2-Proxy-Endpoint
{# Raise the maximal header size. #} location /oauth2/ {
{# Keycloak uses huge headers for authentification #} proxy_pass http://127.0.0.1:{{ ports.localhost.oauth2_proxy[application_id] }};
proxy_buffer_size 16k; proxy_set_header Host $host;
proxy_buffers 8 16k; proxy_set_header X-Real-IP $remote_addr;
proxy_busy_buffers_size 16k; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
large_client_header_buffers 4 16k; proxy_set_header X-Forwarded-Proto $scheme;
}
# OAuth2-Proxy-Endpoint
location /oauth2/ {
proxy_pass http://127.0.0.1:{{ports.localhost.oauth2_proxy[application_id]}};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}

View File

@@ -1,6 +1,8 @@
server server
{ {
server_name {{ domain }}; server_name {{ domain }};
{# Include buffers for OIDC #}
{% include 'roles/srv-proxy-core/templates/headers/buffers.conf.j2' %}
{% if applications | get_app_conf(application_id, 'features.oauth2', False) %} {% if applications | get_app_conf(application_id, 'features.oauth2', False) %}
{% include 'roles/web-app-oauth2-proxy/templates/endpoint.conf.j2'%} {% include 'roles/web-app-oauth2-proxy/templates/endpoint.conf.j2'%}

View File

@@ -4,6 +4,11 @@
msg: "{{ allowed_applications }}" msg: "{{ allowed_applications }}"
when: MODE_DEBUG | bool when: MODE_DEBUG | bool
- name: Merge system_email definitions
set_fact:
SYSTEM_EMAIL: "{{ DEFAULT_SYSTEM_EMAIL | combine(system_email | default({}, true), recursive=True) }}"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: Merge variables - name: Merge variables
block: block:
- name: Merge users - name: Merge users
@@ -11,11 +16,6 @@
users: "{{ default_users | combine(users| default({}), recursive=True) }}" users: "{{ default_users | combine(users| default({}), recursive=True) }}"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}" no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: Merge system_email definitions
set_fact:
SYSTEM_EMAIL: "{{ DEFAULT_SYSTEM_EMAIL | combine(system_email | default({}, true), recursive=True) }}"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: Merge application definitions - name: Merge application definitions
set_fact: set_fact:
applications: "{{ defaults_applications | merge_with_defaults(applications | default({}, true)) }}" applications: "{{ defaults_applications | merge_with_defaults(applications | default({}, true)) }}"

View File

@@ -4,4 +4,7 @@ users:
username: demo username: demo
email: "demo@{{ PRIMARY_DOMAIN }}" email: "demo@{{ PRIMARY_DOMAIN }}"
roles: [] roles: []
description: Demo User description: Demo User
limits:
rate: "60 / 1min" # token fill rate (N per window)
burst: 3600 # max immediate tokens