๊ฐ๋น์ DNS ์ฐ๋ ๊ฐ๋ฐ์์ SSL ์๋๊ฐฑ์ ์ข์ถฉ์ฐ๋๊ธฐ (feat. Postfix + Naver SMTP)
1๏ธโฃ ๋ฐฐ๊ฒฝ: ์ ๋ฉ์ผ ์๋ฆผ์ด ํ์ํ๋๊ฐ?
๋๋ฉ์ธ ์ธ์ฆ์(SSL)๋ Let’s Encrypt๋ก ๋ฌด๋ฃ ๋ฐ๊ธ์ด ๊ฐ๋ฅํ์ง๋ง,
์ด๋ฒ์ Wildcard ๋ฐฉ์์ผ๋ก ๋ง๋ค ์๋ฐ์ ์์๋ค.
ํนํ *.๋๋ฉ์ธ ํํ์ Wildcard ์ธ์ฆ์๋ DNS TXT ๋ ์ฝ๋๋ฅผ ์ง์ ๋ฑ๋กํด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
(๐ก ๋ณด์ถฉ ์ค๋ช
)
์ผ๋ฐ ๋๋ฉ์ธ(example.com, www.example.com)์ HTTP-01 ์ธ์ฆ ๋ฐฉ์์ ์ด์ฉํด ์๋ ๊ฐฑ์ ์ด ๊ฐ๋ฅํ๋ค.
์ฆ, certbot renew๋ฅผ ํฌ๋ก (cron)์ ๋ฑ๋กํด๋๋ฉด,
์๋ฒ๊ฐ ์๋์ผ๋ก /.well-known/acme-challenge/ ๊ฒฝ๋ก์ ์์ ์ธ์ฆํ์ผ์ ๋ง๋ค๊ณ
Let’s Encrypt๊ฐ HTTP ์์ฒญ์ผ๋ก ์ด๋ฅผ ํ์ธํด ์ธ์ฆ์ ๊ฐฑ์ ํ๋ค.
๊ทธ๋ฌ๋ Wildcard(*.example.com)์ ๊ฒฝ์ฐ,
ํ์ ๋๋ฉ์ธ ์ ์ฒด(aaa.example.com, bbb.example.com ๋ฑ)์ ๋ํ ๊ถํ์ ์ฆ๋ช
ํด์ผ ํ๊ธฐ ๋๋ฌธ์
HTTP ๋ฐฉ์๋ง์ผ๋ก๋ “๋๋ฉ์ธ ์ ์ฒด์ ์์ ์์”์ ํ์ธํ ์ ์๋ค.
๊ทธ๋์ Let’s Encrypt๋ DNS-01 ๋ฐฉ์, ์ฆ “DNS์ TXT ๋ ์ฝ๋๋ก ์ธ์ฆ๊ฐ์ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ”๋ง ํ์ฉํ๋ค.
๋ด๊ฐ ์ฌ์ฉํ๋ ๊ฐ๋น์(Gabia) ๋ DNS API๋ฅผ ์ ๊ณตํ์ง ์๊ธฐ ๋๋ฌธ์,
Certbot์ด ์๋์ผ๋ก TXT ๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ ์ ์๋ค.
(์ด ๋ถ๋ถ ๋๋ฌธ์ ๊ฐ๋น์๋ฅผ ์ฐ๋ ๊ฑธ ์กฐ๊ธ ํํ ์ค... ๐
AWS Route 53, Cloudflare, Google Cloud DNS ๋ฑ์
API๋ฅผ ํตํด TXT ๋ ์ฝ๋๋ฅผ ์๋ ๋ฑ๋กํ ์ ์์ด Wildcard ์๋๊ฐฑ์ ์ด ๊ฐ๋ฅํ๋ค.)
์ฆ, ๋งค๋ฒ ์๋ ๋ช ๋ น์ ์ง์ ์คํํด์ผ ํ๋ค ๐
sudo certbot certonly --manual --preferred-challenges dns \
-d example.com -d '*.example.com'
๊ทธ๋ฆฌ๊ณ DNS TXT ๋ ๊ฐ๋ฅผ ์๋์ผ๋ก ๋ฑ๋กํด์ผ ํ๋ค.
์ด ๊ณผ์ ์์ฒด๋ ์ด๋ ต์ง ์์ง๋ง,
๐ ์ธ์ฆ์ ์ ํจ๊ธฐ๊ฐ(90์ผ)์ ๊น๋นกํ๋ฉด ์ฌ์ดํธ๊ฐ “๋ณด์ ์ฐ๊ฒฐ ์คํจ”๋ก ์ค๋จ๋๋ค.
๊ทธ๋์ ๋ง๋ฃ 30์ผ ์ ๋ฉ์ผ๋ก ์๋ ์๋ฆผ์ด ์ค๋๋ก ์ค์ ํด๋์๋ค.
2๏ธโฃ ํ๊ฒฝ ์์ฝ
ํญ๋ชฉ ๋ด์ฉ
| OS | Rocky Linux 9 |
| ์ธ์ฆ์ | Let’s Encrypt (Wildcard) |
| DNS | ๊ฐ๋น์ (API ๋ฏธ์ง์) |
| ๋ฉ์ผ ์ ์ก | Postfix + s-nail + Naver SMTP (465 SSL) |
| ์๋ฆผ ์คํฌ๋ฆฝํธ | /root/check-ssl.sh (cron ์๋ ์คํ) |
3๏ธโฃ ๋ฉ์ผ ๋ฐ์ก ์คํจ ์ด์ ์ ํด๊ฒฐ
์ด๊ธฐ์ s-nail๋ก ๋ฉ์ผ์ ๋ณด๋ด๋ ค ํ์ง๋ง ์คํจํ์ต๋๋ค.
๋ฌธ์ ๋ก๊ทธ
550 5.7.2 Your email has been blocked because the sender is unauthenticated.
์ด๋ Postfix๊ฐ ๋จ์ ๋ก์ปฌ ์ก์ (unauthenticated)์ด๋ผ์
๋ค์ด๋ฒ SMTP ์ธ์ฆ์ด ์ ๋ ์ํ์๊ธฐ ๋๋ฌธ์
๋๋ค.
โ ํด๊ฒฐ ๊ณผ์ ์์ฝ
๊ฐ๋น์ DNS ํ๊ฒฝ์์ Let’s Encrypt Wildcard ์ธ์ฆ์ ๋ง๋ฃ ์๋ฆผ ๋ฉ์ผ์ ๋ณด๋ด๊ธฐ ์ํด
๋ก์ปฌ ์๋ฒ(Postfix)๊ฐ ๋ค์ด๋ฒ SMTP ์๋ฒ๋ฅผ ํตํด ์ธ์ฆ ๋ฐ์กํ๋๋ก ์ค์ ํ์ต๋๋ค.
1๏ธโฃ Postfix ๋ฐ ๋ฉ์ผ ์ ํธ ์ค์น
sudo dnf install -y postfix s-nail
sudo systemctl enable --now postfix
- postfix: ๋ฉ์ผ ์ ์ก(MTA) ์๋ฒ
- s-nail: ๊ฐ๋จํ CLI ๋ฉ์ผ ๋ฐ์ก ๋๊ตฌ
- enable --now: ๋ถํ ์ ์๋ ์คํ + ์ฆ์ ์์
2๏ธโฃ SMTP ์ธ์ฆ ์ค์ (/etc/postfix/main.cf)
inet_interfaces = 127.0.0.1
inet_protocols = ipv4
relayhost = [smtp.naver.com]:465
smtp_use_tls = yes
smtp_tls_security_level = encrypt
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_generic_maps = hash:/etc/postfix/generic
๐
- relayhost: ๋ค์ด๋ฒ SMTP ์๋ฒ ์ง์
- smtp_sasl_password_maps: ๊ณ์ /๋น๋ฐ๋ฒํธ ์ ์ฅ ์์น
- smtp_generic_maps: ๋ก์ปฌ root ์ฃผ์๋ฅผ ๋ค์ด๋ฒ ๋ฉ์ผ ์ฃผ์๋ก ๋ณํ
3๏ธโฃ SMTP ๋น๋ฐ๋ฒํธ ํ์ผ ์ค์
sudo nano /etc/postfix/sasl_passwd
[smtp.naver.com]:465 example@naver.com:์ ํ๋ฆฌ์ผ์ด์
๋น๋ฐ๋ฒํธ
sudo postmap /etc/postfix/sasl_passwd
sudo chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db
๐ก
- ์ผ๋ฐ ๋น๋ฐ๋ฒํธ๋ ์ฌ์ฉ ๋ถ๊ฐ →
๋ค์ด๋ฒ 2๋จ๊ณ ์ธ์ฆ ํ์ฑํ ํ ์ฑ ๋น๋ฐ๋ฒํธ๋ฅผ ์์ฑํด์ผ ํจ. (์ค์!!) - postmap: Postfix๊ฐ ์ฝ์ ์ ์๋ ํด์ DB๋ก ๋ณํ.
- chmod 600: ํ์ผ ๊ถํ ์ ํ(๋ณด์ ๋๋ฌธ์!)
4๏ธโฃ ๋ฉ์ผ ์ฃผ์ ๋ณํ ์ค์
sudo nano /etc/postfix/generic
root@xxx-web-01.example.kr example@naver.com
sudo postmap /etc/postfix/generic
๐
๋ก์ปฌ์์ root@xxx.example.kr ๋ก ๋ฐ์ก๋๋ ๋ฉ์ผ์
์ธ๋ถ์์๋ example@naver.com ์ผ๋ก ๋ณด์ด๊ฒ ๋ณํ.
5๏ธโฃ Postfix ์ฌ์์
sudo systemctl restart postfix
6๏ธโฃ ํ ์คํธ ๋ฉ์ผ ๋ฐ์ก
echo "ํ
์คํธ ๋ฉ์ผ์
๋๋ค." | s-nail -s "Postfix → Naver OK?" -r example@naver.com example@naver.com
์ดํ ๋ก๊ทธ ํ์ธ ๐
sudo tail -n 50 /var/log/maillog
์ ์์ด๋ผ๋ฉด ๋ค์ ๋ฉ์์ง๊ฐ ๋ณด์ ๋๋ค:
250 2.0.0 OK ... - nsmtp
๐ SMTP ์ธ์ฆ ์ฑ๊ณต!
์ด์ ์๋ฒ๊ฐ ๋ค์ด๋ฒ SMTP๋ฅผ ํตํด ์ ์์ ์ผ๋ก ์ธ์ฆ๋ ๋ฉ์ผ์ ๋ฐ์กํ ์ ์์ต๋๋ค.
์ด์ ํ ์คํธ ์ฑ๊ณตํ์ผ๋ ํด๋น ๊ด๋ จํด์ ํฌ๋ก ์์ ์คํ ๋๋๋ก ์คํฌ๋ฆฝํธ๋ฅผ ๋ง๋ค์ด ๋ณด์!
4๏ธโฃ SSL ๋ง๋ฃ ์๋ฆผ ์คํฌ๋ฆฝํธ
/root/check-ssl.sh
#!/usr/bin/env bash
EMAIL="example@naver.com"
CERT="/etc/letsencrypt/live/example.kr/fullchain.pem"
THRESHOLD=30 # ๋ง๋ฃ 30์ผ ์ดํ๋ถํฐ ์๋ฆผ
if [[ ! -f "$CERT" ]]; then
echo "โ ๏ธ ์ธ์ฆ์ ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค: $CERT" |
s-nail -s "[SSL ๊ฒฝ๊ณ ] example.kr ์ธ์ฆ์ ํ์ผ ์์" "$EMAIL"
exit 1
fi
EXPIRE_RAW=$(openssl x509 -in "$CERT" -noout -enddate | cut -d= -f2)
EXPIRE_TS=$(date -d "$EXPIRE_RAW" +%s)
NOW_TS=$(date +%s)
DAYS_LEFT=$(( (EXPIRE_TS - NOW_TS) / 86400 ))
if (( DAYS_LEFT <= THRESHOLD )); then
SUBJECT="โ ๏ธ example.kr SSL ${DAYS_LEFT}์ผ ํ ๋ง๋ฃ ์์ "
BODY=$(cat <<EOF
๋๋ฉ์ธ: example.kr (*.enhasys.kr)
์ธ์ฆ์ ๊ฒฝ๋ก: $CERT
๋ง๋ฃ์ผ: $EXPIRE_RAW (D-${DAYS_LEFT})
โ
์กฐ์น ๋ฐฉ๋ฒ:
1. ๊ฐ๋น์ DNS์ TXT 2๊ฐ ์ถ๊ฐ
2. ์๋ ๋ช
๋ น์ผ๋ก ๊ฐฑ์ ์คํ
sudo certbot certonly --manual --preferred-challenges dns \
-d example.kr -d '*.example.kr'
EOF
)
echo "$BODY" | s-nail -s "$SUBJECT" "$EMAIL"
fi
5๏ธโฃ ํฌ๋ก ์ค์
crontab -e
0 3 * * * certbot renew --quiet
0 9 * * * /root/check-ssl.sh
- ์ค์ 3์: ์๋ ๊ฐฑ์ ์๋ (์ผ๋ฐ ๋๋ฉ์ธ์ฉ) (์์ผ๋ ์นด๋๊ฐ ์๋ ๋๋ฉ์ธ๋ค์ ์ด๋ ๊ฒ ์ง์ ์๋ ๊ฐฑ์ ์ด ๋๋๋ก ํด๋จ๋ค.)
- ์ค์ 9์: example.kr ๋ง๋ฃ์ผ ์ฒดํฌ ํ ๋ฉ์ผ ๋ฐ์ก
โ ๊ฒฐ๊ณผ
- ์ด์ example.kr ์์ผ๋์นด๋ ์ธ์ฆ์๋ง ์๋ ๊ฐฑ์ ํ๋ฉด ๋จ
- ๋๋จธ์ง ๋๋ฉ์ธ(example1.co.kr, example2.co.kr)์ ์๋ ๊ฐฑ์ ๋จ
- ๋ง๋ฃ 30์ผ ์ ์๋ ๋ฉ์ผ ๋์ฐฉ์ผ๋ก ๊น๋นกํ ์ผ์ด ์์
๐ ๊ฒฐ๋ก
- Postfix ์ค์
- SASL ์ธ์ฆ
- ๊ฐ๋น์ API ๋ถ์ฌ ๋์
- crontab ์๋ํ
๊น์ง ํด์ผํ๋ ๊ณผ์ ์ด์๋ค. - (์ฆ DNS๋ ๊ผญ API ์๋๊ฑธ๋ก ์ฌ์ฉํ์๊ธธ @@)