CentOS Stream release 8でDKIM認証に対応してみた

2024年2月21日

はじめに

2023年10月にGoogleが新たなメール送信者ガイドラインを発表しました。

2024年2月以降、SPF/DKIMによるメール認証をしていないメールは、Gmailへメールが届かなくなる可能性があり、Gmailアカウントへ1日5000件以上メールを送信する企業は、SPF/DKIMに加えてDMARCの3つへ対応する必要があります。

対応しない場合、こちらも同様にメールが届かなくなる可能性があります。

本、ブログでは、CentOS Stream release 8サーバにインストールしているPostfixをOpenDKIMを使用してDKIM認証に対応させ、DNS TXTレコードでDMARCに対応します。

SPF認証はすでに対応しておりますので設定しているレコードを後ほど記載します。

SPF、DKIM、DMARCなどの用語については、以下サイトに記載がございますので、気になる方はご参照ください。

opendkimのインストール

メール送信時にメールヘッダにDKIM署名を付加してくれる機能をインストールします。

opendkimは標準レポジトリに存在しませんのでEPELレポジトリよりインストールします。

rpm -q epel-release

epel-release-8-8.el8.noarch

 →EPELレポジトリがインストールされています。(されていない場合、dnf install epel-releaseでインストール可。)

8系OSでは、opendkim-toolsという、DKIMに必要な、公開鍵と秘密鍵を生成する機能と一緒にインストールします。

dnf install opendkim opendkim-tools --enablerepo=epel

・・・[中略]
============================================================================================================================================================================
 パッケージ                                    アーキテクチャー                   バージョン                                    リポジトリー                          サイズ
============================================================================================================================================================================
インストール:
 opendkim                                      x86_64                             2.11.0-0.34.el8                               epel                                  244 k
 opendkim-tools                                x86_64                             2.11.0-0.34.el8                               epel                                   84 k
・・・[中略]

rpm -qコマンドで念の為、インストールされたことを確認します。

rpm -q opendkim opendkim-tools

opendkim-2.11.0-0.34.el8.x86_64
opendkim-tools-2.11.0-0.34.el8.x86_64

opendkimキーペア作成

メール送信時に秘密鍵を使用し署名されたメールを受信側で公開鍵が登録されているDNSサーバを参照し、メール認証を実施します。

この時に必要となるキーペア作成となります。

キーペア保存用ディレクトリを作成します。

これは任意ですが、ドメイン別に分かりやすくするための措置です。

mkdir /etc/opendkim/keys/mail.dev.sharemyknowledge.jp
 →送信元ドメインは「mail.dev.sharemyknowledge.jp」を使用します。

秘密鍵&公開鍵作成

先ほどインストールした、opendkim-genkeyコマンドを使用します。

opendkim-genkey -D /etc/opendkim/keys/mail.dev.sharemyknowledge.jp/ -d mail.dev.sharemyknowledge.jp -s 240128 -b 2048

  • オプション説明
オプション意味
-Dキーペアを保存するディレクトリを指定します。デフォルトは、カレントディレクトリです。
-d署名を行うドメインを指定します。
-s生成されたキーペアのセレクター名を指定します。一般的に日付を指定することが多いようです。メッセージ署名に使われる特定の公開鍵を識別するために使用されます。
-b生成する秘密鍵のキーサイズを指定します。デフォルトは1024です。セキュリティ上の理由から2048ビット指定とすることを推奨します。

作成されたキーペアを確認します。

  • .privateとつくものが秘密鍵です。
  • .txtとつくものが公開鍵です。
    • こちらにDNSへ登録するレコードが記載されます。

ls -la /etc/opendkim/keys/mail.dev.sharemyknowledge.jp/

合計 8
drwxr-xr-x 2 root root       46  1月 28 17:58 .
drwxr-x--- 3 root opendkim   41  1月 28 17:39 ..
-rw------- 1 root root     1675  1月 28 17:58 240128.private
-rw------- 1 root root      511  1月 28 17:58 240128.txt

chown -R opendkim. /etc/opendkim/keys/mail.dev.sharemyknowledge.jp
 →opendkimからファイルへアクセスできるよう権限を変更します。

所有者、グループが、opendkimになったことを確認します。

