mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
Both mail providers published "v=DMARC1; p=reject; ruf=...; adkim=s; aspf=s" without a rua tag, so the domain owner received no aggregate reports and could not see who sends in the domain's name or whether legitimate mail fails alignment. services.<entity>.dmarc.rua_user in web-app-stalwart and web-app-mailu now names the users-catalogue key whose mailbox receives the aggregate reports. It is set to administrator, the one user every deployment provisions with a mailbox (user-administrator), and an inventory may name another key. The address is built as <username>@<mail domain>, which is the exact account or alias the provider creates, so the record never points at an address the server does not serve. An assert in the DNS task fails the deploy before any record is written when the user carries no mailbox account (Stalwart), or neither a mailbox account nor a forward alias (Mailu), so reports cannot bounce. Mailu's DMARC_RUA env, which only feeds the record its admin UI suggests, now carries the same local part instead of the unprovisioned "admin". production_facts.py takes a required --dmarc-rua. check_dmarc parses the record's tags and fails unless rua names that mailbox (size suffixes and several URIs are accepted). The policy check now reads the p tag instead of matching the substring "p=", which "sp=" also matched. Closes #1125 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
116 lines
6.5 KiB
YAML
116 lines
6.5 KiB
YAML
---
|
|
application_id: "web-app-stalwart"
|
|
http_port: "{{ lookup('config', application_id, 'services.stalwart.ports.local.http') }}"
|
|
|
|
database_password: "{{ lookup('config', application_id, 'secrets.credentials.database_password') }}" # nocheck: lookup-config-path
|
|
|
|
STALWART_VOLUMES_DIR: "{{ lookup('container', application_id, 'directories.volumes') }}"
|
|
STALWART_CONFIG_DIR: "{{ [ STALWART_VOLUMES_DIR, 'etc' ] | path_join }}"
|
|
STALWART_CONFIG_FILE: "{{ [ STALWART_CONFIG_DIR, 'config.json' ] | path_join }}"
|
|
|
|
container_port: "{{ lookup('config', application_id, 'services.stalwart.ports.internal.http') }}"
|
|
STALWART_LOCAL_BASE_URL: "http://localhost:{{ container_port }}"
|
|
STALWART_JMAP_URL: "{{ STALWART_LOCAL_BASE_URL }}/jmap/"
|
|
STALWART_LOG_DIR: "{{ lookup('volume', application_id, 'data').target }}"
|
|
STALWART_BAN_TRACER:
|
|
"@type": "Stdout"
|
|
buffered: false
|
|
level: "debug"
|
|
eventsPolicy: "include"
|
|
events:
|
|
"security.authentication-ban": true
|
|
"security.abuse-ban": true
|
|
"security.scan-ban": true
|
|
"security.loiter-ban": true
|
|
"auth.failed": true
|
|
STALWART_JMAP_APPLICATION_GET: >-
|
|
{{ {'using': ['urn:ietf:params:jmap:core', 'urn:stalwart:jmap'],
|
|
'methodCalls': [['x:Application/get', {'ids': none}, 'c0']]} | to_json }}
|
|
STALWART_JMAP_TRANSIENT_ERRORS:
|
|
- serverUnavailable
|
|
- rateLimit
|
|
STALWART_CONTAINER_ADDRESS: "{{ lookup('container_address', application_id, 'stalwart') }}"
|
|
|
|
STALWART_DOMAIN: "{{ lookup('config', application_id, 'services.stalwart.domain') }}"
|
|
STALWART_DOMAIN_DNS_ZONE: "{{ STALWART_DOMAIN | to_zone }}"
|
|
STALWART_EMAIL: "{{ lookup('email', application_id) }}"
|
|
STALWART_HOSTNAME: "{{ STALWART_EMAIL.host }}"
|
|
STALWART_WEB_DOMAIN: "{{ lookup('domain', application_id) }}"
|
|
STALWART_HOSTNAME_DNS_ZONE: "{{ STALWART_HOSTNAME | to_zone }}"
|
|
container_hostname: "{{ lookup('container_hostname', application_id) }}"
|
|
|
|
STALWART_OIDC_ONION_ISSUER: "{{ lookup('tls', 'web-app-keycloak', 'domain').endswith('.onion') }}"
|
|
STALWART_OIDC_SOCKS_PROXY: "{{ lookup('tor_socks_proxy') if STALWART_OIDC_ONION_ISSUER | bool else '' }}"
|
|
# Keycloak access tokens carry neither a Stalwart audience nor a urn:ietf:params:oauth:scope:mail scope, so the v1 defaults reject every one of them.
|
|
STALWART_OIDC_TOKEN_VALIDATION:
|
|
skipAudienceValidation: true
|
|
unscopedTokens: "interoperable"
|
|
|
|
STALWART_CONTAINER: "{{ lookup('config', application_id, 'services.stalwart.name') }}"
|
|
STALWART_DATABASE_SHARED: "{{ lookup('database', application_id, 'shared') | bool }}"
|
|
STALWART_STORE_LAYOUT_VERSION: "1"
|
|
STALWART_STORE_MARKER_FILE: "{{ [ lookup('container', application_id, 'directories.instance'), 'store.layout' ] | path_join }}"
|
|
|
|
STALWART_ANTIVIRUS_ENABLED: "{{ lookup('config', application_id, 'services.clamav.enabled') | bool }}"
|
|
STALWART_CLAMAV_HOST: "clamav"
|
|
STALWART_CLAMAV_MILTER_PORT: "{{ lookup('config', application_id, 'services.clamav.ports.internal.milter') }}"
|
|
STALWART_CLAMAV_MILTER_TIMEOUT_CONNECT_MS: 5000
|
|
STALWART_CLAMAV_MILTER_TIMEOUT_COMMAND_MS: 5000
|
|
STALWART_CLAMAV_MILTER_TIMEOUT_DATA_MS: 15000
|
|
STALWART_CLAMAV_MILTER_CONF: "{{ [ STALWART_CONFIG_DIR, 'clamav-milter.conf' ] | path_join }}"
|
|
STALWART_WEBMAIL_BASE_URL: "{{ lookup('canonical_url', application_id, 'webmail') }}"
|
|
STALWART_WEBMAIL_DOMAIN: "{{ STALWART_WEBMAIL_BASE_URL | regex_replace('^https?://', '') }}"
|
|
STALWART_WEBMAIL_HTTP_PORT: "{{ lookup('config', application_id, 'services.webmail.ports.local.http') }}"
|
|
STALWART_WEBMAIL_CONFIG_DIR: "{{ [ STALWART_VOLUMES_DIR, 'webmail' ] | path_join }}"
|
|
STALWART_WEBMAIL_OAUTH_CONFIG: "{{ [ STALWART_WEBMAIL_CONFIG_DIR, 'oauth.inc.php' ] | path_join }}"
|
|
STALWART_WEBMAIL_OIDC_CLIENT_ID: "{{ lookup('config', application_id, 'services.sso.oidc.clients.webmail') }}"
|
|
|
|
STALWART_WEBUI_VERSION: "{{ lookup('config', application_id, 'services.stalwart.webui_version') }}"
|
|
STALWART_WEBUI_RESOURCE_URL: "https://github.com/stalwartlabs/webui/releases/download/{{ STALWART_WEBUI_VERSION }}/webui.zip"
|
|
STALWART_WEBUI_CACHE_FILE: "/var/cache/infinito/core/cache/package/stalwart-webui/webui-{{ STALWART_WEBUI_VERSION }}.zip"
|
|
STALWART_WEBUI_LOCAL_FILE: "{{ [ STALWART_CONFIG_DIR, 'webui.zip' ] | path_join }}"
|
|
STALWART_WEBUI_CONTAINER_FILE: "{{ lookup('volume', application_id, 'webui_bundle').target }}"
|
|
STALWART_WEBUI_LOCAL_URL: "file://{{ STALWART_WEBUI_CONTAINER_FILE }}"
|
|
STALWART_WEBUI_APP_DESCRIPTION: "Stalwart Web Interface"
|
|
STALWART_WEBUI_OAUTH_CLIENT_ID: "{{ lookup('config', application_id, 'services.sso.oidc.clients.webui') }}"
|
|
STALWART_WEBUI_BASE_URL: "{{ lookup('canonical_url', application_id) }}"
|
|
|
|
STALWART_IP4_PUBLIC: "{{ DOCKER_PUBLIC_BIND_HOST }}"
|
|
STALWART_ACTIVE_PROVIDER: "{{ lookup('mail_provider') == application_id }}"
|
|
|
|
STALWART_ADMIN_USER: "{{ lookup('users', 'stalwartadmin').username }}"
|
|
STALWART_ADMIN_PASSWORD: "{{ lookup('users', 'stalwartadmin').password }}"
|
|
|
|
STALWART_USERS: "{{ lookup('stalwart_users') }}"
|
|
|
|
STALWART_DMARC_RUF: "{{ lookup('config', application_id, 'users.administrator.email') }}"
|
|
STALWART_DMARC_RUA_USER: "{{ lookup('config', application_id, 'services.stalwart.dmarc.rua_user') }}"
|
|
STALWART_DMARC_RUA: "{{ lookup('users', STALWART_DMARC_RUA_USER).username }}@{{ STALWART_DOMAIN }}"
|
|
|
|
STALWART_BOT_APP_PASSWORD_DESCRIPTION: "Infinito.Nexus submission"
|
|
STALWART_BOT_APP_PASSWORD_RETIRED_DESCRIPTION: "Infinito.Nexus submission, retired"
|
|
stalwart_app_password_stale: {}
|
|
STALWART_RELAY_RULE: "!is_empty(authenticated_as)"
|
|
|
|
STALWART_BAN_PERIOD_MS: "{{ (lookup('config', application_id, 'services.stalwart.ban_period_seconds') | int) * 1000 }}"
|
|
STALWART_BAN_PERIODS:
|
|
authBanPeriod: "{{ STALWART_BAN_PERIOD_MS | int }}"
|
|
abuseBanPeriod: "{{ STALWART_BAN_PERIOD_MS | int }}"
|
|
loiterBanPeriod: "{{ STALWART_BAN_PERIOD_MS | int }}"
|
|
scanBanPeriod: "{{ STALWART_BAN_PERIOD_MS | int }}"
|
|
|
|
STALWART_SSO_ENABLED: "{{ lookup('sso', application_id, 'is_enabled') | bool }}"
|
|
|
|
STALWART_IMPORT_MAILU: "{{ lookup('config', application_id, 'services.stalwart.migration.import_mailu') | bool }}"
|
|
|
|
STALWART_PRODUCTION_HOST: "{{ MAIL_PRODUCTION_HOST | trim }}"
|
|
STALWART_PRODUCTION_RESOLVER: "{{ MAIL_PRODUCTION_RESOLVER | trim }}"
|
|
STALWART_PROMETHEUS_ENABLED: "{{ lookup('config', application_id, 'services.prometheus.enabled') | bool }}"
|
|
STALWART_MAIL_FACTS_METRICS_FILE: "{{ [ DIR_METRICS_TEXTFILE, 'stalwart-mail-facts.prom' ] | path_join }}"
|
|
|
|
STALWART_ONION_ACTIVE: "{{ 'svc-net-tor' in group_names }}"
|
|
STALWART_ONION_GATEWAY_ID: "svc-net-tor-smtp"
|
|
STALWART_ONION_ROUTE_NAME: "onion"
|
|
STALWART_ONION_RELAY_HOST: "{{ lookup('config', STALWART_ONION_GATEWAY_ID, 'services.tor-smtp.name') }}"
|
|
STALWART_ONION_RELAY_PORT: "{{ lookup('config', STALWART_ONION_GATEWAY_ID, 'services.tor-smtp.ports.internal.smtp') | int }}"
|