Mail server_DKIM signing - SomethingWithHorizons/mailserver GitHub Wiki

DKIM is an Internet Standard that enables a person or organisation to associate a domain name with an email message. This, in effect, serves as a method of claiming responsibility for a message. At its core, DKIM is powered by asymmetric cryptography. The sender's Mail Transfer Agent (MTA) signs every outgoing message with a private key. The recipient retrieves the public key from the sender's DNS records and verifies if the message body and some of the header fields were not altered since the message signing took place.

Procedure

  1. Install OpenDKIM, its tools, and a library providing MySQL backend support:

    apt install opendkim opendkim-tools libopendbx1-mysql
    
  2. Add following MySQL table to store DKIM signatures in relation to their domains:

    CREATE TABLE `mailserver`.`dkim` (
      `id` INT(10) UNSIGNED NOT NULL auto_increment,
      `domain` VARCHAR(63) COLLATE utf8_unicode_ci NOT NULL,
      `selector` VARCHAR(127) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'mail',
      `private_key` TEXT COLLATE utf8_unicode_ci NOT NULL,
      `public_key` TEXT COLLATE utf8_unicode_ci NOT NULL,
      PRIMARY KEY (`id`),
      INDEX (`domain`),
      UNIQUE (`domain`, `selector`),
      CONSTRAINT `dkim_domain_domains_name` 
        FOREIGN KEY (`domain`) REFERENCES `domains` (`name`) 
          ON DELETE CASCADE ON UPDATE CASCADE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    
  3. Edit /etc/opendkim.conf to enable MySQL retrieval of IDs (linked to the individual domains) from the DKIM table and relate them to the corresponding key. Also the default (local file based) communication socket is swapped for an ip based socket as an entry point for postfix' signature key requests:

      # Sign for example.com with key in /etc/dkimkeys/dkim.key using
      # selector '2007' (e.g. 2007._domainkey.example.com)
      #Domain                 example.com
      #KeyFile                /etc/dkimkeys/dkim.key
      #Selector               2007
    + SigningTable dsn:mysql://mailadmin:<MYSQL PASSWORD>@127.0.0.1/mailserver/table=dkim?keycol=domain?datacol=id
    + KeyTable     dsn:mysql://mailadmin:<MYSQL PASSWORD>@127.0.0.1/mailserver/table=dkim?keycol=id?datacol=domain,selector,private_key
    
      # 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                 inet:8892@localhost
    + Socket                  inet:[email protected]
    - Socket                  local:/var/run/opendkim/opendkim.sock
    + #Socket                 local:/var/run/opendkim/opendkim.sock
    

    :warning: Replace <MYSQL PASSWORD> by the password defined during database preparation.

  4. Tell postfix to use opendkim:

    postconf -e "milter_protocol = 2"
    postconf -e "milter_default_action = accept"
    postconf -e "smtpd_milters = inet:127.0.0.1:8892"
    postconf -e "non_smtpd_milters = inet:127.0.0.1:8892"
    
  5. Restart both opendkim and postfix to effectuate the changes:

    service opendkim restart
    service postfix restart
    
  6. Generate DKIM key for each hosted domain that has to be signed:

    # Download https://raw.githubusercontent.com/SomethingWithHorizons/mailserver/master/generate-dkim.sh
    wget -O /usr/local/bin/generate-dkim.sh https://raw.githubusercontent.com/SomethingWithHorizons/mailserver/master/generate-dkim.sh
    
    # generate key
    bash /usr/local/bin/generate-dkim.sh --domain=example.org
    

    :warning: Replace example.org by your domain.

    :warning: Ensure to follow instructions on-screen and update your DNS settings as instructed!

  7. Create /etc/systemd/system/opendkim.service.d/opendkim_timeout_workaround.conf to prevent Opendkim start-up failure due to MariaDB not being available at the time of opendkim service start-up:

    + [Service]
    + RestartSec=5
    

    :warning: WARNING: This regards a "quick fix". A more solid solution would be to configure Opendkim to explicitly wait on as successful MariaDB servic start-up!

References

https://fossies.org/linux/opendkim/opendkim/README.SQL