diff options
author | Guilhem Moulin <guilhem@fripost.org> | 2018-12-03 23:13:04 +0100 |
---|---|---|
committer | Guilhem Moulin <guilhem@fripost.org> | 2018-12-04 01:14:45 +0100 |
commit | c21b92d9b79a80a27607618666b56fbc5cd26ac8 (patch) | |
tree | 264c8800eac3d6aeac734bbf43fdde40a16781ff | |
parent | 50d5b3827eb9e342e499c053f330ac0bcfe424fa (diff) |
Upgrade DKIM keys to rsa2048, and allow for multiple keys.
-rw-r--r-- | certs/dkim/8f00fb94ec6c37aacb48bd43e073f9b7.pub | 9 | ||||
-rw-r--r-- | certs/dkim/9df9cdc7e101629b5003b587945afa70.pub | 9 | ||||
-rw-r--r-- | certs/dkim/README | 11 | ||||
-rw-r--r-- | group_vars/all.yml | 12 | ||||
-rw-r--r-- | roles/amavis/handlers/main.yml | 4 | ||||
-rw-r--r-- | roles/amavis/tasks/main.yml | 19 | ||||
-rw-r--r-- | roles/amavis/templates/etc/amavis/conf.d/50-user.j2 | 18 |
7 files changed, 69 insertions, 13 deletions
diff --git a/certs/dkim/8f00fb94ec6c37aacb48bd43e073f9b7.pub b/certs/dkim/8f00fb94ec6c37aacb48bd43e073f9b7.pub new file mode 100644 index 0000000..ef400f4 --- /dev/null +++ b/certs/dkim/8f00fb94ec6c37aacb48bd43e073f9b7.pub @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApmCWIVZt+L/bJ5+abvdm +Fm6Er/9g6e4WX2HKyeIfC5eDaPbUyHqHSY7xzWNiU+cbBvny8BASkdWsclLdoiuM +J6Yes5VSzkH6j2gp9Uuy7d6p61Jbrizi7/CQzCZfhi5uGKiGtV2g+V/sIuXekm9Q ++Q2eqjj/6hUHGDPTTKEFlgruyaS6y+Kes+sJYjMG62lbTOKL5TjY6z0Gr2AMfglB +Uj9QWD5jm+bH0clE1HZq51mxXQbV2v/7JEHjznR0nSB+jY2EV7g/MXM8DwJCDH4Z +cknoH0NrcJRjuRt8ndufnx4Qh0t7qqWwmGF0jZOcZxHeODfkUlLxQ4SCMVeqV/SS +TwIDAQAB +-----END PUBLIC KEY----- diff --git a/certs/dkim/9df9cdc7e101629b5003b587945afa70.pub b/certs/dkim/9df9cdc7e101629b5003b587945afa70.pub new file mode 100644 index 0000000..2574f71 --- /dev/null +++ b/certs/dkim/9df9cdc7e101629b5003b587945afa70.pub @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyN6rMmDzZ0MtN6e+T3lS +wny1qs0djjXJMJi5gfCXl9ZW4v5LT098EtpEQsDfY8NY3PvuBTD74Xsvy9jRh71/ +q0iZHHwOffQlP8BVi2uelO9brVBr9nHWvycbEp/PXMVPOSBRuXyrvIYPnWjmaPZc +xT4L3OB5BtZPsGElxAzZMbTDzRr8K0yIY/HtVTXD5JJsKb3GIXiyHY7GCvV6tKeP +eI2L0vJOJ2LLHHX962ykWHAfS12izkfBxGkMVn4AQZIPQ4iGwAPZ9z5DIsz11Riw ++3ysWWdmz2yV8HtoDKfOB4/vyFyWFlyaMkdvblDjgQv0m6bHwvXlxAGSWcZirmEM +pQIDAQAB +-----END PUBLIC KEY----- diff --git a/certs/dkim/README b/certs/dkim/README new file mode 100644 index 0000000..e5addf9 --- /dev/null +++ b/certs/dkim/README @@ -0,0 +1,11 @@ +To convert a PEM-encoded public key to a TXT record, run + + $ SELECTOR="8f00fb94ec6c37aacb48bd43e073f9b7" + $ DOMAIN="fripost.org" + $ printf "%s._domainkey%s IN TXT (\n" "$SELECTOR" "${DOMAIN:+.$DOMAIN.}"; \ + { printf "v=DKIM1; k=rsa; t=s; s=email; p="; + sed '/^--.*--$/d' <"./certs/dkim/$SELECTOR.pub" | tr -d '\n'; + } | fold -w64 | sed 's/.*/ "&"/; $s/$/ )\n/' + +Remove the "t=s" tag if subdomaining or third-party signature (hosted +domain) is required, cf. RFC 6376 sec. 3.6.1. diff --git a/group_vars/all.yml b/group_vars/all.yml index 49cf935..f222b56 100644 --- a/group_vars/all.yml +++ b/group_vars/all.yml @@ -29,20 +29,32 @@ postfix_instance: # therefore have to limit the number of outgoing SMTP proxy and # IMAP server to one. Since hosts(5) files cannot map and IP # address to multiple hostnames, a workaround would be to use # round-robin DNS, but we can't rely on DNS as long as our zone is # unsigned. IMAP: { name: mda , addr: "{{ (groups.all | length > 1) | ternary( ipsec[ hostvars[groups.IMAP[0]].inventory_hostname_short ], '127.0.0.1') }}" , port: 2526 } MX: { name: mx, group: mta } out: { name: out, group: mta , addr: "{{ (groups.all | length > 1) | ternary( ipsec[ hostvars[groups.out[0]].inventory_hostname_short ], '127.0.0.1') }}" , port: 2525 } MSA: { name: msa , addr: "{{ (groups.all | length > 1) | ternary( ipsec[ hostvars[groups.MSA[0]].inventory_hostname_short ], '127.0.0.1') }}" , port: 2587 } lists: { name: lists , addr: "{{ (groups.all | length > 1) | ternary( ipsec[ hostvars[groups.lists[0]].inventory_hostname_short ], '127.0.0.1') }}" , port: 2527 } imapsvr_addr: "{{ postfix_instance.IMAP.addr | ipaddr }}" + +dkim_keys: + giraff: + # match key + "fripost.org": + # domain of the entity signing the message (should be unique accross match keys) + d: fripost.org + # selector (should be globally unique and random) + s: 8f00fb94ec6c37aacb48bd43e073f9b7 + "~": # catch-all, for our virtual domains + d: x.fripost.org + s: 9df9cdc7e101629b5003b587945afa70 diff --git a/roles/amavis/handlers/main.yml b/roles/amavis/handlers/main.yml index 62cc6fc..684be0f 100644 --- a/roles/amavis/handlers/main.yml +++ b/roles/amavis/handlers/main.yml @@ -1,13 +1,9 @@ --- - name: Restart ClamAV service: name=clamav-daemon state=restarted -- name: Publish the public key to the DNS zone - # See the output of 'genkeypair.sh dkim --privkey=/path/to/key' - fail: "msg={{ dkim.stdout }}" - - name: Restart Amavis service: name=amavis state=restarted - name: Restart munin-node service: name=munin-node state=restarted diff --git a/roles/amavis/tasks/main.yml b/roles/amavis/tasks/main.yml index 936703a..92a0e81 100644 --- a/roles/amavis/tasks/main.yml +++ b/roles/amavis/tasks/main.yml @@ -24,60 +24,71 @@ - tnef notify: - Restart Amavis - name: Add 'clamav' to the group 'amavis' user: name=clamav groups=amavis append=yes notify: - Restart ClamAV - Restart Amavis - name: Add an 'amavis' alias lineinfile: dest=/etc/aliases create=yes regexp="^amavis{{':'}} " line="amavis{{':'}} root" - name: Compile the static local Postfix database postmap: cmd=postalias src=/etc/aliases db=lmdb owner=root group=root mode=0644 -- name: Create directory /var/lib/dkim - file: path=/var/lib/dkim +- name: Create directory /etc/amavis/dkim + file: path=/etc/amavis/dkim state=directory owner=root group=root mode=0755 when: "'out' in group_names" tags: - genkey + - dkim - name: Generate a private key for DKIM signing - command: genkeypair.sh dkim --privkey=/var/lib/dkim/20140703.fripost.org.key -t rsa -b 1024 + command: genkeypair.sh dkim --privkey=/etc/amavis/dkim/{{ item }}.pem -t rsa -b 2048 + with_items: "{{ (dkim_keys[inventory_hostname_short] | default({})).values() | map(attribute='s') | list }}" register: dkim changed_when: dkim.rc == 0 failed_when: dkim.rc > 1 when: "'out' in group_names" notify: - Restart Amavis - - Publish the public key to the DNS zone tags: - genkey + - dkim + +- name: Fetch DKIM keys + fetch_cmd: cmd="openssl pkey -pubout -outform PEM" + stdin=/etc/amavis/dkim/{{ item }}.pem + dest=certs/dkim/{{ item }}.pub + with_items: "{{ (dkim_keys[inventory_hostname_short] | default({})).values() | map(attribute='s') | list }}" + tags: + - genkey + - dkim - name: Configure Amavis template: src=etc/amavis/conf.d/50-user.j2 dest=/etc/amavis/conf.d/50-user owner=root group=root mode=0644 register: r3 notify: - Restart Amavis - meta: flush_handlers - name: Start Amavis service: name=amavis state=started - name: Install 'amavis' Munin plugin file: src=/usr/share/munin/plugins/amavis dest=/etc/munin/plugins/amavis owner=root group=root diff --git a/roles/amavis/templates/etc/amavis/conf.d/50-user.j2 b/roles/amavis/templates/etc/amavis/conf.d/50-user.j2 index 26bcdb9..f3ff416 100644 --- a/roles/amavis/templates/etc/amavis/conf.d/50-user.j2 +++ b/roles/amavis/templates/etc/amavis/conf.d/50-user.j2 @@ -15,46 +15,54 @@ use strict; # the amavisfeed service. $max_servers = 5; $recipient_delimiter = '+'; $mydomain = 'fripost.org'; $X_HEADER_LINE = "Debian $myproduct_name at $mydomain"; @mynetworks_maps = (); @remove_existing_spam_headers_maps = (); @bypass_virus_checks_maps = (); # load virus checking code $enable_dkim_verification = 1; # load DKIM signing/verifying code {% if 'out' not in group_names %} undef $enable_dkim_signing; @bypass_spam_checks_maps = (); # load spam checking code {% else %} $enable_dkim_signing = 1; # Sign *all* outgoing mails with *our* key (yes, amavis complains, but this is # safe as we force our domain with the 'd' tag). -dkim_key(qr/./, '20140703', '/var/lib/dkim/20140703.'.$mydomain.'.key'); +{% for x,k in dkim_keys[inventory_hostname_short] | default({}) | dictsort() -%} +dkim_key({{ (x == "~") | ternary('qr/./', "'"+x+"'") }}, '{{ k.s }}', '/etc/amavis/dkim/{{ k.s }}.pem'); +{% endfor -%} @dkim_signature_options_bysender_maps = ( - { '.' => { d => $mydomain - , a => 'rsa-sha256' - , ttl => 21*24*3600 - , c => 'relaxed/simple' } } ); +{% for x,k in dkim_keys[inventory_hostname_short] | default({}) | dictsort() %} + { '{{ (x == "~") | ternary('.', x) }}' => { + d => '{{ k.d }}' + , a => 'rsa-sha256' + , ttl => 21*24*3600 + , c => 'relaxed/simple' } + }{% if not loop.last %}, +{% endif %} +{% endfor %} +); # Conform to RFC 4871 and don't sign Received: headers. $signed_header_fields{received} = 0; {% endif %} # Defang viruses and nothing else %defang_maps_by_ccat = ( &CC_VIRUS => 1 , &CC_CATCHALL => undef ); # Don't change the subject for unchecked messages (not by-recip) delete $subject_tag_maps_by_ccat{+CC_UNCHECKED}; # Never BCC / DSN; don't forget to disallow setting amavisSpamDsnCutoffLevel # and amavis*Admin, also %always_bcc_by_ccat = ( &CC_CATCHALL => undef ); %dsn_bcc_by_ccat = ( &CC_CATCHALL => undef ); # Never warn sender or recipient; don't forget to disallow setting |