ls -lad /etc/opendkim/keys/mail.dev.sharemyknowledge.jp/*

-rw------- 1 opendkim opendkim 1675  1月 28 17:58 /etc/opendkim/keys/mail.dev.sharemyknowledge.jp/240128.private
-rw------- 1 opendkim opendkim  511  1月 28 17:58 /etc/opendkim/keys/mail.dev.sharemyknowledge.jp/240128.txt

 →opendkimに変更されたことが確認できます。

DNS設定

登録するDNSレコードを確認します。

cat /etc/opendkim/keys/mail.dev.sharemyknowledge.jp/240128.txt

240128._domainkey       IN      TXT     ( "v=DKIM1; k=rsa; "
          "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA33yXYgq35Tax7KfDtWF1p1jRG3azjW6lv5RTwTSeEv7HdL0nN9Y12c3Nec00sBogtPuC7CZrrJtzWB/4FwQFYnDHyFyyrI0ogKyQnLujmNIP2Q1QibEtiRB1qL9wJoVONT+kXFixQH8OVMn8+8w99dPGmNOwhEgdlxMTS8YZyq0MnZtfEkIwnr3oJfWXu6Ft4DP3seJxH9Jj2B"
          "qRAWHf+GjtMSUbSvvbLLlfJGpQU02lUKP6D08Wbwh8h+cv17Vb7bcBlbHNrJFc6IauV7tt+RXyhetq67m2FGchkfSM3q1drSJPzQcOFYJFRTpDeSxmIbkRlQz5Rb8TofBbMKJvrwIDAQAB" )  ; ----- DKIM key 240128 for mail.dev.sharemyknowledge.jp

DNS登録の際の注意、 240128._domainkey となっておりますが、サブドメインを使用している場合は、 240128._domainkey.mail.dev とするようにします。

  • 公開鍵に含まれる内容
内容意味
v=DKIM1キーレコードのバージョン番号となり、指定する場合は、「DKIM1」となります。
k=rsa鍵の形式となり、電子署名作成の差異に利用できるハッシュの方式を指定します。DKIMではRSA形式のみサポートしています。
p=….公開鍵データとなり、鍵データはBase64でエンコードされたものを記載します。opendkimによって生成されたものをそのまま指定します。

登録するレコード内容は以下となります。

240128._domainkey.mail.dev.sharemyknowledge.jp. TXT
"v=DKIM1; k=rsa; " "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA33yXYgq35Tax7KfDtWF1p1jRG3azjW6lv5RTwTSeEv7HdL0nN9Y12c3Nec00sBogtPuC7CZrrJtzWB/4FwQFYnDHyFyyrI0ogKyQnLujmNIP2Q1QibEtiRB1qL9wJoVONT+kXFixQH8OVMn8+8w99dPGmNOwhEgdlxMTS8YZyq0MnZtfEkIwnr3oJfWXu6Ft4DP3seJxH9Jj2B" "qRAWHf+GjtMSUbSvvbLLlfJGpQU02lUKP6D08Wbwh8h+cv17Vb7bcBlbHNrJFc6IauV7tt+RXyhetq67m2FGchkfSM3q1drSJPzQcOFYJFRTpDeSxmIbkRlQz5Rb8TofBbMKJvrwIDAQAB"

※DNSサービスによって登録の仕方が異なる場合がございますのでご注意ください。

DNSの制約上、255文字以下にレコードを抑える必要がありますので分割して登録するようにします。

さくらのドメインを使用している場合ドメインコントロールパネルより下記のように分割して登録します。

レコード値登録画面で、分割部分を改行して登録することで分割とみなすみたいです。


  • DNS編集

画像中、赤、青、緑枠線で各改行してレコードを入れている画像になります。


  • DNS編集後

画像中、赤、青、緑枠線で、DNSレコード登録後の画面になります。

レコードは、一行に連結されて表示されます。


登録後、下記のようにレコードを引ければ問題ないです。

dig +short 240128._domainkey.mail.dev.sharemyknowledge.jp txt

"v=DKIM1; k=rsa; " "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA33yXYgq35Tax7KfDtWF1p1jRG3azjW6lv5RTwTSeEv7HdL0nN9Y12c3Nec00sBogtPuC7CZrrJtzWB/4FwQFYnDHyFyyrI0ogKyQnLujmNIP2Q1QibEtiRB1qL9wJoVONT+kXFixQH8OVMn8+8w99dPGmNOwhEgdlxMTS8YZyq0MnZtfEkIwnr3oJfWXu6Ft4DP3seJxH9Jj2B" "qRAWHf+GjtMSUbSvvbLLlfJGpQU02lUKP6D08Wbwh8h+cv17Vb7bcBlbHNrJFc6IauV7tt+RXyhetq67m2FGchkfSM3q1drSJPzQcOFYJFRTpDeSxmIbkRlQz5Rb8TofBbMKJvrwIDAQAB"

ついでにDMARCレコードも登録します。

登録する内容としては以下となります。

_dmarc.mail.dev.sharemyknowledge.jp TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc-rua@sharemyknowledge.jp; ruf=mailto:dmarc-ruf@sharemyknowledge.jp; fo=1"
  • レコード説明
内容意味
v=DMARC1バージョン番号となり、DMARC1を指定します。
p=…メール受信者に対して認証が失敗した場合の処理動作を要求するものです。
none:特に何もしない
quarantine:認証に失敗した場合不審なメールとして扱う
reject:認証に失敗した場合 (SMTP 上で) メール拒否
上記、いづれかを指定します。
rua集約レポートの送り先を指定します。受信側が受け取ったメールの認証結果を集計したレポートとなります。
ruf失敗レポートの送り先を指定します。DMARC認証に失敗した個々のメールについて詳細情報を通知するレポートとなります。
fo失敗レポートのオプションとなります。
値 0:すべての認証が pass でなかった場合に失敗レポートを生成する
値 1:いづれかの認証が pass でなかった場合に失敗レポートを生成する
値 d:DKIMの署名検証が失敗した場合に失敗レポート生成する
値 s:SPFの検証が失敗した場合に失敗レポートを生成する
上記、いづれかを指定します。

※DMARCレポートを外部委譲、DMARCに指定したドメインは無関係のドメインを rua や ruf に指定する場合、レポートの移譲先ドメインに委譲元のドメインを示す必要があります。

※Googleでは、1日に1回レポートを送信する仕様となっているようです。

例:「 example.jp._report._dmarc.example.com IN TXT "v=DMARC1"

DMARCレコードの登録が完了したら、引けるか確認します。

dig +short _dmarc.mail.dev.sharemyknowledge.jp txt

"v=DMARC1; p=quarantine; rua=mailto:dmarc-rua@sharemyknowledge.jp; ruf=mailto:dmarc-ruf@sharemyknowledge.jp; fo=1"

 →上記のように引くことができれば問題ないです。

冒頭で設定しているSPFレコードを記載しますとしていましたので紹介します。

設定しているSPFレコードは下記の通りとなります。

dig +short mail.dev.sharemyknowledge.jp txt

"v=spf1 +mx a:dev.sharemyknowledge.jp a:mail.dev.sharemyknowledge.jp a:www5126.sakura.ne.jp a:116-80-41-59.indigo.static.arena.ne.jp +ip4:116.80.41.59 -all"

 →本記事では詳しく解説しませんが参考になれば幸いです。

opendkim設定ファイル変更

opendkimの認証設定などする必要がありますので設定変更していきます。

設定変更の前に念の為、バックアップを取っておきます。

cp -p /etc/opendkim.conf /etc/opendkim.conf.org
cp -p /etc/opendkim.conf /etc/opendkim.conf_$(date +%Y%m%d)

主な変更箇所は以下の通りとなります。

@@ -36,7 +36,7 @@
 ##  Selects operating modes. Valid modes are s (sign) and v (verify). Default is v.
 ##  Must be changed to s (sign only) or sv (sign and verify) in order to sign outgoing
 ##  messages.
-Mode   v
+Mode   s

 ##  Log activity to the system log.
 Syslog yes
@@ -53,8 +53,8 @@
 UserID opendkim:opendkim

 ##  Create a socket through which your MTA can communicate.
-#Socket        inet:8891@localhost
-Socket local:/run/opendkim/opendkim.sock
+Socket inet:8891@localhost
+#Socket local:/run/opendkim/opendkim.sock

 ##  Required to use local socket with MTAs that access the socket as a non-
 ##  privileged user (e.g. Postfix)
@@ -76,7 +76,7 @@

 ##  Add a DKIM-Filter header field to messages passing through this filter
 ##  to identify messages it has processed.
-SoftwareHeader yes
+SoftwareHeader no

 ## SIGNING OPTIONS

@@ -96,17 +96,17 @@

 ##  Gives the location of a private key to be used for signing ALL messages. This
 ##  directive is ignored if KeyTable is enabled.
-KeyFile        /etc/opendkim/keys/default.private
+#KeyFile       /etc/opendkim/keys/default.private

 ##  Gives the location of a file mapping key names to signing keys. In simple terms,
 ##  this tells OpenDKIM where to find your keys. If present, overrides any KeyFile
 ##  directive in the configuration file. Requires SigningTable be enabled.
-# KeyTable     /etc/opendkim/KeyTable
+KeyTable       /etc/opendkim/KeyTable

 ##  Defines a table used to select one or more signatures to apply to a message based
 ##  on the address found in the From: header field. In simple terms, this tells
 ##  OpenDKIM how to use your keys. Requires KeyTable be enabled.
-# SigningTable refile:/etc/opendkim/SigningTable
+SigningTable   refile:/etc/opendkim/SigningTable

 ##  Identifies a set of "external" hosts that may send mail through the server as one
 ##  of the signing domains without credentials as such.
  • 変更点説明
変更箇所意味
Mode動作モードを選択します。有効なモードは s (署名者) と v (検証者) です。
デフォルトでメール受信時の確認 v になっていますが、送信時の署名のみを行いたいので、 s を指定します。
Socket8系OSでインストールされるopendkimはデフォルトで、unixソケットからの通信となっていますので、ポートをlistenする形式に変更しています。
postfixからポートに対して通信することで署名を行います。
SoftwareHeader「DKIM-Filter」ヘッダーフィールドをメールヘッダに追加するか選択できます。
デフォルトで追加されるようになっていますのでセキュリティ上、無効にしています。
KeyFile利用する秘密鍵ファイルを指定しますが、KeyTableにて設定しますのでここではコメントアウトし無効としています。
keyTable利用する秘密鍵を指定しますので、ファイルから読み込むよう、アンコメントアウトし設定を有効化しています。
SigningTable電子署名を行う送信元アドレスを指定しますので、ファイルから読み込むよう、アンコメントアウトし設定有効化しています。

その他、パラメータとして、「ExternalIgnoreList」、「InternalHosts」、「TrustedHosts」がありますが、localhostからの認証はデフォルトで許可されるため変更は行わないものとします。

KeyTable設定変更

秘密鍵を指定しますので、設定変更前にバックアップを取っておきます。

cp -p /etc/opendkim/KeyTable /etc/opendkim/KeyTable.org
cp -p /etc/opendkim/KeyTable /etc/opendkim/KeyTable_$(date +%Y%m%d)

記述形式は、「 [セレクタ名]._domainkey.[ドメイン名] [ドメイン名]:[セレクタ名]:[秘密鍵へのパス] 」となります。

vi /etc/opendkim/KeyTable

240128._domainkey.mail.dev.sharemyknowledge.jp mail.dev.sharemyknowledge.jp:240128:/etc/opendkim/keys/mail.dev.sharemyknowledge.jp/240128.private

 →「 #default._domainkey 」の上側に記載します。

SigningTable設定変更

署名を行うドメインを記載する必要がありますので設定変更前にバックアップを取っておきます。

cp -p /etc/opendkim/SigningTable /etc/opendkim/SigningTable.org
cp -p /etc/opendkim/SigningTable /etc/opendkim/SigningTable_$(date +%Y%m%d)

記述形式は、「 *@[ドメイン名] [セレクタ名]._domainkey.[ドメイン名] 」となります。

vi /etc/opendkim/SigningTable

*@mail.dev.sharemyknowledge.jp 240128._domainkey.mail.dev.sharemyknowledge.jp

 →「 #*@example.com default 」の上側に記載します。

opendkim起動

一連のopendkim設定が完了しましたので起動確認を行います。

起動確認と共に、起動起動の有効化も実施しています。

systemctl --now enable opendkim

Created symlink /etc/systemd/system/multi-user.target.wants/opendkim.service → /usr/lib/systemd/system/opendkim.service.

後に設定するpostfixからopendkimと通信を実施するため、opendkimがlistenしていることを確認します。

netstat -nlp | grep opendkim

tcp        0      0 127.0.0.1:8891          0.0.0.0:*               LISTEN      900205/opendkim

 →opendkimがlistenしていることが確認できます。

Postfix設定変更

SMTP接続時にDKIMを利用する設定パラメータを追記します。

設定は、最下行に追記しますので変更前に設定ファイルのバックアップを取得します。

cp -p /etc/postfix/main.cf /etc/postfix/main.cf_$(date +%Y%m%d)

vi /etc/postfix/main.cf

# DKIM Settings
smtpd_milters = inet:127.0.0.1:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept
  • 変更点説明
変更箇所意味
smtpd_milterssmtpdが利用するmilterを指定を指定します。
non_smtpd_milterssmtpd以外が利用するmilterを指定します。
milter_default_actionmilterがメールを受け取った時のデフォルトの挙動を指定します。

postfix check
 →postfix構文チェックを行います。何も出力がなければ問題ありません。

systemctl restart postfix
 →設定変更を適用するため、サービス再起動を実施します。reloadでも適用可能です。

動作確認

以下、PHPプログラムよりメール送信テストを行います。

$envelopeSender$headers = "From: 項目をDKIMに登録したドメインのメールアドレスを指定します。

$recipient に送信したい宛先アドレスを指定します。

<?php

// Postfix config
$smtpHost = "localhost";
$smtpPort = 25;

// Envelope sender
$envelopeSender = "no-reply@mail.dev.sharemyknowledge.jp";

// Recipient
$recipient = "{宛先アドレス}";

// Email contents
$subject = "Test message from PHP";
$body = "This is a test message sent via Postfix";

// Headers
$headers = "From: no-reply@mail.dev.sharemyknowledge.jp";

// Connect to Postfix
$smtp = fsockopen($smtpHost, $smtpPort, $errno, $errstr, 30);

// Envelope sender
fputs($smtp, "EHLO localhost\r\n");
fputs($smtp, "MAIL FROM:<$envelopeSender>\r\n");

// Recipient
fputs($smtp, "RCPT TO:<$recipient>\r\n");

// Data
fputs($smtp, "DATA\r\n");

// Headers & body
fputs($smtp, "Subject: $subject\r\n");
fputs($smtp, "$headers\r\n\r\n");
fputs($smtp, "$body\r\n.\r\n");

// Quit
fputs($smtp, "QUIT");
fclose($smtp);

?>

送信後、以下のようにしメールログで「 DKIM-Signature field added 」と出ることを確認します。

Jan 29 07:01:44 dev opendkim[904017]: 452245C0EF3F: DKIM-Signature field added (s=240128, d=mail.dev.sharemyknowledge.jp)
Jan 29 07:01:44 dev postfix/qmgr[904124]: 452245C0EF3F: from=<no-reply@mail.dev.sharemyknowledge.jp>, size=473, nrcpt=1 (queue active)

送信元が異なるアドレス等で送信した場合でgmail宛てに送信した場合、DMARCにより隔離されて送信された旨のログが確認できます。

Jan 30 03:44:52 dev opendkim[904017]: 8B3D85C0B039: no signing table match for '***@yahoo.co.jp'
Jan 30 03:44:52 dev postfix/qmgr[951349]: 8B3D85C0B039: from=<no-reply@mail.dev.sharemyknowledge.jp>, size=466, nrcpt=1 (queue active)
Jan 30 03:44:54 dev postfix/smtp[961648]: 8B3D85C0B039: to=<***@gmail.com>, relay=***.google.com***:25, delay=1.8, delays=0.02/0.02/0.84/0.88, dsn=2.0.0, status=sent (250 2.0.0 OK DMARC:Quarantine *** - gsmtp)
  • gmail宛てに送信し、DMARC、DKIM認証、SPF認証が通っていることが確認できました。


  • gmail宛てに送信し、SPF認証をpassしdmarcが失敗となりましたが、quarantineを指定しているため疑わしいメールとして受信されていることを確認しました。


おわりに

いかがでしたでしょうか。

DKIM対応、意外と大変でしたが無事に対応することが出来ました。

本記事が他の方のお役にたてれば光栄です。