홈서버로 메일 서버 구축(2) - 메일 보안 (SPF, DKIM, DMARC)
메일 보안을 적용 해봅시다 ✉️
지난 포스트에서는 메일 서버를 구축했습니다.
메일 서버만으로도 서버 내에서 메일을 송수신 할 수는 있지만, 서버 외부로는 메일을 송수신 하기가 어려워요.
Gmail이나 네이버 메일 등에서는 메일 인증이 올바르게 설정되지 않은 서버에서 보낸 메일을 스팸 처리하거나, 아예 수신을 거부하기도 합니다.
따라서 생성한 메일 계정을 외부에서도 자유롭게 사용하려면, SPF, DKIM, DMARC와 같은 메일 인증 표준을 적용해야 합니다.
선수 지식 🧐
1. SPF
SPF(Sender Policy Framework)는 수신 메일 서버에서 메일을 수신 받는 시점에 발신 메일 서버가 가리키는 IP 주소가 DNS 서버에 등록된 IP와 일치하는지 확인하는 절차입니다.

위의 그림을 보면 보다 쉽게 이해가 될텐데요, 발신 측은 미리 도메인 DNS에 TXT 레코드 형식으로 허용된 서버 IP를 등록해두고, 수신 측이 IP 주소를 확인할 때 DNS 서버를 통해 등록되어 있는 IP 주소와 동일한지 비교합니다.
이 과정을 통해 메일 서버 도메인을 사칭하지 않았는지 검증할 수 있어요.
하지만, SPF로는 완전히 발신 도메인 사칭을 방지할 수 없기 때문에 DKIM과 DMARC를 함께 사용해주어야 합니다.
2. DKIM
DKIM(Domain Keys Identified Mail)은 메일이 전송되는 과정 중에 변조되지 않았는지를 검증하는 절차입니다.
많은 사람들이 DKIM을 밀랍 봉인에 비유하곤 합니다.
DKIM의 절차는 다음과 같습니다.

DKIM은 공개키, 개인키의 개념이 사용되지만 어렵지 않습니다.
SPF에서는 IP 주소를 도메인 DNS에 등록해두었다면, DKIM에서는 공개키 정보를 TXT 레코드 형식으로 등록해두면 됩니다.
이후에, 메일 발송 시 DKIM-Signature에 개인키로 전자서명 후 헤더에 포함하여 전송하면, 수신 메일 서버에서 DNS에 등록되어 있는 레코드를 조회하여 검증합니다.
그러나, DKIM만으로는 From 변조를 검증할 수 없습니다.
DKIM은 도메인 검증만 하기 때문에, MAIL FROM과 from이 같은지 비교할 수 있도록 DMARC를 추가로 적용해주어야 합니다.
3. DMARC
DMARC(Domain-based Message Authentication Reporting Conformance)는 발신자 정보를 위조하는 것을 예방하기 위한 검증 방법입니다.
DMARC는 SPF와 DKIM에 Reporting이 합쳐져 있는데요, 아래가 DMARC의 절차입니다.

SPF와 DKIM을 둘 다 사용해서 메일 서버 도메인 사칭과 내용물 변조 여부를 검증합니다.
이후에 메일이 SPF, DKIM 인증 절차를 통과하지 못한다면 DMARC 정책이 적용되는데, 이 때 사용자가 설정한 정책에 따라 메일을 스팸 처리하거나 거부하고, 검증 결과를 보고서로 설정된 주소에 발송할 수 있습니다.
이 때 정책은 도메인 DNS에 TXT 레코드 형식으로 등록하면 됩니다.
메일 보안 적용하기 👮♀️
0. PTR 레코드
자 이제 메일 보안을 적용하기에 앞서, 가장 먼저 해주어야 할 과정이 있습니다.
도메인과 IP를 연결할 때에는 IP 주소가 도메인을 가리킬 수 있도록 A 레코드를 추가해줬었습니다.
하지만, 메일과 같은 경우는 도메인이 어떤 IP 주소를 가리키고 있는지 확인이 필요합니다.
이 확인 과정을 역방향 DNS 조회, 혹은 리버스 DNS 조회라고 합니다.
PTR 레코드는 다음과 같이 추가하면 됩니다.
Host | Type | Priority | TTL | Data |
---|---|---|---|---|
[뒤집은 공인 IP].in-addr.arpa | PTR | N/A | 4 hrs | mail.[yourdomain] |
정말 정말 중요한 포인트는 공인 IP를 기입할 때 IP 주소를 뒤집어서 표기해야 합니다. 예를 들어 123.456.789.987 이라면, 987.789.456.123 이렇게 적어주어야 해요.
제가 정말 이것 때문에 고생했습니다. 그리고 생각 보다 많은 사람들이 이것 때문에 고생을 하더라구요.
이 내용은 아래 Squarespace 포럼에서 확인했습니다.
Correct way to set PTR DNS record for mail forwarding
1. SPF 설정하기 🥸
자 그러면 SPF부터 설정을 해봅시다!
SPF를 위한 TXT 레코드 설정은 굉장히 간단합니다.
Host | Type | Priority | TTL | Data |
---|---|---|---|---|
@ | TXT | N/A | 4 hrs | v=spf1 ip4:[공인 IP] ~all |
이렇게 설정해주면, 메일의 ip4가 설정한 IP와 동일한 경우 인증 절차를 통과 시켜줍니다.
그리고 저 같은 경우는 ~all
옵션을 사용했기 때문에 SPF 검증에 실패한 경우에도 메일을 수락하지만, 수신 서버에서 ‘주의’ 또는 ‘스팸’으로 표시합니다.
인증 실패 시 메일을 완전히 차단하고 싶다면 -all
옵션을 사용하면 됩니다!
2. DKIM 설정하기 📦
postfix와 dovecot으로 구성된 환경에서는 보통 OpenDKIM을 사용해서 DKIM 설정을 해줍니다.
이 OpenDKIM을 설정하는 것이 조금 복잡하지만, 메일 서버를 구축하는 과정보다는 나으니 천천히 한 번 해봅시다.
우선, OpenDKIM을 install 해줍시다.
sudo apt install opendkim opendkim-tools
그리고, OpenDKIM 디렉토리를 만들고, 그 안에 key를 생성해줍니다.
# 디렉토리 생성
sudo mkdir -p /etc/opendkim/keys/[yourdomain]
cd /etc/opendkim/keys/[yourdomain]
# 키 생성
sudo opendkim-genkey -d [yourdomain] -s [selectorname]
이 때, DKIM은 selector를 기반으로 키의 소유자를 구분하는데 그냥 닉네임 같은 거라고 생각하면 좋습니다.
저는 selector name을 mail로 지정해주었어요.
이 과정을 수행하고 나면, [selectorname].private
, [selectorname].txt
파일이 생성되어 있을거예요!
이어서 생성된 파일의 권한을 설정해줍시다.
sudo chown opendkim:opendkim mail.private
sudo chmod 640 /etc/opendkim/keys/swlee.net/mail.private
sudo chmod 644 /etc/opendkim/keys/swlee.net/mail.txt
이젠 생성한 DKIM 정보를 토대로 /etc/opendkim/KeyTable
, /etc/opendkim/SigningTable
, /etc/opendkim/TrustedHosts
, /etc/opendkim.conf
를 설정해주면 됩니다.
Keytable 먼저 해봅시다.
sudo vi /etc/opendkim/KeyTable
로 vi 편집기를 열어주고, 아래의 내용을 기입해줍시다.
# 키 테이블이 사용할 DKIM 키의 경로를 작성하여, DKIM key를 선언
[selectorname]._domainkey.[yourdomain] [yourdomain]:[selectorname]:/etc/opendkim/keys/[yourdomain]/[selectorname].private
[]로 표기된 부분은 꼭 개인의 환경에 맞춰 수정해주어야 합니다.
그리고, sudo vi /etc/opendkim/SigningTable
로 SigningTable에 아래 내용을 기입해줍니다.
# 사용할 메일 주소와 키 테이블을 매칭
# *는 모든 메일 주소에 해당 키 테이블을 매칭할 것을 의미함
*@[yourdomain] [selectorname]._domainkey.[yourdomain]
sudo vi /etc/opendkim/TrustedHosts
로 TrustedHosts는 아래와 같이 작성해줍니다.
127.0.0.1
localhost
[공인 IP]
[yourdomain]
이제 마지막입니다!
sudo vi /etc/opendkim.conf
으로 OpenDKIM 아래와 같이 설정 파일을 수정해줍니다.
# This is a basic configuration for signing and verifying. It can easily be
# adapted to suit a basic installation. See opendkim.conf(5) and
# /usr/share/doc/opendkim/examples/opendkim.conf.sample for complete
# documentation of available configuration parameters.
Syslog yes
SyslogSuccess yes
LogWhy yes
# Common signing and verification parameters. In Debian, the "From" header is
# oversigned, because it is often the identity key used by reputation systems
# and thus somewhat security sensitive.
Canonicalization relaxed/simple
Mode sv
SubDomains yes
# from이 헤더에 중복되어 dkim 인증 오류 발생 - 주석처리
#OversignHeaders From
# Signing domain, selector, and key (required). For example, perform signing
# for domain "example.com" with selector "2020" (2020._domainkey.example.com),
# using the private key stored in /etc/dkimkeys/example.private. More granular
# setup options can be found in /usr/share/doc/opendkim/README.opendkim.
#Domain example.com
#Selector 2020
#KeyFile /etc/dkimkeys/example.private
# 설정 파일 연결
KeyTable /etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts
# In Debian, opendkim runs as user "opendkim". A umask of 007 is required when
# using a local socket with MTAs that access the socket as a non-privileged
# user (for example, Postfix). You may need to add user "postfix" to group
# "opendkim" in that case.
UserID opendkim
UMask 002
# Socket for the MTA connection (required). If the MTA is inside a chroot jail,
# it must be ensured that the socket is accessible. In Debian, Postfix runs in
# a chroot in /var/spool/postfix, therefore a Unix socket would have to be
# configured as shown on the last line below.
# postfix 연결 소켓
Socket local:/run/opendkim/opendkim.sock
Socket inet:8891@localhost
#Socket inet:8891
#Socket local:/var/spool/postfix/opendkim/opendkim.sock
PidFile /run/opendkim/opendkim.pid
# Hosts for which to sign rather than verify, default is 127.0.0.1. See the
# OPERATION section of opendkim(8) for more information.
#InternalHosts 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12
# The trust anchor enables DNSSEC. In Debian, the trust anchor file is provided
# by the package dns-root-data.
TrustAnchorFile /usr/share/dns/root.key
#Nameservers 127.0.0.1
이제 OpenDKIM 설정은 모두 끝났습니다.
이제 이 OpenDKIM 소켓을 postfix에 연결해봅시다.
지난 번에 다루었던 파일인 /etc/postfix/main.cf 파일을 vi 편집기로 열어봅시다.
아래의 4줄을 해당 파일 최하단에 추가해줄게요!
# DKIM
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
그리고, 도메인 DNS에 TXT 레코드를 추가해줍시다.
Host | Type | Priority | TTL | Data |
---|---|---|---|---|
mail._domainkey | TXT | N/A | 4 hrs | [your DKIM] |
여기서, Data에는 아까 생성한 /etc/opendkim/keys/[yourdomain]/[selectorname].txt
파일 안에 있는 값 중 일부를 넣어주어야 합니다.
sudo cat /etc/opendkim/keys/[yourdomain]/[selectorname].txt
을 하면 아래와 같이 DKIM key를 조회할 수 있습니다.
[selectorname]._domainkey IN TXT ( "v=DKIM1; h=sha256; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwf6TnXFm5i+OoT6XGWxn7YjqxA3HoqwuoTQjCwVzQTHSQtbOSAwtnG8clastaGHOXzTl3ElgJicLFHKM+e4kNNCJte/sidfSF8tqd1NM7i4PvuMysMTunuaEDy4dNCPKG0+JIugY9hI1zu7/jHE2t5PryTzWKXs7h0TZQqHooVLRDfkRkXhXewoYkcJXpqyKeil+uEr7xgRvzQ"
"DGr1wY+VSZ3/QS4bEByBRaUKLBZlxxCX9yvHNEIk4oroIE6dVDrRx65Q6jgKKnqyBB2YcSLoKvY1slIU6X6wU1MVCS5BmvnSzZXXIAKUANem2QNSj6/nQ9KL5KJW36bxMsVxi7fQIDAQAB" ) ; ----- DKIM key [selectorname] for [yourdomain]
이제 여기서 값을 발췌해서 아래와 같이 편집해줍니다.
v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwf6TnXFm5i+OoT6XGWxn7YjqxA3HoqwuoTQjCwVzQTHSQtbOSAwtnG8clastaGHOXzTl3ElgJicLFHKM+e4kNNCJte/sidfSF8tqd1NM7i4PvuMysMTunuaEDy4dNCPKG0+JIugY9hI1zu7/jHE2t5PryTzWKXs7h0TZQqHooVLRDfkRkXhXewoYkcJXpqyKeil+uEr7xgRvzQDGr1wY+VSZ3/QS4bEByBRaUKLBZlxxCX9yvHNEIk4oroIE6dVDrRx65Q6jgKKnqyBB2YcSLoKvY1slIU6X6wU1MVCS5BmvnSzZXXIAKUANem2QNSj6/nQ9KL5KJW36bxMsVxi7fQIDAQAB
여기서 정말 정말 중요한 점은 p=
다음에 이어지는 공개키가 한 줄로 잘 이어지고, 따옴표가 올바르게 닫혀 있어야 정확하게 인식이 됩니다!
키값이 잘 들어갔는지 확인하려면 dig TXT [selectorname]._domainkey.[yourdomain]
를 실행해보세요!
동일하게 잘 나온다면 적용이 잘 되고 있는 것입니다.
그리고 서비스 재시작!
sudo systemctl restart opendkim
sudo systemctl restart postfix
3. DMARC 설정하기 📪
이제 정말 마지막 단계입니다.
이건 정말 정말 쉬워요.
도메인 DNS에 TXT 레코드를 하나만 추가해주면 됩니다.
Host | Type | Priority | TTL | Data |
---|---|---|---|---|
_dmarc | TXT | N/A | 4 hrs | v=DMARC1; p=none; rua=mailto:[yourmailadd] |
v는 DMARC의 버전 정보, p는 정책, rua는 보고서를 받을 메일 주소를 의미합니다.
위의 Data 안의 값은 메일이 DMARC 검증에 실패하더라도 아무런 조치를 취하지 않고 보고서만 보내라는 의미입니다.
따라서, 테스트용으로는 좋지만, 나중에는 수정해주는게 좋아요!
Thunderbird 연결 🦅
자, 모든 보안 설정이 끝났습니다!
메일 클라이언트 중 하나인 Thunderbird를 설치하고, 로그인을 해봅시다.
위의 과정이 성공적으로 이루어졌다면, Thunderbird에 성공적으로 로그인할 수 있을거예요!
로그인 과정은 이 블로그를 참고하면 좋을 것 같습니다.
Postfix, dovecot, letsencrypt 를 이용한 메일서버 구축 - 4
성공적으로 로그인이 되셨고, 구글 메일이나 네이버 메일로 전송한 메일을 원문 보기 했을 때 아래와 같이 표기된다면 성공입니다!
참고 사이트 🔎
[MAIL보안] SPF (Sender Policy Framework) 메일 보안 - 1
이 사이트의 메일 보안 시리즈를 바탕으로 진행했습니다!
OpenDKIM 설정 관련은 이 포스트를 참고했습니다.
Correct way to set PTR DNS record for mail forwarding
Squarespace에서의 PTR 레코드 설정 방법에 대한 토론이 이루어진 Sqarespace forum 페이지입니다.
Squarespace 네임서버에서 Spacemail DNS 레코드 설정 방법
Squarespace의 레코드 설정 방법을 참고한 포스트입니다!