Postfix+DKIM email signatures in amavisd-new

DKIM is a system to verify the sender and integrity of emails.

A DKIM standard (RFC 4871) states the following, which applies to its predecessor DomainKeys (historical: RFC 4870) as well:

DomainKeys Identified Mail (DKIM) defines a mechanism by which email messages can be cryptographically signed, permitting a signing domain to claim responsibility for the introduction of a message into the mail stream. Message recipients can verify the signature by querying the signer’s domain directly to retrieve the appropriate public key, and thereby confirm that the message was attested to by a party in possession of the private key for the signing domain.

The DomainKeys specification was a primary source from which the DomainKeys Identified Mail [DKIM] specification has been derived. The purpose in submitting the RFC 4870 document is as an historical reference for deployed implementations written prior to the DKIM specification.

Implementation and mail flow

              +------+
              |verify|          (verify)
              +--+---+              | (by amavisd and/or SA)
                ^^^ milter          |
incoming:       |||             +---v-------+
  MX ---->  25 smtpd ---> 10024 >           >---> 10025 smtpd -->
                 ||             |           |
  SASL -->  25 smtpd \          |  amavisd  | (notifications)
submission        |   +->       |           >--->_
  mynets->  25 smtpd ---> 10026 >ORIGINATING>---> 10027 smtpd -->
submission            +->       +-------^---+            |
       --> 587 smtpd /  :               |                v milter
                       (convert         |             +------+
                       to 7-bit)      (sign)          | sign |
                                                      +------+

Here’s how to set it up:

1) Create the domain key:

# mkdir /var/db/dkim/
# amavisd genrsa /var/db/dkim/example-foo.key.pem

2) Configure amavisd to use this key for the domain example.com. Edit the amavisd configuration file

# vi /etc/amavisd/amavisd.conf

add the following lines to amavisd.conf:

$enable_dkim_verification = 1;
$enable_dkim_signing = 1;
dkim_key(’example.com’, ‘foo’, ‘/var/db/dkim/example-foo.key.pem’);
@dkim_signature_options_bysender_maps = (
{ ‘.’ => { ttl => 21*24*3600, c => ‘relaxed/simple’ } } );
@mynetworks = qw(0.0.0.0/8 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12
192.168.0.0/16);  # list your internal networks
$inet_socket_port = [10024,10026];  # listen on two ports

The 10024>10025 path will be controlled by a default policy bank, the other (10026>10027), dedicated to mail intended to be signed,
will use a policy bank (arbitrarily) named ORIGINATING:

$forward_method = 'smtp:[127.0.0.1]:10025';  # MTA with non-signing service
$notify_method  = 'smtp:[127.0.0.1]:10027';  # MTA with signing service

# switch policy bank to 'ORIGINATING' for mail received on port 10026:
$interface_policy{'10026'} = 'ORIGINATING';

$policy_bank{'ORIGINATING'} = {  # mail originating from our users
  originating => 1,  # indicates client is ours, allows signing
  #
  # force MTA to convert mail to 7-bit before DKIM signing
  # to avoid later conversions which could destroy signature:
  smtpd_discard_ehlo_keywords => ['8BITMIME'],
  #
  # forward to a smtpd service providing DKIM signing service
  # (if using a signing milter instead of signing by amavisd):
  forward_method => 'smtp:[127.0.0.1]:10027',
  #
  # other special treatment of locally originating mail,
  # just some suggestions here:
  spam_admin_maps  => ["spamalert\@$mydomain"],  # warn of spam from us
  virus_admin_maps => ["virusalert\@$mydomain"],
  banned_filename_maps => ['ALT-RULES'],         # more relaxed rules
  spam_quarantine_cutoff_level_maps => undef,    # quarantine all spam
  spam_dsn_cutoff_level_maps => undef,
  spam_dsn_cutoff_level_bysender_maps => # bounce to local senders only
    [ { lc(".$mydomain") => undef,  '.' => 15 } ],
};

run command:

$ amavisd showkeys

add the public key (as displayed) to your DNS zone, increment SOA sequence number and reload DNS; then test signing and a published key:

$ amavisd testkeys

if all went well:

$ amavisd reload

In Postfix:

Here is one way of configuring Postfix for providing two paths through a content filter. Locally submitted or authenticated mail will go to a content filter to its port 10026 and will be signed on its way out (either by amavisd or by a signing milter). All other mail (incoming) will be diverted to port 10024 for normal content filtering, and will not be eligible for signing.

main.cf:

content_filter = amavisfeed:[127.0.0.1]:10024

smtpd_sender_restrictions =
   check_sender_access regexp:/etc/postfix/tag_as_originating.re
   permit_mynetworks
   permit_sasl_authenticated
   permit_tls_clientcerts
   check_sender_access regexp:/etc/postfix/tag_as_foreign.re

/etc/postfix/tag_as_originating.re:

/^/  FILTER amavisfeed:[127.0.0.1]:10026

/etc/postfix/tag_as_foreign.re:

/^/  FILTER amavisfeed:[127.0.0.1]:10024

In master.cf set up two listening smtpd services for receiving filtered mail from amavisd (as per README.postfix), one on tcp port 10025 (for inbound mail) and the other on port 10027 (for originating mail).If a signing milter is in use it will be attached to a smtpd service on 10027 only.  If no milters are in use and signing is done by amavisd, both smtpd services can have exactly the same settings, nd in fact only one suffices, in which case redirecting $forward_method and $notify_method to ‘smtp:[127.0.0.1]:10027’ in later example can be disregarded.

master.cf:

# mail return from a content filter (non-signing)
10025    inet    n    -    n    -    -    smtpd
   -o content_filter=
   ... (other options, mail not to be signed) ...

# mail from our users returning from a content filter (DKIM signing)
10027    inet    n    -    n    -    -    smtpd
   -o content_filter=
   ... (other options, mail intended to be signed) ...
   -o milter_default_action=accept
   -o milter_macro_daemon_name=ORIGINATING

source: http://www.ijs.si/software/amavisd/amavisd-new-docs.html#dkim

4 Comments

  1. memed

    vi /etc/amavisd/amavisd.conf
    [..]
    dkim_key(’example.com’, ‘foo’, ‘/var/db/dkim/example-foo.key.pem’);
    [..]
    mas… maksudnya example.com itu nama domain kita apa sembarang?
    terus maksudnya "foo" itu apa yah ?
    terus kalo misal dalam satu server saya punya beberapa virtual domain gimana?
    saya lagi implement postfix dg amavisd tetapi kalo ada email dari yahoo pasti dimark **spam** di headernya. Thx b4

  2. admin admin

    example.com domain yg kita punya yg akan di sign, foo itu selector.

    untuk multiple domain, bisa seperti ini:

    #        signing domain  selector     private key              options
    #        -------------   --------     ----------------------   ----------
    dkim_key('example.org', 'abc',       '/var/db/dkim/a.key.pem');
    dkim_key('example.org', 'yyy',       '/var/db/dkim/b.key.pem', t=>'s');
    dkim_key('example.org', 'zzz',       '/var/db/dkim/b.key.pem', h=>'sha256');
    dkim_key('example.com', 'sel-2008',  '/var/db/dkim/sel-example-com.key.pem',
    

    yg membedakannya di selector yg uniq.

    selector di define dns, di domain yg akan di sign

    selector._domainkey.example.com

  3. Thank you boss, sangat bermanfaat dan memudahkan pemahaman implement DKIM via amavisd-new secara langsung tanpa dkim-milter.

Leave a Reply

Your email address will not be published. Required fields are marked *