목차
- 메일 서버 개요
- POSTFIX 서버 구축
패키지 설치 및 설정파일 편집
TLS (SSL) 설정
opendkim 및 opendkim-tools 설치
1. 메일 서버 개요
메일 서버는 이메일을 송수신하고 저장하는 시스템이다. 사용자가 이메일을 보내면, 메일 서버는 그 이메일을 수신자의 메일 서버로 전달하고, 수신자는 자신의 메일 서버에서 이메일을 다운로드하거나 확인할 수 있다.
이번 매뉴얼에서는 POSTFIX 패키지를 설치해 Ubuntu 서버에 메일서버를 구축한다.
대부분의 상용 이메일 서비스는 발신자의 도메인에 대한 인증(예: SPF, DKIM, DMARC)을 요구한다. 도메인이 없으면 이러한 인증을 통과할 수 없어 발송된 이메일이 차단될 가능성이 높다.
1. SPF (Sender Policy Framework) 화이트 도메인
목적: 발신자 도메인의 이메일을 보낸 서버의 IP 주소를 검증하여 스팸 및 피싱 공격을 방지.
수신 서버는 이메일을 받을 때 발신자의 도메인 DNS에서 SPF 레코드를 확인하고, 발신 IP 주소가 레코드에 포함되어 있으면 인증
이메일과 IP 주소를 검증
2. DKIM (DomainKeys Identified Mail)
이메일 내용의 무결성을 검증하고, 발신자가 해당 이메일의 작성자임을 인증. 스팸을 막는 과정
DKIM의 작동 원리
서명 생성: 이메일의 특정 부분을 해시 함수로 해시하여 고정된 길이의 해시 값을 생성
프라이빗 키로 암호화: 이 해시 값을 발신자의 프라이빗 키로 암호화하여 서명을 만듦. 이 서명이 이메일의 헤더에 추가됨.
서명 검증: 수신자는 발신자의 도메인에서 공개 키를 조회하여, 이메일 헤더에 있는 서명을 복호화. 그 후, 이메일의 해당 부분을 다시 해시하여 얻은 값과 이메일 헤더에 있는 서명을 비교.
3. DMARC (Domain-based Message Authentication, Reporting & Conformance)
이메일 인증 프로토콜로, 이메일의 진위를 확인하고 스팸 및 피싱 공격을 방지하기 위해 설계
DMARC는 SPF와 DKIM을 기반으로 작동
작동 원리
- 이메일이 수신될 때, 수신 서버는 DMARC 레코드를 조회하여 정책을 확인
- SPF와 DKIM 검증을 수행
- 두 인증 결과를 조합하여 DMARC 검증을 수행
- DMARC 검증에 실패한 경우, 설정된 정책에 따라 이메일을 처리
1. POSTFIX 서버 구축
POSTFIX 패키지 설치
apt install postfix
패키지 설치 및 설정파일 편집
호스트네임 및 도메인 설정
Postfix가 이메일 발송 시 “발신 도메인”을 설정하는 방법을 정의. 여기서는 /etc/hostname 파일에 정의된 서버의 호스트 이름을 발신 도메인으로 사용
vi /etc/postfix/main.cf
myhostname = shjtest.o-r.kr
myorigin = /etc/hostname
메일 수신 및 발신 범위 설정
mydestination = $myhostname, localhost, shjtest.o-r.kr, localhost.localdomain
Postfix 메일 서버가 수신할 메일의 도메인을 지정하는 항목. 즉, Postfix가 “자기 자신”을 대상으로 하는 메일을 받아들이는 도메인을 정의
여기 나열된 도메인에 대한 메일은 이 서버에서 수신
네트워크 인터페이스 설정
Postfix가 수신할 IP 주소 범위를 지정한다. 여기서는 모든 네트워크 인터페이스에서 메일을 수신할 수 있도록 설정
inet_interfaces에 대한 설정이 아예 없다면 외부 메일을 받을 수 없다.
inet_interfaces = all
TLS (SSL) 설정
POSTFIX 메일서버에 TLS(Transport Layer Security) 인증 키를 적용하면 이메일 전송의 보안성과 신뢰성을 높일 수 있다.
필자는 지난번에 했던 APM 소스설치 프로젝트를 할 때 발급 받은 Letsencrypt 인증서를 사용하겠다.
SSL 키 파일 목록
/etc/letsencrypt/live/shjtest.o-r.kr# ls -lrt
lrwxrwxrwx 1 root root 41 Sep 19 11:01 privkey.pem -> ../../archive/shjtest.o-r.kr/privkey1.pem <- 이거랑
lrwxrwxrwx 1 root root 43 Sep 19 11:01 fullchain.pem -> ../../archive/shjtest.o-r.kr/fullchain1.pem
lrwxrwxrwx 1 root root 39 Sep 19 11:01 chain.pem -> ../../archive/shjtest.o-r.kr/chain1.pem
lrwxrwxrwx 1 root root 38 Sep 19 11:01 cert.pem -> ../../archive/shjtest.o-r.kr/cert1.pem <- 이거
#SSL 키 추가
vi /etc/postfix/main.cf
smtpd_tls_cert_file=/etc/letsencrypt/live/shjtest.o-r.kr/cert.pem
smtpd_tls_key_file=/etc/letsencrypt/live/shjtest.o-r.kr/privkey.pem
smtpd_tls_security_level=may
smtpd_use_tls=yes
opendkim 및 opendkim-tools 설치
opendkim 패키지 설치
apt install opendkim opendkim-tools
DKIM 설정
opendkim.conf 파일 설정
vi /etc/opendkim.conf
AutoRestart Yes # OpenDKIM 프로세스가 자동으로 재시작되도록 설정
AutoRestartRate 10/1h # 1시간에 최대 10번까지 자동 재시작 가능
Syslog yes # OpenDKIM 로그를 시스템 로그(syslog)에 기록
SyslogSuccess yes # 이메일 서명이 성공적으로 이루어졌을 때도 시스템 로그에 기록
LogWhy yes # 이메일이 서명되거나 서명되지 않은 이유를 로그에 기록
Domain shjtest.o-r.kr
Selector 1728277767.r # DKIM 서명에 사용할 선택자(selector)를 지정. 선택자는 서명을 구분하는 식별자로, DNS에 저장된 공개키를 찾는 데 사용
UserID opendkim:opendkim
Socket inet:8891@localhost #OpenDKIM이 메일 서버(Postfix 등)와 통신할 소켓을 지정. 이 경우, localhost의 8891 포트를 사용해 내부에서 Postfix 메일 서버와 통신
KeyTable refile:/etc/opendkim/KeyTable #서명에 사용할 키 정보를 포함하는 테이블의 경로를 지정
SigningTable refile:/etc/opendkim/SigningTable # 서명 테이블이 위치한 파일의 경로를 지정. 어떤 도메인 또는 이메일 주소에 대해 DKIM 서명을 적용할지를 정의하는 파일.
Mode sv # 서명(s) 및 검증(v) 모드를 사용
PidFile /var/run/opendkim/opendkim.pid #OpenDKIM 프로세스의 PID 파일 경로를 지정
SignatureAlgorithm rsa-sha256
Key 디렉터리생성
mkdir -p /etc/opendkim/keys/shjtest.o-r.kr
DKIM Key 발급
Network Tools: DNS,IP,Email (mxtoolbox.com)


