From 963807558065fcd55b484e3162fc5ffad2cdde43 Mon Sep 17 00:00:00 2001 From: Viyurz Date: Sat, 6 Apr 2024 21:43:34 +0200 Subject: [PATCH] Stalwart mail: Migrate to PostgreSQL & LLDAP. --- env.yml | 2 +- roles/mailserver/tasks/backup.yml | 43 ++++++++++--------- roles/mailserver/tasks/update.yml | 16 ++++--- roles/mailserver/templates/common-server.toml | 10 +++++ roles/mailserver/templates/common-tls.toml | 10 +++++ .../mailserver/templates/common-tracing.toml | 3 ++ .../mailserver/templates/directory-ldap.toml | 28 ++++++++++++ .../mailserver/templates/docker-compose.yaml | 12 ++++++ roles/mailserver/templates/smtp-listener.toml | 9 ++++ .../templates/store-postgresql.toml | 17 ++++++++ secrets.yml.example | 6 +++ 11 files changed, 129 insertions(+), 27 deletions(-) create mode 100644 roles/mailserver/templates/common-server.toml create mode 100644 roles/mailserver/templates/common-tls.toml create mode 100644 roles/mailserver/templates/common-tracing.toml create mode 100644 roles/mailserver/templates/directory-ldap.toml create mode 100644 roles/mailserver/templates/smtp-listener.toml create mode 100644 roles/mailserver/templates/store-postgresql.toml diff --git a/env.yml b/env.yml index c5068e9..4a428d8 100644 --- a/env.yml +++ b/env.yml @@ -115,7 +115,7 @@ users: hedgedoc: 1004 homepage: 8686 lldap: 1007 - mailserver: 8 + mailserver: 8 # Do not change postgres: 70 searxng: 977 searxng_redis: 999 diff --git a/roles/mailserver/tasks/backup.yml b/roles/mailserver/tasks/backup.yml index ae28954..a36a2eb 100644 --- a/roles/mailserver/tasks/backup.yml +++ b/roles/mailserver/tasks/backup.yml @@ -1,22 +1,25 @@ -- name: +- name: "Backup PostgreSQL stalwart database & {{ volumes['mailserver_datadir'] }} directory" + shell: > + docker exec postgres + pg_dump -c {{ role_name }} | + borg create + --compression lzma + "{{ borg_repodir }}::{{ role_name }}-{now:%Y-%m-%d_%H-%M-%S}" + "{{ volumes['mailserver_datadir'] }}" + - + --stdin-name dump_{{ role_name }}.sql + environment: + DOCKER_HOST: "{{ docker_host }}" + BORG_PASSCOMMAND: "cat {{ borg_passphrase_file }}" become: true - block: - - name: Create borg backup - command: - cmd: | - borg create - --compression=lzma - "{{ borg_repodir }}::{{ role_name }}-{now:%Y-%m-%d_%H-%M-%S}" - {{ volumes['mailserver_datadir'] }} - environment: - BORG_PASSCOMMAND: "cat {{ borg_passphrase_file }}" - - name: Prune borg repository - command: - cmd: | - borg prune - --glob-archives='{{ role_name }}-*' - {{ borg_prune_options }} - {{ borg_repodir }} - environment: - BORG_PASSCOMMAND: "cat {{ borg_passphrase_file }}" +- name: Prune borg repository + command: + cmd: | + borg prune + --glob-archives='{{ role_name }}-*' + {{ borg_prune_options }} + {{ borg_repodir }} + environment: + BORG_PASSCOMMAND: "cat {{ borg_passphrase_file }}" + become: true diff --git a/roles/mailserver/tasks/update.yml b/roles/mailserver/tasks/update.yml index 1a84283..42bc1aa 100644 --- a/roles/mailserver/tasks/update.yml +++ b/roles/mailserver/tasks/update.yml @@ -3,21 +3,24 @@ path: "{{ project_dir }}" state: directory -- name: Template docker-compose.yaml to project directory +- name: Template configuration files to project directory template: - src: docker-compose.yaml - dest: "{{ project_dir }}/docker-compose.yaml" + src: "{{ item.src }}" + dest: "{{ project_dir }}/{{ item.path }}" owner: "{{ host_uid }}" - group: "{{ host_uid }}" + group: "{{ users['mailserver'] + uid_shift }}" mode: '640' + with_filetree: ../templates/ + when: item.state == 'file' + become: true -- name: "Create directory {{ volumes['mailserver_datadir'] }} with correct permissions" +- name: "Create (if not exists) directory {{ volumes['mailserver_datadir'] }} & set permissions" file: path: "{{ volumes['mailserver_datadir'] }}" state: directory owner: "{{ users['mailserver'] + uid_shift }}" group: "{{ users['mailserver'] + uid_shift }}" - mode: '770' + mode: '700' become: true - name: Set limited permissions on certificate directories @@ -76,3 +79,4 @@ - name: Create/Restart project services community.docker.docker_compose: project_src: "{{ project_dir }}" + restarted: true diff --git a/roles/mailserver/templates/common-server.toml b/roles/mailserver/templates/common-server.toml new file mode 100644 index 0000000..4e55ded --- /dev/null +++ b/roles/mailserver/templates/common-server.toml @@ -0,0 +1,10 @@ +[server] +hostname = "%{HOST}%" +max-connections = 8192 + +[server.security] +fail2ban = "100/1d" + +[server.run-as] +user = "mail" +group = "mail" diff --git a/roles/mailserver/templates/common-tls.toml b/roles/mailserver/templates/common-tls.toml new file mode 100644 index 0000000..03913b1 --- /dev/null +++ b/roles/mailserver/templates/common-tls.toml @@ -0,0 +1,10 @@ +[server.tls] +enable = true +implicit = true +timeout = "1m" +certificate = "default" +ignore-client-order = true + +[certificate."default"] +cert = "file:///etc/fullchain.pem" +private-key = "file:///etc/privkey.pem" diff --git a/roles/mailserver/templates/common-tracing.toml b/roles/mailserver/templates/common-tracing.toml new file mode 100644 index 0000000..3b43356 --- /dev/null +++ b/roles/mailserver/templates/common-tracing.toml @@ -0,0 +1,3 @@ +[global.tracing] +method = "stdout" +level = "debug" diff --git a/roles/mailserver/templates/directory-ldap.toml b/roles/mailserver/templates/directory-ldap.toml new file mode 100644 index 0000000..40b0eed --- /dev/null +++ b/roles/mailserver/templates/directory-ldap.toml @@ -0,0 +1,28 @@ +[directory."ldap"] +type = "ldap" +address = "ldap://lldap:3890" +base-dn = "{{ ldap_base_dn }}" +timeout = "30s" +tls.enable = false + +[directory."ldap".bind] +dn = "{{ mailserver_secrets['ldap_user'] }}" +secret = "{{ mailserver_secrets['ldap_password'] }}" + +[directory."ldap".bind.auth] +enable = true +dn = "uid=?,ou=people,{{ ldap_base_dn }}" + +[directory."ldap".filter] +name = "(&(|(objectClass=person)(objectClass=posixGroup))(uid=?))" +email = "(&(|(objectClass=person)(objectClass=posixGroup))(|(mail=?)(mailAlias=?)(mailList=?))(mail=*@{{ domain }}))" +verify = "(&(|(objectClass=person)(objectClass=posixGroup))(|(mail=*?*)(mailAlias=*?*)))" +expand = "(&(|(objectClass=person)(objectClass=posixGroup))(mailList=?))" +domains = "(&(|(objectClass=person)(objectClass=posixGroup))(|(mail=*@?)(mailAlias=*@?)))" + +[directory."ldap".attributes] +name = "uid" +type = "objectClass" +description = ["distinguishedName"] +email = "mail" +email-alias = "mailAlias" diff --git a/roles/mailserver/templates/docker-compose.yaml b/roles/mailserver/templates/docker-compose.yaml index a61eb96..7595cd0 100644 --- a/roles/mailserver/templates/docker-compose.yaml +++ b/roles/mailserver/templates/docker-compose.yaml @@ -3,6 +3,8 @@ services: image: docker.io/stalwartlabs/mail-server:v0.6.0 container_name: mailserver restart: always + networks: + - mailserver ports: - "{{ ports['mailserver_smtp'] }}:25" - {{ ports['mailserver_smtps'] }}:465 @@ -12,3 +14,13 @@ services: - {{ volumes['mailserver_tls_certificate_file'] }}:/etc/fullchain.pem - {{ volumes['mailserver_tls_certificate_key_file'] }}:/etc/privkey.pem - {{ volumes['mailserver_datadir' ] }}:/opt/stalwart-mail + - ./common-server.toml:/opt/stalwart-mail/etc/common/server.toml + - ./common-tls.toml:/opt/stalwart-mail/etc/common/tls.toml + - ./common-tracing.toml:/opt/stalwart-mail/etc/common/tracing.toml + - ./directory-ldap.toml:/opt/stalwart-mail/etc/directory/ldap.toml + - ./store-postgresql.toml:/opt/stalwart-mail/etc/store/postgresql.toml + - ./smtp-listener.toml:/opt/stalwart-mail/etc/smtp/listener.toml + +networks: + mailserver: + name: mailserver diff --git a/roles/mailserver/templates/smtp-listener.toml b/roles/mailserver/templates/smtp-listener.toml new file mode 100644 index 0000000..951c9be --- /dev/null +++ b/roles/mailserver/templates/smtp-listener.toml @@ -0,0 +1,9 @@ +[server.listener."smtp"] +bind = ["[::]:25"] +protocol = "smtp" +tls.implicit = false + +[server.listener."submissions"] +bind = ["[::]:465"] +protocol = "smtp" +tls.implicit = true diff --git a/roles/mailserver/templates/store-postgresql.toml b/roles/mailserver/templates/store-postgresql.toml new file mode 100644 index 0000000..8ad0405 --- /dev/null +++ b/roles/mailserver/templates/store-postgresql.toml @@ -0,0 +1,17 @@ +[store."postgresql"] +type = "postgresql" +host = "postgres.{{ domain }}" +port = 5432 +database = "stalwart" +user = "{{ mailserver_secrets['postgres_user'] }}" +password = "{{ mailserver_secrets['postgres_password'] }}" + +[store."postgresql".timeout] +connect = "15s" + +[store."postgresql".tls] +enable = false +allow-invalid-certs = false + +[store."postgresql".purge] +frequency = "0 3 *" diff --git a/secrets.yml.example b/secrets.yml.example index ba5b80b..3dfbb73 100644 --- a/secrets.yml.example +++ b/secrets.yml.example @@ -35,6 +35,12 @@ lldap_secrets: postgres_user: postgres_password: +mailserver_secrets: + ldap_user: + ldap_password: + postgres_user: + postgres_password: + searxng_secrets: searxng_secret: