■追記 buster の対応について

SPF は DNS の設定だけですむので簡単ですが、DKIM についてはなんとなく敷居が高い感じがして手を付けていませんでした。結構有名な上場企業(しかもSIer)でもメールヘッダーを見ると DKIM のシグネチャーが付いてないことが多いです。

今回はメールサーバのお引っ越しにあわせて、DKIM の実装とちょっとだけ DMARC の対応をしてみました。なかなか、仕組みがよく解らなくて時間が掛かりましたが、なんとか動くようになったので設定方法を書いてみます。
※SPFについては既にDNSの設定が終わっている前提で、今回は触れません。

 前提条件・環境

  • Debian GNU/Linux 8.0 Jessie
  • postfix 2.11.3-1
  • sasl2-bin 2.1.26.dfsg1-13+deb8u1
  • opendkim 2.9.2-2

postfix は、chroot モードで動かしていて、saslauthd は既に稼働しているとします。
また DKIM は postfix 単体では動作しないので、インターネット側に公開されている権威 DNS サーバの設定が必要です。また、DMARC の設定も DNS サーバの設定追加が必要です。

今回例としてあげるサーバは、2つのドメインを受け持っていますが、単にドメイン名が違うだけでアカウントは一緒です。つまり、takahashi@lonnie.co.jp と takahashi@it-tutor.jp は同じアカウントとして扱うというちょっと手抜きの構成です。しかし、DKIM のシグネチャーは別々に設定するという方針にしました。

 Tips

DNS の設定変更を行うので、設定に先立って権威 DNS の TTL を600秒程度に変更しておきます。これを忘れると、DKIM の設定終了後のテストを数時間待つ羽目になります。

 opendkim のインストールと設定

aptitude install opendkim opendkim-tools

以上で必要なモジュールは全てインストールされます。

ここで注意することは、一般的な Debian パッケージとは異なり、サービスの起動に必要なコンフィグは最低限のものしか用意されません。もちろん、/usr/share/doc/opendkim/examples/ に置いてある opendkim.conf.sample.gz を解凍すると opendkim.conf のサンプルファイルが出てくるのですが、内容を読んでも初見だとさっぱりです??

ネットで色々調べたり、実際に設定値を入れてみたり、試行錯誤した結果、私が理解している内容を簡単に書いてみます。

1.インストールしただけでは動かない(当たり前)
2.DKIM には opendkim.conf とは別に、設定用のディレクトリと設定ファイルが必要。
3.設定ファイルには DNS サーバで使う TXT レコードを記述したファイルがある。
4.複数の設定ファイルを識別する為にセレクターという概念(名称)がある。
5.DKIM がメールヘッダーに署名する時に必要な秘密キー・公開キーの他に、 key.table, signing.table,  trusted.hosts という3つの設定ファイルが必要。

# Sign for example.com with key in /etc/mail/dkim.key using
# selector '2007' (e.g. 2007._domainkey.example.com)

というコメントに従って、/etc/mail というディレクトリを作成し、その中に keys というディレクトリ(この中に秘密キーを入れる)を作成します。次に、key.table, signing.table, trusted.hosts の3つの設定ファイルを作成します。

それでは最初に、秘密キーと公開キーを作成します。

# cd /etc/mail/keys
# opendkim-genkey -b 2048 -s 20161112lny -d lonnie.co.jp
# opendkim-genkey -b 2048 -s 20161112itt -d it-tutor.jp

-b はキーの長さ、-s はセレクター名、-d はドメイン名(@より右側)です。
このコマンドを実行すると、

20161112lny.private
20161112lny.txt
20161112itt.private
20161112itt.txt

このように4つのファイルが出来上がります。
.private は署名する時に使う秘密キー、.txt は DNS サーバに設定する公開キーですが、すぐに使える様に bind のフォーマットで書かれています。

次に3つの設定ファイルの内容です。

# cd /etc/mail
# cat signing.table
*@lonnie.co.jp  lonnie
*@it-tutor.jp   it-tutor

これは見ての通りで、どのようなメールアドレスに対してDKIMが署名をするかという設定です。
設定ファイルの右側には次に設定する key.table を参照するためのインデックスのようなもので、この識別名は1つの単語になっていれば任意に設定できます。

# cat key.table
lonnie          lonnie.co.jp:20161112lny:/etc/mail/keys/20161112lny.private
it-tutor        it-tutor.jp:20161112itt:/etc/mail/keys/20161112itt.private

key.table のフォーマットはこんな感じです。つまり、signing.table の設定行の右側に書いてある識別名と key.table の左側の識別名がペアになる感じです。key.table の右側は見ての通りで、『ドメイン名:セレクター名:秘密キーの場所』です。