PRIVATE 키 설정
vi /etc/opendkim/keys/shjtest.o-r.kr/mail.private
-----BEGIN RSA PRIVATE KEY-----
~내용생략~
-----END RSA PRIVATE KEY-----
KeyTable 설정
KeyTable 파일은 도메인, 키 파일의 경로 정보를 포함
vi /etc/opendkim/KeyTable
1728277767.r._domainkey.shjtest.o-r.kr shjtest.o-r.kr:1728277767.r:/etc/opendkim/keys/shjtest.o-r.kr/mail.private
1728277767.r._domainkey.shjtest.o-r.kr: 이 부분은 선택자와 도메인을 결합한 것으로, DKIM 서명에 사용할 비공개키를 찾기 위해 DNS에서 조회할 때 사용됩니다.
_domainkey는 DKIM 설정할 때 사용하는 DNS 레코드의 접두사
shjtest.o-r.kr:mail:/etc/opendkim/keys/shjtest.o-r.kr/mail.private: 이 부분은 비공개키의 위치를 지정
SigningTable설정
어떤 도메인 또는 이메일 주소에 대해 DKIM 서명을 적용할지 정의하는 테이블이다.
vi /etc/opendkim/SigningTable
*@shjtest.o-r.kr 1728277767.r:_domainkey.shjtest.o-r.kr
*@shjtest.o-r.kr: 이 부분은 shjtest.o-r.kr 도메인에서 발송되는 모든 이메일 주소에 대해 DKIM 서명을 적용하도록 설정합니다.
1728277767.r:_domainkey.shjtest.o-r.kr: 선택자 1728277767.r을 사용하여 해당 도메인에 대한 DKIM 공개키를 찾도록 지정합니다.
퍼미션 변경
chmod -R 750 /etc/opendkim/keys/
chown opendkim:opendkim /etc/opendkim/keys/shjtest.o-r.kr/mail.private
chmod 640 /etc/opendkim/keys/shjtest.o-r.kr/mail.private
OpenDKIM 데몬은 일반적으로 opendkim 사용자로 실행되며, 이 사용자가 DKIM 서명 생성에 필요한 개인 키 파일에 접근할 수 있도록 퍼미션 설정
POSTFIX 연동
vi /etc/postfix/main.cf
# DKIM config
milter_default_action = accept
milter_protocol = 2
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
메일 로그 설정
vi /etc/postfix/main.cf
#추가
maillog_file = /var/log/mail.log

