From df93903d843abd9eadef31e660e353970cd0c1d9 Mon Sep 17 00:00:00 2001 From: Andrea Dell'Amico Date: Wed, 1 Jun 2022 17:09:07 +0200 Subject: [PATCH] Add support for DKIM signing via opendkim. --- README.md | 3 +- defaults/main.yml | 40 ++++++++++--- handlers/main.yml | 6 ++ tasks/dkim.yml | 88 ++++++++++++++++++++++++++++ tasks/main.yml | 3 +- templates/dkim_keytable.j2 | 3 + templates/dkim_signingtable.j2 | 3 + templates/dkim_trustedhosts.j2 | 3 + templates/main.cf.j2 | 7 +++ templates/opendkim.conf.j2 | 103 +++++++++++++++++++++++++++++++++ vars/main.yml | 12 +++- 11 files changed, 259 insertions(+), 12 deletions(-) create mode 100644 tasks/dkim.yml create mode 100644 templates/dkim_keytable.j2 create mode 100644 templates/dkim_signingtable.j2 create mode 100644 templates/dkim_trustedhosts.j2 create mode 100644 templates/opendkim.conf.j2 diff --git a/README.md b/README.md index 17b79b4..2eda3d3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ Role Name ========= -A role that installs and configures sendmail. With support for the spamassassin and clamav milters +A role that installs and configures postfix, . With support +for the spamassassin and clamav milters Role Variables -------------- diff --git a/defaults/main.yml b/defaults/main.yml index a51cbdc..6a3dbbb 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -41,12 +41,12 @@ postfix_smtp_sasl_tls_security_options: '{{ postfix_smtp_sasl_security_options } postfix_smtp_sasl_mechanism_filter: plain, login # Set it in your vars files -#postfix_relay_host: smtp-relay.example.com +# postfix_relay_host: smtp-relay.example.com postfix_relay_port: 587 -#postfix_smtp_relay_user: smtp-user +# postfix_smtp_relay_user: smtp-user postfix_smtp_relay_user: '{{ ansible_fqdn }}' # This one has to be set inside a vault file -#postfix_smtp_relay_pwd: 'set_you_password_here_in_a_vault_encrypted_file' +# postfix_smtp_relay_pwd: 'set_you_password_here_in_a_vault_encrypted_file' postfix_smtpd_reject_unknown_helo_hostname: False postfix_reject_unknown_sender_domain: True ############################################################################# @@ -103,9 +103,34 @@ postfix_spf_policy_domain_whitelist: '' postfix_spf_policy_reject_not_pass_domains: '' postfix_spf_policy_lookup_time: 20 postfix_spf_policy_void_limit: 2 +# +# DKIM +# +postfix_dkim_enabled: false +postfix_dkim_domains: [] +# - domain: 'example.com' +# dkim_selector: 'default' +# s: sign +# v: verify +# sv: sign and verify +postfix_dkim_mode: 'v' +postfix_dkim_trusted_hosts_enabled: false +postfix_dkim_trusted_hosts: [] +# - 'example.com' +# - 'CIDR' +postfix_dkim_sign_subdomains: "no" +postfix_dkim_syslog: "yes" +postfix_dkim_syslog_success: "yes" +postfix_dkim_logwhy: "yes" +postfix_dkim_socket: 'inet:8891@localhost' +postfix_dkim_milter_socket: 'inet:[127.0.0.1]:8891' +postfix_dkim_v_sendreports: 'no' +postfix_dkim_reportaddress: '' +postfix_dkim_canonicalization: 'relaxed/relaxed' +postfix_dkim_minkeybits: 1024 ############################################################################# -# SMTP server that not accept authenticated clients. +# SMTP server that not accept authenticated clients. ############################################################################# postfix_smtpd_server: False postfix_smtpd_server_restrictions: @@ -194,10 +219,8 @@ postfix_transport_maps: - 'hash:/etc/postfix/transport' postfix_transport_data: [] -# -# Example: -# postfix_transport_data: -# - { domain: 'example.com', action: 'smtp:[dest.smtp.example.com]:25' } +# - domain: 'example.com' +# action: 'smtp:[dest.smtp.example.com]:25' postfix_rbl_enabled: True postfix_rbl_list: 'zen.spamhaus.org' postfix_spamhaus_dbl_enabled: True @@ -265,4 +288,3 @@ postfix_firewalld_services: - { service: 'smtp', state: 'enabled', zone: '{{ firewalld_default_zone }}' } - { service: 'smtps', state: 'enabled', zone: '{{ firewalld_default_zone }}' } - { service: 'smtp-submission', state: 'enabled', zone: '{{ firewalld_default_zone }}' } - diff --git a/handlers/main.yml b/handlers/main.yml index 62e759f..8960c74 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -1,3 +1,4 @@ +--- - name: Update SASL hash shell: postmap hash:/etc/postfix/sasl_passwd @@ -19,3 +20,8 @@ - name: restart saslauth daemon service: name=saslauthd state=restarted when: postfix_enabled | bool + +- name: restart opendkim + service: + name: opendkim + state: restarted diff --git a/tasks/dkim.yml b/tasks/dkim.yml new file mode 100644 index 0000000..03d7679 --- /dev/null +++ b/tasks/dkim.yml @@ -0,0 +1,88 @@ +--- +- name: Manage the DKIM packages in EL systems + block: + - name: Install the DKIM packages on EL + yum: + pkg: '{{ postfix_dkim_el_pkgs }}' + state: present + + when: + - ansible_distribution_file_variety == "RedHat" + - postfix_dkim_enabled + tags: ['postfix', 'postfix_dkim', 'dkim'] + +- name: Manage the DKIM packages in DEB systems + block: + - name: Install the DKIM packages on DEB + apt: + pkg: '{{ postfix_dkim_deb_pkgs }}' + state: present + cache_valid_time: 1800 + + when: + - ansible_distribution_file_variety == "Debian" + - postfix_dkim_enabled + tags: ['postfix', 'postfix_dkim', 'dkim'] + +- name: DKIM configuration + block: + - name: Create the dkim domains subdirs + file: + dest: '{{ postfix_dkim_base_dir }}/{{ item.domain }}' + state: directory + mode: 0750 + owner: '{{ postfix_dkim_user }}' + group: '{{ postfix_dkim_group }}' + loop: '{{ postfix_dkim_domains }}' + + - name: Create the dkim signatures + become: true + become_user: '{{ postfix_dkim_user }}' + shell: opendkim-genkey -D {{ postfix_dkim_base_dir }}/{{ item.domain }} -d {{ item.domain }} -s {{ item.dkim_selector }} + args: + creates: '{{ postfix_dkim_base_dir }}/{{ item.domain }}/{{ item.dkim_selector }}.private' + loop: '{{ postfix_dkim_domains }}' + notify: restart opendkim + + - name: Update the keytable and signitable files + template: + src: 'dkim_{{ item }}.j2' + dest: '{{ postfix_dkim_base_dir }}/{{ item }}' + owner: '{{ postfix_dkim_user }}' + group: '{{ postfix_dkim_group }}' + mode: 0600 + loop: + - keytable + - signingtable + notify: restart opendkim + + - name: Install the trustedhosts list when defined + template: + src: 'dkim_trustedhosts.j2' + dest: '{{ postfix_dkim_base_dir }}/trustedhosts' + owner: '{{ postfix_dkim_user }}' + group: '{{ postfix_dkim_group }}' + mode: 0600 + notify: restart opendkim + when: postfix_dkim_trusted_hosts_enabled + + - name: Install the opendkim configuration + template: + src: opendkim.conf.j2 + dest: '{{ postfix_dkim_conf }}' + owner: root + group: root + mode: 0644 + notify: restart opendkim + + tags: ['postfix', 'postfix_dkim', 'dkim', 'postfix_conf', 'dkim_conf'] + +- name: Manage the DKIM service + block: + - name: Ensure that the opendkim service is started and enabled + service: + name: opendkim + state: started + enabled: true + + tags: ['postfix', 'postfix_dkim', 'dkim'] diff --git a/tasks/main.yml b/tasks/main.yml index 85b0050..0ffd8d6 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,5 +1,7 @@ --- - import_tasks: smtp-common-packages.yml +- import_tasks: dkim.yml + when: postfix_dkim_enabled - import_tasks: postfix_spf_policy.yml when: postfix_spf_policy_install - import_tasks: smtp-configuration.yml @@ -14,4 +16,3 @@ when: postfix_smtpd_server | bool - import_tasks: postfix-letsencrypt-hook.yml when: postfix_use_letsencrypt | bool - diff --git a/templates/dkim_keytable.j2 b/templates/dkim_keytable.j2 new file mode 100644 index 0000000..c252c85 --- /dev/null +++ b/templates/dkim_keytable.j2 @@ -0,0 +1,3 @@ +{% for dom in postfix_dkim_domains %} +{{ dom.dkim_selector }}._domainkey.{{ dom.domain }} {{ dom.domain }}:{{ dom.dkim_selector }}:{{ postfix_dkim_base_dir }}/{{ dom.domain }}/{{ dom.dkim_selector }}.private +{% endfor %} diff --git a/templates/dkim_signingtable.j2 b/templates/dkim_signingtable.j2 new file mode 100644 index 0000000..0b32f2b --- /dev/null +++ b/templates/dkim_signingtable.j2 @@ -0,0 +1,3 @@ +{% for dom in postfix_dkim_domains %} +*@{{ dom.domain }} {{ dom.dkim_selector }}._domainkey.{{ dom.domain }} +{% endfor %} diff --git a/templates/dkim_trustedhosts.j2 b/templates/dkim_trustedhosts.j2 new file mode 100644 index 0000000..f96b94c --- /dev/null +++ b/templates/dkim_trustedhosts.j2 @@ -0,0 +1,3 @@ +{% for item in postfix_dkim_trusted_hosts %} +{{ item }} +{% endfor %} diff --git a/templates/main.cf.j2 b/templates/main.cf.j2 index 9c98f7e..0af570f 100644 --- a/templates/main.cf.j2 +++ b/templates/main.cf.j2 @@ -576,6 +576,13 @@ smtpd_milters = {% if postfix_spamassassin_milter %} {{ postfix_spamassassin_milter_socket }} {% endif %} +{% if postfix_dkim_enabled %} + {{ postfix_dkim_milter_socket }} +{% endif %} +{% if postfix_dkim_enabled %} +non_smtpd_milters = + {{ postfix_dkim_milter_socket }} +{% endif %} {% endif %} {% if postfix_smtpd_server %} diff --git a/templates/opendkim.conf.j2 b/templates/opendkim.conf.j2 new file mode 100644 index 0000000..41a868e --- /dev/null +++ b/templates/opendkim.conf.j2 @@ -0,0 +1,103 @@ +## CONFIGURATION OPTIONS + +## Specifies the path to the process ID file. +PidFile /var/run/opendkim/opendkim.pid + +## Selects operating modes. Valid modes are s (sign) and v (verify). Default is v. +## Must be changed to s (sign only) or sv (sign and verify) in order to sign outgoing +## messages. +Mode {{ postfix_dkim_mode }} + +{% if "s" in postfix_dkim_mode %} +## SubDomains { yes | no } +## default "no" +## +## Sign for subdomains as well? + +SubDomains {{ postfix_dkim_sign_subdomains }} +{% endif %} + +## Log activity to the system log. +Syslog {{ postfix_dkim_syslog }} + +## Log additional entries indicating successful signing or verification of messages. +SyslogSuccess {{ postfix_dkim_syslog_success }} + +## If logging is enabled, include detailed logging about why or why not a message was +## signed or verified. This causes an increase in the amount of log data generated +## for each message, so set this to No (or comment it out) if it gets too noisy. +LogWhy {{ postfix_dkim_logwhy }} + +## Attempt to become the specified user before starting operations. +UserID {{ postfix_dkim_user }}:{{ postfix_dkim_group }} + +## Create a socket through which your MTA can communicate. +Socket {{ postfix_dkim_socket }} + +## Required to use local socket with MTAs that access the socket as a non- +## privileged user (e.g. Postfix) +Umask 002 + +## This specifies a text file in which to store DKIM transaction statistics. +## OpenDKIM must be manually compiled with --enable-stats to enable this feature. +# Statistics /var/spool/opendkim/stats.dat + +{% if "v" in postfix_dkim_mode %} +## Specifies whether or not the filter should generate report mail back +## to senders when verification fails and an address for such a purpose +## is provided. See opendkim.conf(5) for details. +SendReports {{ postfix_dkim_v_sendreports }} + +{% endif %} +{% if postfix_dkim_reportaddress != '' %} +## Specifies the sending address to be used on From: headers of outgoing +## failure reports. By default, the e-mail address of the user executing +## the filter is used (executing_user@hostname). +# ReportAddress {{ postfix_dkim_reportaddress }} +{% endif %} + +## Add a DKIM-Filter header field to messages passing through this filter +## to identify messages it has processed. +SoftwareHeader yes + +{% if "s" in postfix_dkim_mode %} +## SIGNING OPTIONS + +## Selects the canonicalization method(s) to be used when signing messages. +Canonicalization {{ postfix_dkim_canonicalization }} + +## Specifies the minimum number of key bits for acceptable keys and signatures. +MinimumKeyBits {{ postfix_dkim_minkeybits }} + +## Gives the location of a file mapping key names to signing keys. In simple terms, +## this tells OpenDKIM where to find your keys. If present, overrides any KeyFile +## directive in the configuration file. Requires SigningTable be enabled. +KeyTable /etc/opendkim/keytable + +## Defines a table used to select one or more signatures to apply to a message based +## on the address found in the From: header field. In simple terms, this tells +## OpenDKIM how to use your keys. Requires KeyTable be enabled. +SigningTable refile:/etc/opendkim/signingtable + +{% if postfix_dkim_trusted_hosts_enabled %} +## Identifies a set of "external" hosts that may send mail through the server as one +## of the signing domains without credentials as such. +# ExternalIgnoreList refile:/etc/opendkim/TrustedHosts + +## Identifies a set "internal" hosts whose mail should be signed rather than verified. +InternalHosts refile:/etc/opendkim/TrustedHosts +{% endif %} + +## Always oversign From (sign using actual From and a null From to prevent +## malicious signatures header fields (From and/or others) between the signer +## and the verifier. From is oversigned by default in the Fedora package +## because it is often the identity key used by reputation systems and thus +## somewhat security sensitive. +OversignHeaders From +{% endif %} + +## Instructs the DKIM library to maintain its own local cache of keys and +## policies retrieved from DNS, rather than relying on the nameserver for +## caching service. Useful if the nameserver being used by the filter is +## not local. +# QueryCache yes diff --git a/vars/main.yml b/vars/main.yml index 3808477..175c924 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -1,2 +1,12 @@ --- -# vars file for ansible-role-template \ No newline at end of file +postfix_dkim_el_pkgs: + - opendkim + +postfix_dkim_deb_pkgs: + - opendkim + - opendkim-tools + +postfix_dkim_base_dir: /etc/opendkim +postfix_dkim_user: opendkim +postfix_dkim_group: opendkim +postfix_dkim_conf: /etc/opendkim.conf