# cat trusted.hosts
127.0.0.1
::1
localhsot
comet
comet.lonnie.co.jp
lonnie.co.jp
it-tutor.jp

trusted.hosts にはこのようにメールサーバの名称とドメイン名を記載しておきます。
作成した設定ファイルにパーミッションを設定します。

# cd /etc/mail
# chmod 644 *
# chown -R opendkim:opendkim *
# chmod 700 keys
# cd /etc/mail/keys
# chmod -R 600 *

最後に、/etc/opendkim.conf と /etc/default/opendkim の設定です。

# cat /etc/opendkim.conf
# 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                   002
# Sign for example.com with key in /etc/mail/dkim.key using
# selector '2007' (e.g. 2007._domainkey.example.com)
#Domain                 lonnie.co.jp
#KeyFile                /etc/mail/keys/20161026lny.private
#Selector               20161026lny
MultipleSignatures      yes
KeyTable                /etc/mail/key.table
SigningTable            refile:/etc/mail/signing.table
ExternalIgnoreList      /etc/mail/trusted.hosts
InternalHosts           /etc/mail/trusted.hosts

# Commonly-used options; the commented-out versions show the defaults.
Canonicalization        relaxed/simple
Mode                    sv
SubDomains              no
#ADSPAction             continue
# 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

# List domains to use for RFC 6541 DKIM Authorized Third-Party Signatures
# (ATPS) (experimental)
#ATPSDomains            example.com

今回は1つのサーバで複数のドメインを扱っているので、上記設定ファイルで Domain, KyeFile, Selector はコメントアウトしています。そのかわり、MultipleSignatures を yes として、

KeyTable                /etc/mail/key.table
SigningTable            refile:/etc/mail/signing.table
ExternalIgnoreList      /etc/mail/trusted.hosts
InternalHosts           /etc/mail/trusted.hosts

の設定を入れています。

また、Canonicalization    relaxed/simple は、どの程度メールヘッダーが変わってもOKにするかという大ざっぱな方針を意味するようです。Gmail は relaxed/relaxed と設定してありましたが、IIJ のメールサーバでは relaxed/simple になっていたので、こちらに習いました。

Mode はデフォルトでは v だけで、送られてきたメールの DKIM 署名のチェックだけを行いますが、今回は送信メールに自ら DKIM の署名をするので、 sv という Mode にします。

最後に、/etc/default/opendkim の設定です。

# cat /etc/default/opendkim
# Command-line options specified here will override the contents of
# /etc/opendkim.conf. See opendkim(8) for a complete list of options.
#DAEMON_OPTS=""
#
# Uncomment to specify an alternate socket
# Note that setting this will override any Socket value in opendkim.conf
#SOCKET="local:/var/run/opendkim/opendkim.sock" # default
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
#SOCKET="inet:54321" # listen on all interfaces on port 54321
#SOCKET="inet:12345@localhost" # listen on loopback on port 12345
#SOCKET="inet:12345@192.0.2.1" # listen on 192.0.2.1 on port 12345

Postfix が chroot を使っている時には /var/spool/postfix 内で完結しないといけないので、上記の設定となります。
次に、sasl の設定時と同じように、opendkim を postfix グループへ所属させます。

# adduser postfix opendkim

これまでの設定が終わりましたら、一度 service opendkim restart しておきます。

 追記 2019/09/16 Debian stretch (debian10) 対応について

jessie (Debian8) で、動いていた opendkim 関連の config は、基本的には何も触らなくても buster (Debian10) でも動作しますが、/etc/opendkim.conf に、下記の設定を追加してください。
【注意】今回の設定例において postfix は chroot で動いています。

Socket local:/var/spool/postfix/opendkim/opendkim.sock
PidFile /run/opendkim/opendkim.pid

この設定は、/etc/default/opendkim にも設定があります。しかし…

# Note that setting this will override any Socket value in opendkim.conf

と書いて有るので、設定はしなくて良いみたいです。
ですが、一応、/etc/default/opendkim も、同じ設定にしておきます。

RUNDIR=/run/opendkim
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=