DNS 레코드에 다음 필드값을 입력한다.
MX
shjtest.o-r.kr 210.122.10.35
1728277767.r._domainkey .shjtest.o-r.kr
TXT
v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfCghTe4IgzMm/smrmKjTnI9cD tf7TxCPfBiVrdxWg4pbtOUGta+nWtO2e8uGhLip8ndIg9fO2+Ef8VKdvF7EclIA4 zjUloNajH3qZH90IYwzC7U/T3HWZ7vRgioKecpZAa4fvh13XG4qUBkzSAvZ6Xn4P gfy3FOZytXhaP6WoyQIDAQAB
_dmarc.shjtest.o-r.kr
v=DMARC1; p=quarantine; pct=100;
DMARC 검증에 실패한 이메일을 격리(스팸 폴더 등으로 이동)하도록 지시, 모든 이메일에 대해 이 정책을 적용
v=spf1 a mx ~all
a: 이 도메인의 A 레코드에 설정된 IP 주소에서 이메일을 보낼 수 있음을 의미. 즉, 해당 도메인의 웹 서버에서 발송된 이메일이 허용
mx: MX 레코드에 지정된 메일 서버가 메일을 송수신할 수 있도록 허용. MX레코드가 지정된 이 메일 서버에서 보낸 이메일은 SPF 검증에서 통과할 수 있다.
~all: SPF 검증에 실패하는 경우의 처리 방식을 지정.
~는 “softfail”을 의미하며, SPF 검증에 실패한 이메일을 거부하지 않고, 스팸으로 분류할 수 있음.
서비스 재시작
systemctl restart opendkim
systemctl restart postfix
systemctl status opendkim
systemctl status postfix
메일 발송 테스트
apt install mailutilsapt install mailutils
echo "dkim mail sending test" | mail -s "dkim mail sending test" -r "root@shjtest.o-r.kr" soonho.jung@hostway.co.kr



이메일 헤더
Authentication-Results: spf=pass (sender IP is 210.122.10.35)
smtp.mailfrom=shjtest.o-r.kr; dkim=pass (signature was verified)
header.d=shjtest.o-r.kr;dmarc=pass action=none
header.from=shjtest.o-r.kr;compauth=pass reason=100
Received-SPF: Pass (protection.outlook.com: domain of shjtest.o-r.kr