Rocky Linux - iRedMail (Nginx, Postfix, Dovecot) TLS 인증서 적용

iRedMail 인증서 공식 문서 참고 : https://docs.iredmail.org/letsencrypt.html

 

Let's Encrypt 무료 인증서를 적용하는 방법에 대해 진행하고자 합니다.

이전 자체 구축(107)에서는 웹 서비스를 Apache로 구성했으나, 이번에는 iRedMail의 기본 웹 구성인 Nginx를 기반으로 진행하였습니다. 또한, 웹뿐만 아니라 SMTP/POP3/IMAP 클라이언트에서도 TLS 연결이 필수이므로, PostfixDovecot에도 인증서를 함께 적용했습니다. 설정에 사용되는 주요 옵션들에 대해서도 최대한 자세히 설명드리겠습니다.


◈ STEP① Roundcube Nginx에 보안 인증서 적용

ⓐ Let's Encrypt 무료 인증서를 받기 위한 자동화 Certbot 설치

[root@localhost]# dnf install epel-release -y    (EPEL 저장소 추가, 이전 포스팅에서 설치)

[root@localhost]# dnf install certbot python3-certbot-nginx -y    (Certbot, Python3 설치)

 

※ 아파치(Apache) 웹 서버로 구성되어 있다면, python3-certbot-apache으로 설치

 

ⓑ Nginx 설정 준비

[root@localhost]# vi /etc/nginx/sites-available/00-default.conf    (설정 파일 경로)

