この記事について
| 環境 | AlmaLinux 9 + Postfix(旧CentOS 6.8時代のコマンドも併記) |
|---|---|
| 目的 | OpenDKIMを導入してDKIM署名 → DNS設定 → DMARC設定まで行う |
| 結果 | サーバーから送信したメールも、webフォーム経由のメールも DKIM: PASS になった |
つまずきポイント要約
途中でつまずいた点は以下の3つ。詳細は各セクションに記載。
- AlmaLinux 9 で opendkim のインストールが依存関係エラーで失敗 → crb リポジトリを有効化して解決
- opendkim-testkey が秘密鍵を見つけられない → KeyFile ではなく KeyTable 方式に変更して解決
- webフォーム経由のメールだけ DKIM: FAIL(body hash did not verify)→ PHP ファイルの改行コード(CRLF)が原因
参考サイト

DKIMのインストール
インストールできるかの確認
yum info opendkim
インストール
sudo yum install opendkim
つまずき①:AlmaLinux 9 でインストールに失敗する
事象:almalinux9 では一度失敗した。エラー内容は以下。
Error:
Problem: conflicting requests
- nothing provides libmilter.so.1.0()(64bit) needed by opendkim-2.11.0-0.36.el9.x86_64 from epel
- nothing provides libmemcached.so.11()(64bit) needed by opendkim-2.11.0-0.36.el9.x86_64 from epel
(try to add '--skip-broken' to skip uninstallable packages or '--nobest' to use not only best candidate packages)
原因:epel の opendkim が要求する依存パッケージ(libmilter, libmemcached)が、デフォルトで有効なリポジトリに存在しない。これらは crb(旧 PowerTools)リポジトリに入っている。
対処:crb リポジトリを有効化する。
sudo dnf config-manager --set-enabled crb
crb リポジトリが有効になったことを確認
sudo dnf repolist all
再度インストール
sudo yum install opendkim
インストールできているかの確認
yum list installed | grep opendkim
インストールによって opendkim ユーザが作成されているはず
$ id opendkim
uid=498(opendkim) gid=499(opendkim) 所属グループ=499(opendkim),12(mail)
インストールができたら鍵の生成を行う
鍵の生成
鍵を保存するディレクトリを作成
mkdir /etc/opendkim/keys/mydomain.com
opendkim-genkey が使えるかの確認
opendkim-genkey --help
なければ opendkim-tools をインストール
sudo yum install opendkim-tools
# -s はセレクタ(鍵の名前)
$ sudo opendkim-genkey -D /etc/opendkim/keys/mydomain.com/ -d mydomain.com -s default
default.private と default.txt の二つのファイルができていることを確認
$ sudo ls keys/mydomain.com
default.private default.txt
default.private(秘密鍵)default.txt(公開鍵)
opendkim からファイルにアクセスできるよう、所有者を変更
$ sudo chown -R opendkim:opendkim /etc/opendkim/keys/mydomain.com/
注意:秘密鍵の権限は緩すぎても opendkim がエラーを出す。600 にしておくのが安全。不用意に変更しない。
DNSの設定
DNSにTXTレコードを追加する。登録する内容は、さきほど生成された default.txt に書いてある。
$ sudo cat /etc/opendkim/keys/mydomain.com/default.txt
[sudo] password for user1:
default._domainkey IN TXT ( "v=DKIM1; k=rsa; "
"p=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ) ; ----- DKIM key default for mydomain.com
v=DKIM1は、DKIMのバージョン。k=rsaは、鍵のアルゴリズムがRSAであることを示す。p=xxxxxxは、公開鍵の値。
なお、本記事冒頭の参考ブログに書いてあったADSPレコードの登録は、すでに廃止された仕様なので現在は必要ない(下記IIJの記事を参照)。

DNSに反映されたかの確認
dig txt default._domainkey.mydomain.com
動作テスト
$ opendkim-testkey -d mydomain.com -s default -vvv #-vvvは詳細表示
つまずき②:opendkim-testkey が秘密鍵を見つけられない
事象:動作テストで以下のエラーが出る。
opendkim-testkey: /etc/opendkim/keys/default.private: stat(): No such file or directory
原因:opendkim-testkeyはデフォルトで/etc/opendkim/keys/直下を参照する。今回は鍵をドメイン名のサブディレクトリに置いたため、パスが一致していない。
対処:OpenDKIMの設定ファイル/etc/opendkim.confで鍵ファイルの場所を正しく指定する。編集前に念のため opendkim.conf をコピーしておく。
秘密鍵のパスの指定方法は KeyFile と KeyTable の2通りあり、いずれかを使う。KeyFile は単一ドメイン向け、KeyTable は1つのサーバーで複数のドメインやセレクタを運用する場合向け。今回は後々の拡張も考えて KeyTable を選択。以下のように書き換える。
KeyFile /etc/opendkim/keys/default.private
# KeyTable /etc/opendkim/KeyTable
↓↓↓ KeyFile を無効にして KeyTable を有効化
# KeyFile /etc/opendkim/keys/default.private
KeyTable /etc/opendkim/KeyTable
KeyTable に「セレクタ ドメイン:セレクタ名:秘密鍵のパス」を記述
#一行で
default._domainkey.mydomain.com mydomain.com:default:/etc/opendkim/keys/mydomain.com/default.private
再度テストして、エラーが出なければOK
$ opendkim-testkey -d mydomain.com -s default -vvv #-vvvがないとエラー以外何も出ない
KeyTable を使用する場合 SigningTable も必要なので有効にする
# SigningTable refile:/etc/opendkim/SigningTable
↓↓↓
SigningTable refile:/etc/opendkim/SigningTable
SigningTableの記述例。「このアドレスから送るメールは、この鍵で署名する」という対応表。
*@[ドメイン名] ._domainkey.[ドメイン名]
# 例 *はワイルドカードで、すべてのアドレスを意味する
*@mydomain.com default._domainkey.mydomain.com
その他 opendkim.conf の変更箇所。Mode sv は署名(s)と検証(v)の両方を行う設定。SoftwareHeader はバージョン情報をヘッダに出す設定なので、情報漏えい防止のため無効化。
Mode v
↓
Mode sv
SoftwareHeader yes
↓
SoftwareHeader no
# ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
↓
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
# InternalHosts refile:/etc/opendkim/TrustedHosts
↓
InternalHosts refile:/etc/opendkim/TrustedHosts
# OpenDKIMとPostfixの通信方法
# 今回はTCPソケット(inet:8891)を利用するので切り替える
#Socket inet:8891@localhost
Socket local:/run/opendkim/opendkim.sock
↓
Socket inet:8891@localhost
#Socket local:/run/opendkim/opendkim.sock
opendkim が起動しているか
service opendkim status
自動起動の確認
chkconfig --list opendkim #centOS6.8
もしくは
sudo systemctl is-enabled opendkim #almalinux9
サーバー再起動時の自動起動
sudo chkconfig opendkim on #centOS6.8
もしくは
sudo systemctl enable opendkim #almalinux9
postfixとDKIMを連携させる
postfix 側にも、メールを milter(OpenDKIM)に渡すための設定が必要。main.cf の最下段に記述する。ポート番号は opendkim.conf の Socket で指定した 8891 に合わせる。
# DKIMと連携させるための記述
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept
設定のエラーチェック
postfix check
再起動して反映
sudo systemctl restart postfix
送信テスト
$ echo "テストメールです" | sendmail -t -f renraku@example.com test@gmail.com
届いたgmailのソースを見て DKIM:’PASS’ となっていれば成功
つまずき③:webフォーム経由のメールだけ DKIM:’FAIL’ になる
事象:コマンドからの送信テストは PASS するのに、運営サイトのwebフォームから送ったメールは DKIM:’FAIL’ となった。メールのソースを見ると body hash did not verify となっている。
原因:署名時と検証時で本文のハッシュ値が一致していない。調べると、改行コードが「\n」でなく「\r\n」になっているとこのエラーになるらしい。フォームのPHPファイルを確認すると、ファイル自体の改行コードがCRLFになっており、メール本文の文字列に生の改行(\nや\r\nのエスケープではなく、ソース上の物理的な改行)が入っていた。つまり本文にCRLFがそのまま混入していた。
対処:本文中のこの改行を削除したら DKIM:’PASS’ となった。
エラー解決参考

さくらのメールボックスのwebメールで送信するときのDKIM認証
ここまでの設定は、運営しているwebサーバーから送信したメールのDKIM認証のやり方。さくらのメールボックスのwebメールから送信する場合は、さくらのSMTPサーバーを経由するため、このサーバーでの署名は行われず、DKIM認証されない。経路上で実際にメールを送信するSMTPサーバーが署名を行う必要があるので、さくら側での設定が別途必要。
やり方のページ

上記URLを参考に、webサーバー上にある秘密鍵をさくらのメールボックスのSMTPサーバーにアップロードする。セレクタ名も同じにして設定を完了すれば、webメールやiphoneからの送信もDKIM認証が使えるようになる。
DMARCの設定
SPFとDKIMの設定が終わったらDMARCも設定する。DNSにTXTレコードを1つ追加するだけ。
ホスト名
_dmarc.<ドメイン名>
txtレコード。まずは p=none(監視のみ)で運用開始し、レポートを見て問題なければ quarantine や reject に引き上げる方針。
v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com
openDKIMをmonitの監視対象にする
opendkim が落ちるとメールが署名されなくなるので、monit で死活監視して自動復旧させる。monit の設定に以下を追加。
check process opendkim with pidfile /var/run/opendkim/opendkim.pid
start program = "/usr/sbin/service opendkim start"
stop program = "/usr/sbin/service opendkim stop"
if 5 restarts within 5 cycles then timeout
monitを再起動
$ sudo /sbin/service monit restart
確認
sudo monit summary
動作確認として、openDKIMを手動で停止し、monit が自動で再起動させるか見てみる。
$ sudo /sbin/service opendkim stop
