diff --git a/host_vars/emma.ccchb.de b/host_vars/emma.ccchb.de index 9032aba..38aae46 100644 --- a/host_vars/emma.ccchb.de +++ b/host_vars/emma.ccchb.de @@ -1,4 +1,6 @@ --- +dovecot_listen: '[2a01:4f8:150:926f::2], 176.9.59.104' + haproxy_v4: 176.9.59.104 haproxy_v6: 2a01:4f8:150:926f::2 diff --git a/roles/dovecot/handlers/main.yml b/roles/dovecot/handlers/main.yml new file mode 100644 index 0000000..f28cc64 --- /dev/null +++ b/roles/dovecot/handlers/main.yml @@ -0,0 +1,14 @@ +--- +- name: Reload s6-rc + service: + name: s6-rc + state: reloaded + +- name: Reload Dovecot + command: s6-svc -h /run/service/dovecot + +- name: Restart Dovecot + command: s6-svc -wR -T 5000 /run/service/dovecot + +- name: Restart Dovecot log + command: s6-svc -wR -T 5000 /run/service/dovecot-log diff --git a/roles/dovecot/tasks/main.yml b/roles/dovecot/tasks/main.yml new file mode 100644 index 0000000..ae68193 --- /dev/null +++ b/roles/dovecot/tasks/main.yml @@ -0,0 +1,161 @@ +--- +- name: Install Dovecot + package: + name: dovecot dovecot-fts-xapian dovecot-pigeonhole + state: present + +- name: Set permissions on /usr/local/etc/dovecot + file: + path: /usr/local/etc/dovecot + state: directory + owner: acme + group: dovecot + mode: 0750 + +- name: Generate DH parameters + command: openssl dhparam -out /usr/local/etc/dovecot/dh.pem 2048 + args: + creates: /usr/local/etc/dovecot/dh.pem + +- name: Add vmail group + group: + name: vmail + gid: 20002 + +- name: Add vmail user + user: + name: vmail + uid: 20002 + group: vmail + home: /var/empty + create_home: no + login_class: daemon + password: '*' + +- name: Add vmail ZFS file system + zfs: + name: '{{ bhyve_pool }}/var/vmail' + state: present + +- name: Set permissions on /var/vmail + file: + path: /var/vmail + state: directory + owner: vmail + group: vmail + mode: 0750 + +- name: Create /var/spool/postfix + file: + path: /var/spool/postfix + state: directory + owner: root + group: wheel + mode: 0755 + +- name: Add /var/log/dovecot to fstab + mount: + path: /var/log/dovecot + src: tmpfs + fstype: tmpfs + opts: 'rw,size={{ dovecot_log_size }},mode={{ dovecot_log_mode }},uid={{ dovecot_log_uid }},gid={{ dovecot_log_gid }},late' + state: mounted + +- name: Create Dovecot service directories + file: + path: '/etc/s6-rc/service/{{ item }}' + state: directory + owner: root + group: wheel + mode: 0755 + with_items: '{{ dovecot_service_dirs }}' + notify: + - Reload s6-rc + - Restart Dovecot log + - Restart Dovecot + +- name: Generate Dovecot service scripts + template: + dest: '/etc/s6-rc/service/{{ item }}' + src: '{{ item }}.j2' + mode: 0555 + owner: root + group: wheel + with_items: '{{ dovecot_service_scripts }}' + notify: + - Reload s6-rc + - Restart Dovecot log + - Restart Dovecot + +- name: Generate Dovecot service configuration + copy: + dest: '/etc/s6-rc/service/{{ item.name }}' + content: '{{ item.content }}' + mode: 0444 + owner: root + group: wheel + loop_control: + label: '{{ item.name }} = {{ item.content }}' + notify: + - Reload s6-rc + - Restart Dovecot log + - Restart Dovecot + with_items: '{{ dovecot_service_config }}' + +- name: Configure dovecot + template: + dest: '/usr/local/etc/dovecot/{{ item }}' + src: '{{ item }}.j2' + mode: 0440 + owner: dovecot + group: wheel + with_items: + - dovecot.conf + - passwd + notify: + - Reload Dovecot + +- name: Tell acme.sh where to find Dovecot + lineinfile: + path: /var/db/acme/account.conf + create: yes + owner: acme + group: acme + regexp: '^DEPLOY_DOVECOT_PEM_PATH=' + state: present + line: 'DEPLOY_DOVECOT_RELOAD="sudo s6-svc -h /run/service/dovecot"' + +- name: Flush handlers + meta: flush_handlers + +- name: Allow acme.sh to reload Dovecot + template: + dest: /usr/local/etc/sudoers.d/acme_dovecot + src: acme_dovecot.j2 + mode: 0444 + owner: root + group: wheel + +- name: Deploy X.509 certificate to Dovecot + command: 'env sudo -Hu acme acme.sh --debug --home /var/db/acme --install-cert --domain {{ ansible_fqdn }} --cert-file /usr/local/etc/dovecot/cert.pem --key-file /usr/local/etc/dovecot/privkey.pem --fullchain-file /usr/local/etc/dovecot/fullchain.pem --reloadcmd "sudo s6-svc -h /run/service/dovecot"' + args: + creates: /usr/local/etc/dovecot/fullchain.pem + notify: + - Reload Dovecot + +- name: Start Dovecot + command: fdmove -c 2 1 s6-rc -u -v 2 -t 15000 change dovecot + register: change + changed_when: change.stdout | length > 0 + +- name: Enable Dovecot + lineinfile: + path: /etc/s6-rc/service/enabled/contents + regexp: "^dovecot$" + line: dovecot + state: present + notify: + - Reload s6-rc + +- name: Flush handlers (again) + meta: flush_handlers diff --git a/roles/dovecot/templates/acme_dovecot.j2 b/roles/dovecot/templates/acme_dovecot.j2 new file mode 100644 index 0000000..af8e19c --- /dev/null +++ b/roles/dovecot/templates/acme_dovecot.j2 @@ -0,0 +1 @@ +acme ALL=NOPASSWD:/usr/local/bin/s6-svc -h /run/service/dovecot diff --git a/roles/dovecot/templates/dovecot-log/finish.j2 b/roles/dovecot/templates/dovecot-log/finish.j2 new file mode 100644 index 0000000..37c3bce --- /dev/null +++ b/roles/dovecot/templates/dovecot-log/finish.j2 @@ -0,0 +1,13 @@ +#!/usr/local/bin/execlineb -S2 +# {{ ansible_managed }} + +s6-envdir ./env +multisubstitute { + importas -i -u NAME NAME +} + +fdmove -c 1 2 +ifelse { test "${1}" -eq 0 } { + echo "${NAME}-log: Stopped." +} + echo "${NAME}-log: Failed with exit status (${1}, ${2})." diff --git a/roles/dovecot/templates/dovecot-log/run.j2 b/roles/dovecot/templates/dovecot-log/run.j2 new file mode 100644 index 0000000..1f9904f --- /dev/null +++ b/roles/dovecot/templates/dovecot-log/run.j2 @@ -0,0 +1,23 @@ +#!/usr/local/bin/execlineb +# {{ ansible_managed }} + +s6-envdir ./env +multisubstitute { + importas -i -u NAME NAME + importas -i -u USER USER + importas -i -u GROUP GROUP + importas -i -u MODE MODE + importas -i -u DIR DIR +} + +foreground { fdmove -c 1 2 echo "${NAME} log: Starting." } + +ifelse -n { install -d -o "${USER}" -g "${GROUP}" -m "${MODE}" "$DIR" } { + foreground { fdmove -c 1 2 echo "${NAME} log: Failed to create logging directory." } + false +} + +fdmove -c 2 1 + +s6-envuidgid $USER +s6-log -d 3 T $DIR diff --git a/roles/dovecot/templates/dovecot.conf.j2 b/roles/dovecot/templates/dovecot.conf.j2 new file mode 100644 index 0000000..9f8dab2 --- /dev/null +++ b/roles/dovecot/templates/dovecot.conf.j2 @@ -0,0 +1,124 @@ +# {{ ansible_managed }} + +base_dir = /var/run/dovecot +import_environment = TZ LC_CTYPE LC_TIME LC_COLLATE LC_NUMERIC LC_MONETARY +log_path = /dev/stderr + +default_vsz_limit = 2 G +verbose_proctitle = yes +doveadm_worker_count = 8 + +mail_location = mdbox:~/mdbox +mail_plugins = fts fts_xapian + +listen = {{ dovecot_listen }} + +ssl = required +ssl_cert =