#(주석 처리)   server_name _;

                      server_name mail.foxydog.co.kr;    (인증서를 발급받을 도메인을 명시)

 

                      location ~ /.well-known/acme-challenge/ {
                      allow all;     (iRedMail 설치 시, 이미 포함되어 있음)

[root@localhost]# nginx -t    (설정 테스트 확인)

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

[root@localhost]# systemctl reload nginx    (적용)

◇ 추가 설명

server_name_ (언더바) 설정은 일치하는 도메인이 없는 경우에 대응하는 기본 서버 블록을 정의할 때 관례적으로 사용되는 형식입니다. nginx는 server_name이 명시적으로 일치하지 않으면 이 블록을 fallback(기본)으로 사용합니다. DNS에서 여러 도메인의 A 레코드를 동일한 IP로 지정하면, 서로 다른 도메인이라도 모두 이 nginx 서버로 요청이 도달하며, nginx는 각 요청의 host 헤더를 기준으로 해당 server_name 블록을 결정하게 됩니다. 이처럼 nginx 한대로 여러 도메인을 처리하거나, 모든 요청을 하나의 기본 웹사이트로 처리할 수 있습니다. 항상 지시문 끝에 세미클론「 ; 」입력 주의

 

일반 인증서(멀티 도메인/SAN 또는 와일드카드 인증서가 아닌 경우)는 하나의 도메인(FQDN) 당 하나의 인증서로 발급됩니다. 이때 Certbot은 HTTP 방식으로 도메인 소유권을 검증하며, server_name mail.foxydog.co.kr 지시문처럼 nginx에 해당 도메인을 명시해 두어야, 인증 과정 중 http://mydomainhost/.well-known/... 요청이 정상 처리되어 인증서 발급이 성공합니다.

 

ⓒ 인증서 발급

[root@localhost]# cd /etc/nginx/sites-available    (경로 이동)

[root@sites-available]# cp -arp 00-default.conf 00-default.conf_bak    (기존 설정 파일 백업)

 

[root@localhost]# certbot --nginx -d mail.foxydog.co.kr    (인증서 발급 및 자동 설정)

※ 예시를 보여드리기 위한 진행 방식으로, 실 서버 운영 시에는 # certbot certonly -d mydomainhost 와 같이 인증서만 발급받는 식으로 진행하는 게 좋습니다.

ACME 서버에 등록 및 발급받기 위해, 방화벽에서 80/443 포트가 오픈되어있어야 합니다.

자세한 순서는 캡처 화면 확인, 대략적인 순서로는 다음과 같다.

  • 이메일 주소 입력 (긴급 갱신 및 보안 공지 수신에 사용) : foxydog@foxydog.co.kr (관리자 메일 주소)
  • ACME 서버에 등록 필요, 동의? (예/아니요) : Y
  • Cerbot 개발 비영리 단체 EFF 이메일 주소 공유(뉴스레터)? (예/아니요) : Y (선택사항)
  • 인증서 배포 중... 문제가 없다면 성공적으로 인증서를 받습니다. Certbot이 백그라운드에서 이 인증서를 자동으로 갱신하는 예약 작업을 설정했습니다. Nginx 설정에 자동으로 배포 및 성공적으로 활성화했습니다.

 

ⓓ Nginx 설정 수정

※ 자동이 항상 좋은 것은 아닙니다. 특히 iRedMail 자체적으로 구성된 Nginx 설정을 사용하므로, Certbot --nginx와 같은 자동 발급 및 자동 설정 옵션을 사용할 경우, 기존 구성과 충돌이 발생해 웹메일이나 관리자 페이지가 제대로 작동하지 않는 문제가 생길 수 있습니다. 이러한 이유로 기존 00-default.conf 설정 파일을 미리 백업해 두었습니다. 이후 certbot이 변경한 설정 중 필요한 값만 선별하여 복사하고, 나머지는 백업한 설정으로 복원합니다. 다음과 같이 순서로 진행

 

[root@localhost]# vi /etc/nginx/sites-available/00-default.conf    (기존 설정파일 열기)

ssl_certificate / ssl_certificate_key / include / ssl_dhparam 부분만 복사

[root@localhost]# cd /etc/nginx/sites-available/    (경로 이동)

[root@localhost]# cp 00-default.conf_bak 00-default.conf    (백업 파일로 복원)

cp: overwrite '00-default.conf'? y    (덮어쓰기)

[root@localhost]# vi 00-default-ssl.conf    (iRedMail 설정 파일 열기)

#(주석 처리)   server_name _;

                      server_name mail.foxydog.co.kr;    (인증서를 발급받은 도메인을 명시)

                      ssl_certificate /etc/letsencrypt/live/mydomainhost/fullchain.pem;

                      ↑ (인증서)
                      ssl_certificate_key /etc/letsencrypt/live/mydomainhost/privkey.pem;

                      ↑ (인증서 Key)

                      # include, ssl_dhparam 도 #(주석) 처리    (이미 iRedMail 설정에 포함되어 있음)

 

ⓔ 최종 적용 및 HTTPS 접속 인증서 확인

[root@localhost]# nginx -t    (설정 테스트 확인)

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok

nginx: configuration file /etc/nginx/nginx.conf test is successful

[root@localhost]# systemctl reload nginx    (적용)

 

◇ http(s)://mydomainhost/mail/, http(s)://mydomainhost/iredadmin/ 웹 메일(관리자) 접근 테스트

※ HTTP 접속 시, HTTPS로 자동 리다이렉트가 되는지 확인하세요.

같은 브라우저에서 접속을 반복했다면 쿠키 값을 삭제하거나 새 창/시크릿 창에서 열어보는 것을 권장합니다. 이는 기존 쿠키나 캐시 된 리소스를 불러오면서, 인증서가 정상적으로 적용되었음에도 불구하고 '안전하지 않음' 메시지가 표시되는 경우가 있기 때문입니다. (서버의 문제가 아니라, 브라우저 자체 처리 문제)

 

[root@localhost]# curl -v https://mydomainhost    (서버 로컬에서 확인)

 

ⓕ Nginx TLS 로그 남기기

[root@localhost]# vi /etc/nginx/conf-available/log.conf    (로그 파일 수정)

 

error_log /var/log/nginx/error.log notice;    (TLS handshake 에러 남길 시 notice 추가)

TLS 핸드셰이크 실패, 인증서 mismatch 등은 error log에만 출력됩니다.


log_format tls_logs '$remote_addr - $host [$time_local] '

                                '"$request" $status $body_bytes_sent '

                                '"$http_referer" "$http_user_agent" '

                                'TLS:$ssl_protocol/$ssl_cipher '

                                'SNI:$ssl_server_name';

access_log /var/log/nginx/tls_access.log tls_logs;    (순서 주의, 로그 포맷이 먼저)

[root@localhost]# nginx -t    (설정 테스트 확인)

[root@localhost]# systemctl reload nginx    (적용)

[root@localhost]# tail -f /var/log/nginx/tls_access.log    (웹 접속 후 로그 생성 확인)


◈ STEP② Postfix 보안 인증서 적용

인증서만 발급받으면 이후에는 간단합니다.

 

ⓐ Postfix「main.cf」 설정 수정

[root@localhost]# vi /etc/postfix/main.cf    (설정 파일 열기)

smtpd_tls_key_file = /etc/letsencrypt/live/mydomainhost/privkey.pem    (인증서 KEY 추가 등록)

smtpd_tls_cert_file = /etc/letsencrypt/live/mydomainhost/fullchain.pem    (인증서 추가 등록)

#(주석 처리) smtpd_tls_CAfile = /etc/pki/tls/certs/ca-bundle.crt

#(주석 처리) smtpd_tls_CApath = /etc/pki/tls/certs

◇ 추가 설명

→ TLS 프로토콜(Protocol)은 최소 TLSv1.2 이상을 사용하는 것이 권장됩니다.

시스템 설정에서 느낌표「 ! 」는 제외(비활성화)의 의미로, !SSLv2 !SSLv3 !TLSv1 !TLSv1.1과 같이 설정하면 해당 프로토콜들의 사용을 금지하겠다는 의미입니다.

 

→ smtpd_tls_security_level 및 smtp_tls_security_level 설정 값은 may 옵션을 사용하는 것이 일반적으로 권장됩니다.

encrypt 옵션을 사용하면 모든 통신을 암호화(TLS)로 강제하게 되지만, 상대방(수신 측) 메일 서버가 TLS 구성이 되어 있지 않다면 통신 자체가 불가능해집니다. 기업 간 1:1 통신과 같이 양쪽 모두 TLS 환경이 명확하게 구성된 경우에는 encrypt 옵션을 사용할 수 있지만, 일반적인 메일 환경에서는 다양한 외부 메일 서버(포탈 메일 포함)와의 호환성을 고려하여 may 옵션을 사용하는 것이 현실적이 선택입니다.

의미 의미
none TLS 사용 안함(비권장) dane DNSSEC 기반 TLS 인증 사용
may TLS 가능하면 사용, 안되면 평문 허용 verify 인증서 검증 포함
encrypt TLS 없으면 아예 연결 거부 (강제 암호화) secure 엄격한 보안 연결만 허용 (신뢰된 인증서 필요)

→ 인증서는 smtpd_tls 옵션에만 적용하면 됩니다.

수신 및 서버로 메일 인증이 들어올 때 (25/587/465 등) TLS 인증서를 사용합니다.

발신할 때는 대부분 클라이언트 인증서 없이 TLS handshake만 하므로, smtp_tls_cert_file은 필요 없습니다.

 

ⓑ 서비스 재시작 및 인증서 적용(갱신) 확인

[root@localhost]# systemctl restart postfix    (서비스 재시작)

[root@localhost]# netstat -nlp | egrep "25|587|465|1002" | grep tcp    (캡처 참고)

 

※ ps -ef | grep postfix 프로세스를 확인해도 되지만, 메일 서버는 포트 응답으로 확인하는 게 더 정확하다.

※ 수신, 발신에 관계있는 포트들은 25, 465, 587입니다. 10025~10028은 필터 관련으로 내부 로컬에서 처리

[root@localhost]# echo | openssl s_client -connect localhost:25(587) -starttls smtp 2>/dev/null | openssl x509 -noout -dates    (STARTTLS 연결 및 인증서 확인)

[root@localhost]# echo | openssl s_client -connect localhost:465 2>/dev/null | openssl x509 -noout -dates    (SSL 연결 및 인증서 확인)

 

※ 클라이언트에서 SMTP를 이용한 보안 메일 발송 시, 465 포트 또한 보안 연결을 지원하지만, SSL 방식은 이제 구식으로 간주됩니다. 현재는 587 포트를 이용한 STARTTLS 방식이 가장 표준적이며 안정적인 보안 연결 방식으로 권장됩니다.

 

ⓒ 발송, 수신 TLS 통신 로그 확인 (실시간 로그 확인)

[root@localhost]# tail -f /var/log/maillog | grep -i tls    (캡처 참고)

◇ 추가 내용(수신 TLS 헤더 메시지 추가)

[root@localhost]#  vi /etc/postfix/main.cf    (설정 확인)

smtpd_tls_received_header = yes    (#주석 해제 또는 추가)

[root@localhost]# systemctl restart postfix    (서비스 재시작)


◈ STEP③ Dovecot 보안 인증서 적용

ⓐ Dovecot「dovecot.conf」 설정 수정

[root@localhost]# vi /etc/dovecot/dovecot.conf    (설정 파일 열기)

#(주석 처리) ssl_cert = </etc/pki/tls/certs/iRedMail.crt

#(주석 처리) ssl_key = </etc/pki/tls/private/iRedMail.key

ssl_cert = </etc/letsencrypt/live/mydomainhost/fullchain.pem    (인증서 추가 등록)

ssl_key = </etc/letsencrypt/live/mydomainhost/privkey.pem    (인증서 KEY 추가 등록)

◇ 추가 설명

ssl_min_protocol = TLSv1.2, 이 설정은 클라이언트와의 TLS 통신에서 허용할 최소 프로토콜 버전을 지정합니다. TLSv1.1 이하로 접속하려 하면 연결을 거부합니다. TLSv1.3은 자동으로 포함됩니다. (사용 가능한 경우)

 

verbose_ssl = no, 이 설정은 TLS 관련 문제를 디버깅할 때 사용하는 옵션입니다.

예를 들어, 인증서 오류, 클라이언트 접속 실패 원인, TLS 버전 및 Cipher Suite 확인 등 암호화 설정 테스트가 필요할 경우 yes로 설정하여 상세 로그를 확인할 수 있습니다. 다만, 운영 중 특별한 문제가 없다면 불필요한 로그가 누적될 수 있으므로 평소에는 no상태를 유지하는 것이 좋습니다.

 

disable_plaintext_auth = yes, 암호화되지 않은(PLAIN) 인증을 비활성화합니다.

즉, STARTTLS나 SSL 없이 접속하면 로그인 자체가 거부됩니다. IMAP/POP3 평문 인증을 막기 위한 보안 조치입니다. IMAP(143), POP3(110) 기본 포트는 거부 / IMAPS(993), POP3(995) SSL/TLS 연결만 허용

 

ssl = required, 모든 접속은 SSL/TLS로만 허용(더 강력), 대체로 위 옵션과 병행하여 같이 사용

 

ⓑ 서비스 재시작 및 인증서 적용(갱신) 확인

[root@localhost]# systemctl restart dovecot    (서비스 재시작)

[root@localhost]# netstat -nlp | egrep "110|995|143|993" | grep tcp    (캡처 참고)

[root@localhost]# echo | openssl s_client -connect localhost:995 2>/dev/null | openssl x509 -noout -dates    (SSL 연결 및 인증서 확인)

[root@localhost]# echo | openssl s_client -connect localhost:993 2>/dev/null | openssl x509 -noout -dates    (SSL 연결 및 인증서 확인)

 

ⓒ POP3, IMAP, SMTP(587) TLS 통신 로그 확인 (실시간 로그 확인)

[root@localhost]# tail -f /var/log/dovecot/pop3.log    (캡처 참고)

[root@localhost]# tail -f /var/log/dovecot/imap.log

[root@localhost]# tail -f /var/log/maillog    (SMTP-587-Submission)

 

※ SMTP(587) 포트 연결은 Postfix 설정을 통해 확인할 수 있습니다. 클라이언트(예: 아웃룩)에서 메일 서버로 SMTP 인증 과정을 처리하는 로그를 통해 연결 상태를 함께 확인하는 모습입니다.

※ Microsoft 365 정품 구독 제품으로 설치한 아웃룩 클라이언트에서는 의외로 TLSv1.2 프로토콜로 통신을 시도하네요. 조금 찾아보니 Microsoft Oulook은 TLSv1.2 까지만 지원하는 게 맞습니다. SMTP, IMAP POP3, Exchange ActiveSync 등 전송 프로토콜에서 TLS 1.3은 아직 미지원입니다. 자세한 내용은 마이크로소프트 기술 지원 문서(TLS) 참고, Exchange Online의 경우는 이제 모든 이메일 전송 및 인터넷에서 타사와의 서버 통신에 대해 TLS 1.3을 지원한다고 합니다. 순차적으로 적용할 예정으로 보입니다.


◈ STEP④ 인증서 갱신 자동화

ⓐ 준비

※ Certbot에는 갱신 후 hook 스크립트를 실행하는 기능이 있습니다. 이를 활용하여 진행합니다.

[root@localhost]# cd /etc/letsencrypt/renewal-hooks/deploy    (경로 이동)

[root@localhost]# vi foxydog-mail.sh    (스크립트 생성, 저장)

#!/bin/bash

echo "[INFO] Reloading Nginx, Postfix, Dovecot after cert renewal..."

systemctl reload nginx

systemctl reload postfix

systemctl reload dovecot

[root@localhost]# chmod +x foxydog-mail.sh    (실행 권한 부여)

[root@localhost]# ll    (권한 부여 확인)

-rwxr-xr-x 1 root root 155 Jul 8 16:47 foxydog-mail.sh

 

ⓑ 사전 테스트

※ 조건 내부 방화벽 80,443 포트가 인바운드 허용이 되어있어야 합니다.

[root@localhost]# certbot renew --dry-run    (인증서 갱신 테스트)

Congratulations, all simulated renewals succeeded:

/etc/letsencrypt/live/mydomainhost/fullchain.pem (success)    (정상 패턴)

[root@localhost]# tail -f /var/log/letsencrypt/letsencrypt.log    (로그 확인)

 

※ 테스트에서는 갱신에 문제가 없는지 체크만 하므로 인증서 갱신, Deploy hook 스크립트 명령어, 업데이트를 스킵합니다. 마지막에 인증서 Success 메시지만 확인하면 됩니다. (캡처 로그 참고)

 

ⓒ 자동화 등록 (Crontab)

※ 이제 명령어로 「# certbot renew」하면 끝이지만, 이 명령어를 90일마다 실행을 해야 합니다. 똑같이 스크립트를 하나 생성합니다. 저는 별도의 경로를 만들어서 저장하겠습니다. 항상 80/443 웹 포트를 오픈하는 환경이면 갱신만 하면 되지만, 보안상 GEOIP(국가) 차단이 걸려있거나 특정 IP에서만 접근하도록 설정되어 있다면 일시적으로 방화벽 해제 후 갱신 후에 다시 시작하는 방식입니다.

[root@localhost]# mkdir /root/script    (스크립트 경로는 임의)

[root@localhost]# vi /root/script/certbotrenew.sh    (스크립트 생성, 저장)

#!/bin/bash

systemctl stop iptables

sleep 3

certbot renew

sleep 3

systemctl start iptables

[root@mail script]# chmod +x /root/script/certbotrenew.sh    (실행 권한 부여)
[root@mail script]# ls -al    (권한 부여 확인)

-rwxr-xr-x 1 root root 91 Jul 8 18:07 certbotrenew.sh

[root@localhost]# crontab -e    (작업 스케줄러)

예시 (1월/4월/7월/10월 1일 새벽 3시)

0 3 1 1,4,7,10 * /root/script/certbotrenew.sh

 

ⓓ 최종 테스트(스크립트 실행)

※ 설정에 이상이 없다면, 위에 등록한 시간대에 따라 스크립트가 자동으로 실행되어 인증서 갱신이 이루어질 것입니다. 다만, 이 서버는 테스트용으로 구성된 실서버이기 때문에 장기 운영은 어려워 실제 갱신 시점까지 확인해 볼 수는 없습니다. 따라서 실제 갱신 여부는 검증되지 않았고, 최소한 스크립트가 정상적으로 실행되는지 여부는 직접 확인해 보는 것이 좋습니다.

 

[root@localhost]# /root/script/certbotrenew.sh

[root@localhost]# /etc/letsencrypt/renewal-hooks/deploy/foxydog-mail.sh

[root@localhost]# cd /etc/letsencrypt/renewal/    (경로 이동)

[root@localhost]# cat mydomainhost.conf    (인증서 갱신 정의 파일)

◇ 추가 내용

위 파일들은 심볼릭 링크로 되어 있으며, 갱신되면 자동으로 새 파일로 연결됩니다. 즉, 설정한 인증서 경로는 바뀌지 않고, 내부 내용만 교체되기 때문에 자동화를 할 수 있습니다. 다만, 도메인을 변경하거나 인증서 발급 방식을 바꿨을 경우(와일드카드로 재발급)는 스크립트를 경로에 맞게 새로 수정해야 합니다.


◈ 마치며

포스팅 내용을 머릿속에서 최대한 압축하려고 해도, 막상 글을 쓰다 보면 더 자세히 설명하고 싶은 욕심이 생깁니다. 그러다 보니 부가적인 설명이 계속 추가되어 생각보다 진도가 느려지네요. 그래도 자료를 수집하면서 공부가 되니 의미는 있다고 생각합니다.

 

테스트를 위해 클라우드 실서버도 직접 구축해 봤는데, 시간이 곧 비용이라 조바심이 생기네요. (웃음) 당분간 취미 활동은 잠시 줄이고, iRedMail 관련 포스팅에 집중해보려 합니다.

Designed by JB FACTORY