How to Configure DKIM (OpenDKIM) with Postfix

Install OpenDKIM and Postfix


sudo apt install opendkim opendkim-tools postfix

Configure OpenDKIM


OpenDKIM can add DKIM signatures to outbound mail and check DKIM signatures on inbound mail. It can be configured to reject mail that has missing or invalid DKIM signatures.

  1. Create a directory structure that will store trusted hosts, key tables, signature tables, and crypto keys:

    sudo mkdir /etc/opendkim
    sudo mkdir /etc/opendkim/keys
    # or one line
    sudo mkdir -p /etc/opendkim/keys
    
  2. Generate the key pair for your DNS domain and selector:
    For key generation, the opendkim-tools package provides the opendkim-genkey program. This program generates a private key named <my_selector>.private in the specified directory, as well as a public key <my_selector>.txt ready to be included in a bind DNS zone file.

    sudo -u opendkim opendkim-genkey -D /etc/opendkim/keys -d my-domain.org -s my_selector
    
  3. Now, edit /etc/opendkim.conf. For the socket, the easiest option is to use a TCP socket listening on a local port (bypassing socket file ownership or chroot access issues). The file looks like this:

    # This is a basic configuration that can easily be adapted to suit a standard
    # installation. For more advanced options, see opendkim.conf(5) and/or
    # /usr/share/doc/opendkim/examples/opendkim.conf.sample.
    
    # Log to syslog
    Syslog          yes
    # Required to use local socket with MTAs that access the socket as a non-
    # privileged user (e.g. Postfix)
    UMask           007
    
    # Sign for example.com with key in /etc/dkimkeys/dkim.key using
    # selector '2007' (e.g. 2007._domainkey.example.com)
    Domain          my-domain.be
    KeyFile         /etc/opendkim/keys/my_selector.private
    Selector        my_selector
    
    # Map domains in From addresses to keys used to sign messages
    # KeyTable                /etc/opendkim/KeyTable
    # SigningTable            refile:/etc/opendkim/SigningTable
    
    # Hosts to ignore when verifying signatures
    ExternalIgnoreList      /etc/opendkim/TrustedHosts
    InternalHosts           /etc/opendkim/TrustedHosts
    
    # Commonly-used options; the commented-out versions show the defaults.
    #Canonicalization   simple
    #Mode           sv
    #SubDomains     no
    
    # Socket smtp://localhost
    #
    # ##  Socket socketspec
    # ##
    # ##  Names the socket where this filter should listen for milter connections
    # ##  from the MTA.  Required.  Should be in one of these forms:
    # ##
    # ##  inet:port@address           to listen on a specific interface
    # ##  inet:port                   to listen on all interfaces
    # ##  local:/path/to/socket       to listen on a UNIX domain socket
    #
    # Socket         local:/run/opendkim/opendkim.sock
    Socket inet:8891@localhost
    
    ##  PidFile filename
    ###      default (none)
    ###
    ###  Name of the file where the filter should write its pid before beginning
    ###  normal operations.
    #
    PidFile               /run/opendkim/opendkim.pid
    
    
    # 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 Debian pacakge
    # because it is often the identity key used by reputation systems and thus
    # somewhat security sensitive.
    OversignHeaders     From
    
    ##  ResolverConfiguration filename
    ##      default (none)
    ##
    ##  Specifies a configuration file to be passed to the Unbound library that
    ##  performs DNS queries applying the DNSSEC protocol.  See the Unbound
    ##  documentation at http://unbound.net for the expected content of this file.
    ##  The results of using this and the TrustAnchorFile setting at the same
    ##  time are undefined.
    ##  In Debian, /etc/unbound/unbound.conf is shipped as part of the Suggested
    ##  unbound package
    
    # ResolverConfiguration     /etc/unbound/unbound.conf
    
    ##  TrustAnchorFile filename
    ##      default (none)
    ##
    ## Specifies a file from which trust anchor data should be read when doing
    ## DNS queries and applying the DNSSEC protocol. See the Unbound documentation
    ## at http://unbound.net for the expected format of this file.
    
    TrustAnchorFile       /usr/share/dns/root.key
    
    ##  Userid userid
    ###      default (none)
    ###
    ###  Change to user "userid" before starting normal operation? May include
    ###  a group ID as well, separated from the userid by a colon.
    #
    UserID                opendkim
    
  4. In the file /etc/opendkim/TrustedHosts specify which hosts will have messages signed. If needed, include localhost as it is not implicit:

    127.0.0.1
    ::1
    localhost
    [SERVER_IP]
    [YOUR_HOSTNAME]
    mail.[MY_DOMAIN].be
    [MY_DOMAIN].be
    [MY_OTHER_DOMAIN].be
    
  5. Multiple domains


    For a single-domain DKIM setup with only a single key, the configuration shown above, using the three parameters DomainSelectorKeyFile is enough. However, opendkim configuration supports multiple domains and keys, read from a variety of sources (files, SQL databases, Lua scripts, …). KeyTable and SigningTable are the configuration parameters that enable this. For mail servers that are “smarthosts”, opendkim can be configured to sign messages from subnets of trusted systems via the InternalHosts parameter. So, uncomment KeyTable and SigningTable in /etc/opendkim/opendkim.conf:

    # Map domains in From addresses to keys used to sign messages
    KeyTable                /etc/opendkim/KeyTable
    # To use regular expressions in the file, use refile: instead of file:
    SigningTable            refile:/etc/opendkim/SigningTable
    
    Now in the file /etc/opendkim/KeyTable, put information about the private key:

    my_selector_key my-domain.be:my_selector:/etc/opendkim/keys/my_selector.private 
    my_other_selector_key my-other-domain.be:my_other_selector:/etc/opendkim/keys/my_other_selector.private
    
    In the file /etc/opendkim/SigningTable, specify which key will sign a domain:

    *@my-doamin.be my_selector_key
    *@my-other-domain.be my_other_selector_key
    
  6. Socket
    The opendkim service has to provide a communication channel for the MTA (Postfix). A TCP socket listening on a port only accessible locally is a reasonable choice that is also easy to set up.
    We have to change SOCKET in /etc/default/opendkim:

    # SOCKET=local:$RUNDIR/opendkim.sock
    SOCKET="inet:8891@localhost"
    
  7. Change ownership of all files to opendkim:

    sudo chown -R opendkim:opendkim /etc/opendkim
    sudo chmod -R 600 /etc/opendkim/keys
    sudo chmod -R go-rw /etc/opendkim/keys
    
  8. Don’t forget to restart opendkim to apply the settings.

    sudo service opendkim restart
    

