#author("2018-09-01T16:57:57+09:00","default:nowsky","nowsky")
*OpenDKIM [#w5fe9b98]
MTAにmilterとして組み込む事で、DKIMを実装出来るようになるプログラム。
メールの署名付与、署名検証が出来る。
メール送信者の詐称対策に有効なので、SPFと併せて実装しておいた方が良い。
#author("2018-09-01T18:34:09+09:00","default:nowsky","nowsky")
*policyd-spf [#yf2c1aa0]
メール受信時にPostfixでSPF検査を行う為のスクリプト。
設定変更が出来ないPerl版と、細かい変更が可能なPython版の2種類がある。
Postfixで使う時はポリシーチェックとしてスクリプトを呼び出す。

- 参考情報
[[OpenDKIM:+http://opendkim.org/]]
[[PostifxでDKIM認証する:+https://qiita.com/techno_officer/items/3c550d261b5a0c6df3a4]]
[[OpenDKIMを利用したメール認証 :+https://heavy-metal-explorer.com/open_dkim_setting/]]
[[Postfix SMTP アクセスポリシー委譲:+http://www.postfix-jp.info/trans-2.2/jhtml/SMTPD_POLICY_README.html]]
[[holly's wiki - policyd-spf-python:+https://sites.google.com/site/hollyroyaltea/home/mail/postfix/policyd-spf-python]]
~
*構築環境 [#he9feea4]
今回検証した環境はこちら
-debian 8.9 x86_64
-CentOS 7.4 x86_64
-debian 9.5 x86_64
-CentOS 7.5 x86_64
-openSUSE 42.3 x86_64
~

他には下の内容で構築メモを作成
-OpenDKIMは"127.0.0.1:TCP/10027"で待ち受ける
-汎用性を持たせる為、LocalSocketは今回利用しない
-送受信の署名付与/検証を実施する
-マルチドメインの検証に対応させる
~

ドメイン構成などは
-メール鯖のドメイン:hoge.org
-メール鯖のFQDN:mail.hoge.org
-メール鯖のIPアドレス:10.0.0.1
設定ファイル・スクリプト本体がディストリビューション毎に違うが、
設定と説明を統一化する為、同ファイル名のシンボリックリンクを作成する。
シンボリックリンクを作りたく無い時は、実ファイルPATHを直設定する。
~
*構築(Debian) [#c5dbbaa8]
*構築 [#b9907809]
&size(16){&font(b){1. インストール};};
Debianではopendkimとopendkim-toolsの二つをインストールする
デフォルトのリポジトリでインストール出来るので、apt-getを実行するのみとなる。
 # apt-get install opendkim opendkim-tools
~
インストールはディストリビューションによってパッケージ名に違いがある。
今回はパッケージ管理を利用してインストールするので各々の環境にあわせる。
- Debian
 # apt-get install postfix-policyd-spf-python
 # ln -s /etc/postfix-policyd-spf-python/policyd-spf.conf /etc/policyd-spf.conf
 # ln -s /usr/local/bin/policyd-spf /usr/bin/policyd-spf

&size(16){&font(b){2. 設定};};
既存のコンフィグは内容が書かれていない為、ディレクトリ含めて全て作成する必要がある。
また、一部設定がinitファイルに埋め込まれていたり、環境変数として固定化されている為、
埋め込まれた設定を無効化する事で通常のコンフィグから設定を読み込ませる様に変更する。
 # mkdir -p /etc/opendkim/cert
 # cd /etc/opendkim/cert
 # opendkim-genkey -D /etc/opendkim/cert -d mail.hoge.org -s 20170101 -b 2048
 # chown opendkim.root 20170101.private
 # chmod 400 20170101.private
~
#region(&color(#ff0000){設定内容};)
&size(14){&font(b){/etc/opendkim.conf};};
 # 細かい解説はopenSUSE版を参照
 ----
 [01] Syslog              yes
 [02] SyslogFacility      mail
 [03] SyslogSuccess       yes
 [04] LogWhy              yes
 [05] UMask               022
 [06] UserID              opendkim:opendkim
 [07] Socket              inet:10027@127.0.0.1
 [08] PidFile             /var/run/opendkim/opendkim.pid
 [09] KeyTable            refile:/etc/opendkim/KeyTable
 [10] SigningTable        refile:/etc/opendkim/SigningTable
 [11] ExternalIgnoreList  refile:/etc/opendkim/TrustedHosts
 [12] InternalHosts       refile:/etc/opendkim/TrustedHosts
 [13] Mode                sv
 [14] Canonicalization    relaxed/relaxed
 [15] MinimumKeyBits      1024
 [16] SignatureAlgorithm  rsa-sha256
 [17] SoftwareHeader      no
 [18] StrictHeaders       no
 [19] StrictTestMode      no
 [20] SubDomains          no
 
&size(14){&font(b){/etc/opendkim/KeyTable};};
 [セレクタ]._domainkey.[FQDN] [FQDN]:[セレクタ]:[秘密鍵]
 ---
 20170101._domainkey.mail.hoge.org mail.hoge.org:20170101:/etc/opendkim/cert/20170101.private
 
&size(14){&font(b){/etc/opendkim/SigningTable};};
 [署名対象のユーザ]@[FQDN] [セレクタ]._domainkey.[FQDN]
 ---
 *@mail.hoge.org 20170101._domainkey.mail.hoge.org
 
&size(14){&font(b){/etc/opendkim/TrustedHosts};};
 127.0.0.1
 10.0.0.1
 
&size(14){&font(b){/etc/default/opendkim};};
 # 全てコメントアウト
 ---
 #DAEMON_OPTS=""
 #SOCKET="local:/var/run/opendkim/opendkim.sock" # default
 #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
#endregion
~
*構築(CentOS) [#l382d25e]
&size(16){&font(b){1. インストール};};
CentOSの場合、OpenDKIMをyumでインストールするにはEPELリポジトリが必要となる。
EPEL自体もyumでインストール出来る為、今までの様にimport-keyする必要がなくなる。
 # yum install epel-release
 # yum --enablerepo=epel install opendkim
~
- CentOS
 # yum install pypolicyd-spf
 # ln -s /etc/python-policyd-spf/policyd-spf.conf /etc/policyd-spf.conf
 # ln -s /usr/libexec/postfix/policyd-spf /usr/local/bin/policyd-spf

&size(16){&font(b){2. 設定};};
他ディストリビューションと殆ど同じだが、一部設定は利用出来ないのでDisableにする。
また、sysconfigに埋め込まれている環境変数も必要無いので削除(未設定)にする。
 # mkdir /etc/opendkim/keys
 # cd /etc/opendkim/keys
 # opendkim-genkey -D /etc/opendkim/keys -d mail.hoge.org -s 20170101 -b 2048
 # chown opendkim.root 20170101.private
 # chmod 400 20170101.private
~
#region(&color(#ff0000){設定内容};)
&size(14){&font(b){/etc/opendkim.conf};};
 # 細かい解説はopenSUSE版を参照
 ----
 [01] PidFile             /var/run/opendkim/opendkim.pid
 [02] Mode                sv
 [03] Syslog              yes
 [04] SyslogFacility      mail
 [05] SyslogSuccess       yes
 [06] LogWhy              yes
 [07] UserID              opendkim:opendkim
 [08] Socket              inet:10027@127.0.0.1
 [09] Umask               022
 [10] SendReports         no
 [11] SoftwareHeader      no
 [12] Canonicalization    relaxed/relaxed
 [13] MinimumKeyBits      1024
 [14] KeyTable            refile:/etc/opendkim/KeyTable
 [15] SigningTable        refile:/etc/opendkim/SigningTable
 [16] ExternalIgnoreList  refile:/etc/opendkim/TrustedHosts
 [17] InternalHosts       refile:/etc/opendkim/TrustedHosts
 
 # 下記はコンフィグの最終行に追加
 ----
 [18] SignatureAlgorithm  rsa-sha256
 [19] StrictHeaders       no
 [20] StrictTestMode      no
 [21] SubDomains          no
- openSUSE
 # zypper install python-policyd-spf
 # ln -s /etc/python-policyd-spf/policyd-spf.conf /etc/policyd-spf.conf
 # ln -s /usr/libexec/postfix/policyd-spf /usr/local/bin/policyd-spf

 
&size(14){&font(b){/etc/opendkim/KeyTable};};
 [セレクタ]._domainkey.[FQDN] [FQDN]:[セレクタ]:[秘密鍵]
 ---
 20170101._domainkey.mail.hoge.org mail.hoge.org:20170101:/etc/opendkim/keys/20170101.private
 
&size(14){&font(b){/etc/opendkim/SigningTable};};
 [署名対象のユーザ]@[FQDN] [セレクタ]._domainkey.[FQDN]
 ---
 *@mail.hoge.org 20170101._domainkey.mail.hoge.org
 
&size(14){&font(b){/etc/opendkim/TrustedHosts};};
 127.0.0.1
 10.0.0.1
 
&size(14){&font(b){/etc/sysconfig/opendkim};};
 # DKIM_SELECTORをコメントアウト
 ---
 OPTIONS="-x /etc/opendkim.conf -P /var/run/opendkim/opendkim.pid"
 #DKIM_SELECTOR=default
 DKIM_KEYDIR=/etc/opendkim/keys
#endregion
SPFレコードをAR形式(Authentication-Resultsヘッダ)で追加する場合、
&color(#ff0000){python-authresモジュール};が必要となる。
ただし、Python2環境ではモジュールが用意されていないので自力でrpmを作成してインストールする。
 # cd /usr/local/src
 # wget https://files.pythonhosted.org/packages/08/ae/3976998b0f8838a5781234710cee17b6717bbf5cc17db6f528531b975a83/authres-1.1.0.tar.gz
 # tar zxvf authres-1.1.0.tar.gz
 # cd authres-1.1.0
 # python setup.py bdist_rpm
 # yum install dist/*.noarch.rpm
~
*構築(openSUSE) [#ed4dd738]
&size(16){&font(b){1. インストール};};
openSUSEではデフォルトのリポジトリだけだとOpenDKIMをインストール出来ないので、
MailServerリポジトリを追加してからインストールを行う。
リポジトリのプライオリティ、有効化は別途Yastから行っておく。
 # zypper addrepo http://download.opensuse.org/repositories/server:mail/openSUSE_Leap_42.3/server:mail.repo
 # zypper refresh
 # zypper install opendkim
~

&size(16){&font(b){2. 設定};};
証明書はOpenDKIMに付属されているツール(opendkim-genkey)を用いて生成する。
生成した証明書はOpenDKIMのコンフィグ内にディレクトリを作成して保存しておく。
セレクタはDNSレコード、メールヘッダに付与される情報なので生成した日付にする。
コンフィグは証明書を元に署名/検証の制御を実装する。
 # mkdir /etc/opendkim/cert
 # cd /etc/opendkim/cert
 # opendkim-genkey -D /etc/opendkim/cert -d mail.hoge.org -s 20170101 -b 2048
 # chown opendkim.root 20170101.private
 # chmod 400 20170101.private
~
#region(&color(#ff0000){設定内容};)
&size(14){&font(b){/etc/opendkim/opendkim.conf};};
 # 下記以外は全てコメントアウトする
 ----
 [01] BaseDirectory       /run/opendkim
 [02] Canonicalization    relaxed/relaxed
 [03] ExternalIgnoreList  refile:/etc/opendkim/TrustedHosts
 [04] InternalHosts       refile:/etc/opendkim/TrustedHosts
 [05] KeyTable            refile:/etc/opendkim/KeyTable
 [06] LogWhy              yes
 [07] MinimumKeyBits      1024
 [08] Mode                sv
 [09] PidFile             /var/run/opendkim/opendkim.pid
 [10] SignatureAlgorithm  rsa-sha256
 [11] SigningTable        refile:/etc/opendkim/SigningTable
 [12] Socket              inet:10027@127.0.0.1
 [13] SoftwareHeader      no
 [14] StrictHeaders       no
 [15] StrictTestMode      no
 [16] SubDomains          no
 [17] Syslog              yes
 [18] SyslogFacility      mail
 [19] SyslogSuccess       yes
 [20] UMask               022
 [21] UserID              opendkim:opendkim
policyd-spfは受信側の処理となる為、DNSのtxtレコード設定については割愛。
ドキュメントは[[Debianの公開している物:+https://manpages.debian.org/testing/postfix-policyd-spf-python/policyd-spf.conf.5.en.html]]を確認する。
 [01] debugLevel       = 1
 [02] Header_Type      = SPF
 [03] #Authserv_Id     = mx.test.org
 [04] HELO_reject      = False
 [05] Mail_From_reject = False
 [06] PermError_reject = False
 [07] TempError_Defer  = False
 [08] skip_addresses   = 127.0.0.0/8,::ffff:127.0.0.0/104,::1
 [09] Whitelist        = 192.168.0.1
 [10] Domain_Whitelist = mail.test.org
 
 =================================================
 --------------------------------------------------
 
 # 概略のみ解説。詳細はコンフィグを見る
 ----
 [01] デフォルトディレクトリの変更
 [02] 署名の厳格化。simpleは改変禁止、relaxedは(SpaceをTabに変換等)多少許可
 [03] 認証を行わないサーバリスト
 [04] 送信時に必ず認証するサーバリスト
 [05] 署名に利用する秘密鍵の指定
 [06] 詳細ログの出力
 [07] 証明書の最小ビット数
 [08] 署名/検証のモード設定。s:署名、v:検証
 [09] OpenDKIMのPIDファイル
 [10] 署名のアルゴリズム。現在は、RSA-SHA256しか使えない
 [11] 署名するメールのenvelope-fromの設定
 [12] OpenDKIMの起動方法。今回はSocketではなく、TCP:10027で待ち受けを行う
 [13] DKIM-FILTERヘッダーを追加。バージョンが載るので今回は付与しない
 [14] DKIMの標準仕様(RFC5322)に沿っていないメールの処理。今回は受信する
 [15] ヘッダ、ボディが[CRLF]で終了してない場合は不正と判断。今回は受信する
 [16] サブドメインメールの署名付与。今回はサブドメインへの付与はしない
 [17] syslog出力の有効化
 [18] syslogのファシリティ
 [19] 処理成功時にsyslogに出力する
 [20] ファイル生成時のUMASK値
 [21] OpenDKIMを実行するユーザの設定
 
&size(14){&font(b){/etc/opendkim/KeyTable};};
 [セレクタ]._domainkey.[FQDN] [FQDN]:[セレクタ]:[秘密鍵]
 ---
 20170101._domainkey.mail.hoge.org mail.hoge.org:20170101:/etc/opendkim/cert/20170101.private
 
&size(14){&font(b){/etc/opendkim/SigningTable};};
 [署名対象のユーザ]@[FQDN] [セレクタ]._domainkey.[FQDN]
 ---
 *@mail.hoge.org 20170101._domainkey.mail.hoge.org
 
&size(14){&font(b){/etc/opendkim/TrustedHosts};};
 127.0.0.1
 10.0.0.1
#endregion
 [01] 出力ログレベル。1(最低限)~5(デバッグログ)を設定出来る
 [02] SPFのヘッダ形式。SPFは"Received-SPF"、ARは"Authentication-Results"
 [03] ヘッダ形式にARを設定した時にヘッダ識別子として使用する
 [04] HELOコマンドのSPF評価方針。ヘッダ付与のみ行い拒否しない時は"False"を設定
 [05] MAIL FROMコマンドのSPF評価方針。ヘッダ付与のみ行い拒否しない時は"False"を設定
 [06] SPF PermErrorの拒否方針。Falseを設定すると無効となる
 [07] SPF TempErrorの遅延方針。Falseを設定すると無効となる
 [08] SPF評価を無効化するIPアドレス。ローカルホストなど不変な物を設定
 [09] SPF評価を無効化するIPアドレス。ドメイン内の他MXサーバなどユーザ毎に変わる値を設定
 [10] SPF評価を無効化するドメイン。アスタリスクレコードは利用不可
~
*起動 [#ccb53db2]
MTA(Postfix)にOpenDKIMを組み込む為、milter設定を行う。
また、OpenDKIMをサービスとして登録して自動起動出来る様にする。
&size(16){&font(b){3. master.cf};};
policyd-spfを呼び出す為、Postfixのmaster.cfを書き換える。
今回はポリシーとして呼び出す為、下記設定を最終行に追記する。
 # SPF Check
 policy-spf  unix    -    n    n    -    0    spawn
     user=nobody argv=/usr/local/bin/policyd-spf /etc/policyd-spf.conf

 
&size(14){&font(b){/etc/postfix/main.cf};};
 # 下記を追記
 ----
 smtpd_milters=inet:127.0.0.1:10027
 non_smtpd_milters=$smtpd_milters
 milter_default_action=accept
 
&size(14){&font(b){起動処理};};
 # systemctl enable opendkim
 # systemctl start opendkim
 # netstat -an | grep 10027
上の設定でSPFチェックが出来ない場合、argvの中でPythonがスクリプトを直接実行する様に書き換える。
この時、ディストリビューションによってはPythonのバージョン毎にPATHが変わるので注意する。
利用するPythonのバージョンは実スクリプトの1行目を読んで判断する。
 # SPF Check
 policy-spf  unix    -    n    n    -    0    spawn
     user=nobody argv=/usr/bin/python2 /usr/local/bin/policyd-spf /etc/policyd-spf.conf
~
*DNS設定 [#w62cf2c2]
DKIMを利用する場合、権威DNSサーバにTXTレコードを登録する必要がある。
DNSに登録するレコードは、証明書作成時に生成されたテキストファイルに記載されている。
権威DNSサーバ都合で一行に記載出来るレコード文字数が制限されている場合、
下記の様に括弧で囲んだ上で改行して登録する
&size(16){&font(b){4. main.cf};};
master.cfに追加したpolicy-spfを呼び出す為、check_policy_serviceを追加する。
この時、設定は下記の様に&color(#ff0000){ "reject_unauth_destination" の後に追加する。};
前に設定すると、check_policy_serviceで処理したメールが全て許可となり、&color(#ff0000){&font(b){MTAがオープンリレー};};化する。
 smtpd_recipient_restrictions =
      permit_mynetworks,
      reject_unauth_destination,
      check_policy_service unix:private/policy-spf

 
"_adsp"については、ググれば解説が出てくるので省略。
今回は無難な設定として"dkim=unknown"としている。
 _adsp._domainkey.mail.hoge.org.       IN  TXT    "dkim=unknown"
 20170101._domainkey.mail.hoge.org.    IN  TXT  ( "v=DKIM1; k=rsa; p=AAAAAAAA"
                                                  "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
                                                  "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
                                                  "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
                                                  "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
                                                  "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
                                                  "GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG" )
追加した "policy-spf" はmaster.cfに追加したポリシー名と同じにする。
また、デフォルト状態では1,000秒程でポリシープロセスがkillされてしまう為、
下記設定も追加してプロセスのkill間隔を調整する。
 # PROC Kill
 policy-spf_time_limit = 3600s
~
*確認 [#c93e023d]
実際に外部のメールサーバからメールを送信し、SPFヘッダが追加されるか確認する。
下記は実際に外部からメールを送信し、ヘッダ付与テストを行った結果となる。
 Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=59.135.**.**; helo=ezweb.ne.jp; envelope-from=*****@ezweb.ne.jp; receiver=*****@***.***.***