設定 SPF 跟 DomainKeys 在 postfix 和 tinydns

部門最近有架 Mail Server 的需求,要架 Mail Server 首先要搞定不讓自己寄出去的信被當作 Spam,參考 Google 的 電子郵件驗證 中說的,要可以被 驗證和識別,通常就是 Domain 要發佈 SPF 跟簽署 DKIM(DomainKeys Identified Mail) 或最古老的 DomainKeys,不過有了 DKIM 後原本單純 DomainKeys 就被廢棄了(當然目前還是可以用的)。我們單位用的 mail server 是 Postfix 而 DNS 則是 tinydns (djbdns %}

設定 SPF

SPF 只是簡單的 DNS TXT 發佈而已,可以利用 easySPF 製作。於是在 tinydns 的設定檔加入下列資訊:

'foo.bar:v=spf1 ip4\07211.22.33.44/32 ~all:600

這裡用 foo.bar 當作 domain,而 11.22.33.44 則是 Server 寄信出來的 public ip,這樣子就完成啦~

我們用 dig TXT foo.bar @8.8.8.8 +tcp 可以觀察到

;; ANSWER SECTION:
foo.bar.        600     IN    TXT    "v=spf1 ip4:11.22.33.44/32 ~all"

設定 DKIM

先到 DKIM 的官網下載,然後編譯的參數用 ./configure --with-openssl --with-miltermake install 裝好之後我們先編輯 /etc/postfix/opendkim.conf

Domain                  foo.bar
KeyFile                 /etc/postfix/rsa.private
InternalHosts           /etc/postfix/ilist
Selector                dk
Socket                  inet:8891@localhost
Syslog                  Yes
UserID                  postfix

以下分開說明每個參數的作用:

  • Domain : 就是我們要 sign 的 domain
  • KeyFile : 由於 DKIM 或者 Domainkeys 都是靠非對稱加解密方式(像 RSA)作驗證,所以需要一把 private/public key,這裡填入的是 sign 需要的 private key

這裡先說明怎麼建立這兩把 key

openssl genrsa -out /etc/postfix/rsa.private 512
openssl rsa -in /etc/postfix/rsa.private -out /etc/postfix/rsa.public -pubout -outform PEM

其中第二把分離出來的 public key 就有我們要填到 DNS 的資訊, cat /etc/postfix/rsa.public大概會長的像下面一樣

-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL+BLtIPf6o3YlrLJUO8b++v4Jc9ppkf
tBdRZfTB0jprUosjt+QHmY8t8bPFEK83XmRrSTEh94MJOjbXwN7AhGcCAwEAAQ==
-----END PUBLIC KEY-----

從 MF…(略)…Q== 就是我們要填的資訊

  • InternalHosts:這個檔案就是告訴 DKIM 從哪些 ip 來的 relay 我們都要 sign mail,格式如下:
127.0.0.1
10.0.0.0/8

事實上官方文件說從 2.2 之後不需要這個檔案, opendkim 會自動判斷 header 的 From 只要等於 Domain 就會自動 sign,可是我實驗的結果沒有成功 = =,所以還是加上去了。

  • Selector:這個是驗證時候要用的 subdomain,就隨便定一個名稱吧。
  • Socket:由於 opendkim 是一個 daemon,這是他要 listen 的 socket (unix domain socket 也是 ok 的 %}
  • Syslog:要不要使用 syslog 來記錄,會被歸類在 mail facility。
  • UserID:daemon 的 UID

設定也好了之後我們就來啟動 daemon 吧!指令很簡單 opendkim -x /etc/postfix/opendkim.conf -A -l,搞定收工。這樣 opendkim 就會 listen 在 port 8891 了。

然後我們要設定讓 postfix 吃到這個 milter,在 /etc/postfix/main.cf 加入下列資訊:

smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891

然後 /etc/init.d/postfix restart 就完成了 opendkim 的設置。

接下來是 tinydns 的設定,還記得剛剛的 public key 嗎?我們需要它了,打開 tinydns 的設定,加入下列資訊:

'_domainkey.foo.bar:o=-:600
'dk._domainkey.foo.bar:k=rsa; p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL+BLtIPf6o3YlrLJUO8b++v4Jc9ppkftBdRZfTB0jprUosjt+QHmY8t8bPFEK83XmRrSTEh94MJOjbXwN7AhGcCAwEAAQ==:600

其中的 _domainkey. 這個 subdomain 是固定的一定要叫這樣才會 work,我後來才發現(因為懶得慢慢嗑 SPEC 試了好久 QQ),而第二行的 dk._domainkey. 的這個 dk 則是對應前面 /etc/postfix/opendkim.confSelector

這樣整個 DKIM 驗證設定就完成了。

Domainkeys

由於我們已經設定好了 key ,所以接下來要設定 Domainkeys 就簡單多了,首先到 domainkeys-milter 下載,然後編譯的指令是 sh Build -c && sh Build install 裝好之後,由於 dk-milter 比較傳統只有支援 command line 的指令所以沒有設定檔支援,要啟動他的指令如下 /usr/bin/dk-filter -i /etc/postfix/ilist -l -b sv -p inet:8892@localhost -d foo.bar -H -s /etc/postfix/rsa.private -S dk &

指令的內容其實都跟 opendkim 一樣(其實是 opendkim 跟他一樣才對 XD),應該不難理解,所以就這樣啦,然後注意的是我讓 dk-milter listen 在 8892,而 key 則用剛剛產生的,然後我們一樣要修改 /etc/postfix/main.cf

smtpd_milters = inet:localhost:8891, inet:localhost:8892
non_smtpd_milters = inet:localhost:8891, inet:localhost:8892

簡單來說就是有幾個 milter 就一直加上去就對了!

至於 DNS 的部分由於 DKIM 跟 domainkeys 都吃一模一樣的 key 所以就不用在設定一次拉~

驗證有沒有成功

最簡單的方式就是從 Server 寄一次看看啦~

telnet localhost 25
MAIL FROM:xxx@foo.bar
RCPT TO:xxx@gmail.com
DATA
From: xxx@foo.bar
To: xxx@gmail.com
Subject: test message
This is test message!
.
QUIT

然後到 GMail 收信,看信件的 Header 應該會有:spf=passdkim=pass 的字樣就表示成功了!而 Yahoo 也是一樣會有 pass 的字樣哦~