Configure Postfix


  1. To integrate the opendkim service with Postfix. Edit /etc/postfix/main.cf to connect the two.
    Also, we have to make some changes to imporve presentation. By default, TLS is disabled in the Postfix SMTP server, so no difference to plain Postfix is visible. Explicitly set smtpd_use_tls and smtp_use_tls to yes. Add your SERVER IP to mynetworks and your DOMAIN to mydestination.
    # TLS parameters
    ...
    smtpd_use_tls = yes
    smtp_use_tls = yes
    ...
    # Add DOMAIN to mydestination
    mydestination = $myhostname, postcodejobs, localhost.localdomain, localhost, my-domain.be
    # Add SERVER IP to mynetworks
    mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 XX.XXX.XXX.XX
    ...
    # per domain outgoing IP, uncomment it if needed
    # sender_dependent_default_transport_maps = regexp:/etc/postfix/sdd_transport_maps.regexp # can also /etc/postfix/sender_map
    ...
    # DKIM
    milter_default_action = accept
    # Postfix ≥ 2.6 milter_protocol = 6, Postfix ≤ 2.5 milter_protocol = 2
    milter_protocol = 6
    smtpd_milters = inet:localhost:8891
    non_smtpd_milters = $smtpd_milters
    
    More about Postfix Configuration Parameters

  2. Postfix assign dedicated IP for outgoing mail sending
    Postfix allows to route mails through specific IPs depending on a senders domain or email address.
    This is achieved through sender_dependent_default_transport_map.
    Next we create sender transport mapping in a new file /etc/postfix/sdd_transport_maps.regexp. This file contain a regular expression matching the domain with smtp transport to use.

    /@mydomain\.be/                 smtp_be:
    /@myotherdomain\.ru/            smtp_ru:
    
  3. Now, add transports for them in master.cf:

    smtp_be  unix -       -       n       -       -       smtp
        -o syslog_name=mydomain
        -o smtp_helo_name=mydomain.be
        -o smtp_bind_address=XX.XX.XXX.XX
    smtp_ru  unix -       -       n       -       -       smtp
        -o syslog_name=myotherdomain
        -o smtp_helo_name=myotherdomain.ru
        -o smtp_bind_address=XX.XX.XXX.XX
    
    Don’t to forget uncomment sender_dependent_default_transport_map in main.cf.

  4. Restart postfix to apply the settings.

    sudo service postfix restart
    