■jessie の時は、pid ファイルも /var/spool/postfix/var/run に置いてありましたが、何故か buster では上記設定で動いています(謎

 ファイルやディレクトリのパーミッション

/var/spool/postfix/opendkim/ のパーミション

drwxr-xr-x 2 opendkim postfix 4.0K Sep 14 13:59 opendkim

/run/opendkim のパーミッション

drwxr-x--- 2 opendkim opendkim 60 Sep 14 13:59 opendkim

実は stretch 迄は、pid ファイルの場所が /var/run だったんですが、buster から /run に移ったようで、default のコンフィグで対応が終わってない package が結構あるようです。例えば、fail2ban を動かすと、ログに Warning がでます。

起動は出来るので、この辺の初期設定はそのうち解消(update)されるでしょうから、現段階では放置しています。

 DNSサーバの設定

インターネットから参照される権威 DNS サーバのゾーン情報に、DKIM と DMARC 関連の情報を追加します。
今回の例であれば、lonnie.co.jp のゾーン情報には、/etc/mail/keys/20161112lny.txt をそっくり貼付けます。次に、DKIM の署名を認証できなかった時にどうするか?の情報と DMARC のポリシーを書きます。

このような設定で bind を再起動すると、アンダーバーから始まるゾーン名について bind が文句を言ってきます。その場合は、/etc/bind/named.conf.local で、該当のドメイン名に対して、

zone    "lonnie.co.jp"   {
               check-names ignore;
               type master;
               file "lonnie.co.jp";
               };

check-names ignore; という行を追加してください。

_adsp._domainkey IN TXT “dkim=unknown” については、”dkim=unknown” の他に all とか discardable とかあるようですが、unknown にしておくのが安全なようです。
もう一つのゾーン情報(it-tutor.jp)も同様に /etc/mail/keys/20161112itt.txt を使って更新します。

設定を追加・変更した所をもう一度確認してから、service bind9 restart します。

一番最初に $TTL を600秒にしてあれば、約10分程度待てば新しいゾーン情報が参照できる筈なので、下記コマンドで動作チェックを行います。

# cd /etc/mail/keys
# opendkim-testkey -d lonnie.co.jp -s 20161112lny -k 20161112lny.private -vvv
opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: key loaded from 20161112lny.private
opendkim-testkey: checking key '20161112lny._domainkey.lonnie.co.jp'
opendkim-testkey: key not secure
opendkim-testkey: key OK

このように最後にOKと表示されると良いのですが、keys do not match とか表示される場合には、今迄の設定内容を見直してください。

 Postfix の設定

やっとここまで来ました。Postfix からは Milter 経由で opendkim と接続します。
Milter についてはこちらを参照してください。今回は詳しい説明は割愛します。
http://www.postfix-jp.info/trans-2.3/jhtml/MILTER_README.html

main.cf の設定を変更します。
smtpd_recipient_restrictions の設定より後ろの行に、以下の設定を追加します。

# Milter configuration
# OpenDKIM
milter_default_action           = accept
milter_protocol                 = 6
smtpd_milters                   = local:/opendkim/opendkim.sock
non_smtpd_milters               = local:/opendkim/opendkim.sock

この設定は、chroot を使っている時の設定です。もし、chroot を使っていない時には、local:/opendkim/opendkim.sock を、local:/var/spool/postfix/opendkim/opendkim.sock へ変更してください。
設定の追加が終わりましたら postfix stop → postfix start して、さぁ動作確認です。

Gmail のアカウントへ何かテストメールを送ってみます。

おっと、その前に Tips です。Gmail は、メールが送られてくる時に送信元のメールサーがTLS接続を使わないと赤い鍵マークが出てきます。もし、SMTP 接続で TLS を使う様に設定していない場合には、main.cf に smtp_tls_security_level = may を追加すると幸せになれます。

Gmail で受信後、メールのソースを表示してみてください。
下記画面のように PASS と表示されればOKです。

gmail_sample同様に、Gmail から何かメールを自アカウントへ送ってみて、メールヘッダーの詳細を確認してください。

Authentication-Results: comet.lonnie.co.jp; dkim=pass
    reason="2048-bit key; unprotected key"
    header.d=gmail.com header.i=@gmail.com header.b=zS3Vb0zz;
    dkim-adsp=pass; dkim-atps=neutral

※unprotected key という部分がちょっと謎ですが、これで dkim のチェックはOKです。

 追記 2022/11/19

気になったので、unprotected key について、ちょっと調べてみました。

Re: dkim=pass but unprotected

Dan Mahoney Mon, 17 May 2021 18:37:50 -0700
It’s not dnssec signed.

-Dan Mahoney

どうも dnssec に関係するメッセージみたいです。dnssec についてはまだ未対応というか勉強が出来ていないので、この辺の進展がありましたら、再度追記します。

DMARC に関しては、DNS にポリシーを書いただけで、送られてくるメールについてのチェックは出来ていません。Debianパッケージには opendmarc がありますので、これをインストールして設定する事になると思います。これは SPF についても同様で、送られてきたメールの SPF チェックもDNS の設定だけでは動作しませんので、次回はこのあたりを検証しようと思っています。