Add SPF record is a type of DNS TXT record


To see server IP4 and IP6 we can run: ip addr.
Let’s begin with SPF, Sender Policy Framework. It is a mechanism to tell what hosts are allowed to send emails from your Email server. This will help your Emails to avoid being flagged as SPAM.

To implement it, add this TXT record to your DNS.

NameRecord TypeValue
@TXTv=spf1 a mx ip4:44.49.444.57 ip6:3b24:3f0:c0c:a88b::3 ~all

More about SPF Record Syntax

Add DKIM record is a type of DNS TXT record


DomainKeys Identified Mail (DKIM) combines several existing antiphishing and antispam methods to improve the quality of the classification and identification of legitimate e-mail. Instead of the traditional IP-address to determine the message sender, DKIM adds a digital signature associated with the domain name of the organization. In tandem, DNS is used to publish TXT records with the public portion of the cryptographic certificate used for digital signing.

Get and display the Public Key:

sudo cat /etc/opendkim/keys/my_selector.txt
# Output, we copy the highlighted part.
my_selector._domainkey       IN      TXT     ( "v=DKIM1; h=sha256; k=rsa; s=email; "
          "p=[...]"
          "[...]"
          "[...]==" )  ; ----- DKIM key my_selector for my-domain.com
NameRecord TypeValue
my_selector._domainkeyTXTv=DKIM1; k=rsa; s=email; p=MIIBIjANBg…NqQIDAQAB

More about DKIM Signature explained

Add DMARC record is a type of DNS TXT record


DMARC, which stands for “Domain-based Message Authentication, Reporting & Conformance”, is an email authentication, policy, and reporting protocol. It builds on the widely deployed SPF and DKIM protocols, adding linkage to the author (“From:”) domain name, published policies for recipient handling of authentication failures, and reporting from receivers to senders, to improve and monitor protection of the domain from fraudulent email.

NameRecord TypeValue
_dmarcTXTv=DMARC1; p=none

More about DMARC Record Syntax

Testing


opendkim-testkey verifies the setup of signing and verifying (private and public) keys for use with opendkim.
The test program will read a domain name and selector from the command line, configuration file or a key table, then query and parse the resulting DKIM key(s), reporting any errors found.

If a key path is also provided, the test program will read the private key named and attempt to confirm that the private key specified by keypath (or in the key table) and the public DKIM key retrieved match.
We run opendkim-testkey:

opendkim-testkey -d my-domain.be -s my_selector -vvv
or with dig
dig myselector._domainkey.my-domain.be TXT +dnssec

The output will be as follows:

opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: key loaded from /etc/opendkim/keys/my_selector.private
opendkim-testkey: checking key 'my_selector._domainkey.my-domain.be'
opendkim-testkey: key secure
opendkim-testkey: key OK

Use Mail Tester web service:

This service provides you with an email address to send an email from your email server for analysis. It is a very powerful audit tool, which provides a lot of information in the report.

Recources:

Comments

Popular posts from this blog

Installing the Certbot Let’s Encrypt Client for NGINX on Amazon Linux 2

psql: error: connection to server at "localhost" (127.0.0.1), port 5433 failed: ERROR: failed to authenticate with backend using SCRAM DETAIL: valid password not found

Deploy Nuxt.js app using Apache 2