📑 ???
???????TLS ?????????
?????????????????TLS ????????????????????????????????/p>
| ?????? | ??? | ??? | ????????/th> | ?????? |
|---|---|---|---|---|
| SMTP??TA??TA??/td> | STARTTLS | 25 | mx.example.com | ??? MX ???????????? SAN |
| MUA ?????UA??SA??/td> | STARTTLS / TLS | 587 / 465 | smtp.example.com | ???????????/td> |
| IMAP/POP3??UA??DD??/td> | TLS / STARTTLS | 993 / 143 | mail.example.com | ????????????????????? SAN ???????????/td> |
RFC 3207 ??? SMTP STARTTLS ??????????? X.509 PKI ?????FC 7817 ??????????????SAN??ubject Alternative Name??????????????strong>??????????????????????? CA ???????????????????????????????/p>
Let's Encrypt??? Internet Security Research Group ???????????????????CA ????????ACME ?????????????????????????? 90 ???????????????????????????????/p>
????et's Encrypt + certbot ??????
2.1 ??? certbot ??DNS-01 ???
?????????????????? DNS-01 ??????????????????????????80/443 ?????HTTP ??????????????????????? nsupdate ???????????RFC 2136 ????DNS ??????
# Debian / Ubuntu
apt install certbot python3-certbot-dns-rfc2136
# RHEL / Rocky / Alma
dnf install certbot python3-certbot-dns-rfc2136
2.2 NSupdate ??????
??DNS ???????????? TSIG ????????dnssec-keygen ??BIND ??tsigner ??????
# ??DNS ????????TSIG ???
dnssec-keygen -a HMAC-SHA256 -b 256 -n HOST letsencrypt-update
# ????????named.conf
cat >> /etc/bind/named.conf.local << 'KEYEOF'
key "letsencrypt-update" {
algorithm hmac-sha256;
secret "BASE64_ENCODED_SECRET_HERE";
};
zone "example.com" {
type master;
file "/etc/bind/db.example.com";
allow-update { key "letsencrypt-update"; };
};
KEYEOF
??certbot ????????????
cat > /etc/letsencrypt/nsupdate.ini << 'INIEOF'
dns_rfc2136_server = ns1.example.com
dns_rfc2136_port = 53
dns_rfc2136_name = letsencrypt-update
dns_rfc2136_secret = BASE64_ENCODED_SECRET_HERE
dns_rfc2136_algorithm = HMAC-SHA256
INIEOF
chmod 600 /etc/letsencrypt/nsupdate.ini
2.3 ???????????/h3>
certbot certonly \
--dns-rfc2136 \
--dns-rfc2136-credentials /etc/letsencrypt/nsupdate.ini \
-d "*.example.com" -d "example.com" \
--non-interactive --agree-tos \
--email admin@example.com
certbot certonly \
--dns-rfc2136 \
--dns-rfc2136-credentials /etc/letsencrypt/nsupdate.ini \
-d "*.example.com" -d "example.com" \
--non-interactive --agree-tos \
--email admin@example.com??????????????/etc/letsencrypt/live/example.com/???????????????
| ??? | ????/th> | ?????? |
|---|---|---|
fullchain.pem | ??????????????+ ??? CA??/td> | 644 |
privkey.pem | ??? | 600?????root |
cert.pem | ?????????????????CA??/td> | 644 |
chain.pem | ?????CA ??? | 644 |
2.4 ?????? hook ???
Let's Encrypt ????????? 90 ????ertbot ??systemd timer ?????????????????????????????????????????????????????????
cat > /etc/letsencrypt/renewal-hooks/deploy/reload-mail-services.sh << 'SH'
#!/bin/bash
# certbot deploy hook ??????????????????????set -e
DOMAINS=$(echo "$RENEWED_DOMAINS" | tr ',' ' ')
logger -t certbot "Certificate renewed for domains: $DOMAINS"
# Postfix SMTP TLS
if systemctl is-active --quiet postfix; then
postfix reload
logger -t certbot "Postfix reloaded"
fi
# Dovecot IMAP/POP3 TLS
if systemctl is-active --quiet dovecot; then
dovecot reload
logger -t certbot "Dovecot reloaded"
fi
# Nginx (??? MTA-STS web ?????
if systemctl is-active --quiet nginx; then
nginx -s reload
logger -t certbot "Nginx reloaded"
fi
SH
chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-mail-services.sh
???????????/p>
# ??????????????????????????hook ??????
certbot renew --dry-run
# ?????????
journalctl -u certbot.timer --since "7 days ago"
# ????????????
openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem \
-noout -enddate
????ostfix/Dovecot ??????
3.1 Postfix ???
Postfix ??? smtpd_tls_* ???????????? SMTP TLS??code>smtp_tls_* ?????? SMTP TLS???????????? Let's Encrypt ??symlink ????????certbot ?????????????????????
# /etc/postfix/main.cf ??TLS ??????
# ??? SMTP (smtpd)
smtpd_tls_cert_file = /etc/letsencrypt/live/example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/example.com/privkey.pem
smtpd_tls_security_level = may
# ??? SMTP (smtp)
smtp_tls_cert_file = /etc/letsencrypt/live/example.com/fullchain.pem
smtp_tls_key_file = /etc/letsencrypt/live/example.com/privkey.pem
smtp_tls_security_level = may
# ?????? 587 ??????????????submission ???????????????
# ?????465 (smtps) ???????????# smtpd_tls_cert_file = /etc/letsencrypt/live/smtp.example.com/fullchain.pem
????????ostfix ??postfix ?????????????????/etc/letsencrypt/archive/ ????????????????????postfix ?????? ssl-cert ???
usermod -aG ssl-cert postfix
# ??? /etc/letsencrypt/ ???????????chmod g+rx /etc/letsencrypt/live /etc/letsencrypt/archive
chmod 640 /etc/letsencrypt/archive/example.com/privkey*.pem
3.2 Dovecot ???
# /etc/dovecot/conf.d/10-ssl.conf
ssl = required
ssl_cert = </etc/letsencrypt/live/example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/example.com/privkey.pem
# ??IMAP ??POP3 ?????????
# ssl_alt_cert = </etc/letsencrypt/live/imap.example.com/fullchain.pem
# ssl_alt_key = </etc/letsencrypt/live/imap.example.com/privkey.pem
# ????TLS ??? ??RFC 7525 ?????? TLS 1.0/1.1
ssl_min_protocol = TLSv1.2
# ?????????????????ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
# ??? SSLv3 ??????????????ssl_prefer_server_ciphers = yes
3.3 ??? SMTPS??65 ????????????
RFC 8314 ?????? 587 STARTTLS ??? 465 ??? TLS?????? 465 ?????ostfix ?????????????smtps ?????????????????? 465 ??????????????/etc/letsencrypt/live/ symlink ???????????????
# /etc/postfix/master.cf
smtps inet n - n - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
# ???????????smtpd_tls_cert_file????????????? -o smtpd_tls_cert_file=/etc/letsencrypt/live/smtp.example.com/fullchain.pem
-o smtpd_tls_key_file=/etc/letsencrypt/live/smtp.example.com/privkey.pem
????CSP Stapling ?????FC 6066??/h2>
4.1 OCSP Stapling ???
OCSP??nline Certificate Status Protocol??? X.509 PKI ??????????????????????????????????????UA ?????MTA????????? CA ??OCSP ????????????????????????
- ????????A ?????????????????????
- ????????????TLS ??????????HTTP ???
- ????????A ??OCSP ????????????????????????soft-fail ???????????????
OCSP Stapling??FC 6066??LS Certificate Status Request Extension????????????????????? CA ??? OCSP ?????????????????? TLS ???????????"????????ginx ??1.3.7 ????????Apache httpd ??2.3.3 ?????????/p>
4.2 Nginx ?????OCSP Stapling
?????nginx ??? MTA-STS ???????????? Web ??????
# /etc/nginx/conf.d/mta-sts-ocsp.conf
server {
listen 443 ssl http2;
server_name mta-sts.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 1.1.1.1 valid=300s;
resolver_timeout 5s;
# ??????...
}
??? OCSP Stapling ???????????/p>
# ??? openssl ??? OCSP response ??????
openssl s_client -connect mta-sts.example.com:443 -tlsextdebug \
-status 2>&1 | grep -i "OCSP response"
# ?????????:
# OCSP response:
# OCSP Response Data:
# OCSP Response Status: successful (0x0)
# Response Type: Basic OCSP Response
# ??? OCSP response?????nginx ??????
tail -f /var/log/nginx/error.log | grep -i ocsp
4.3 Postfix ?????OCSP Stapling
Postfix ??3.1 ????????OCSP Stapling????? smtpd_tls_staple ??????????Postfix ??OCSP Stapling ????? OCSP ??????????????????
# /etc/postfix/main.cf
# ??? OCSP Stapling
smtpd_tls_staple = yes
# OCSP ?????????
smtpd_tls_staple_file = /var/spool/postfix/ocsp-cache
# ???????????OCSP ???
smtpd_tls_trust_chain_file = /etc/letsencrypt/live/example.com/chain.pem
??? systemd timer ?????? OCSP ?????/p>
cat > /usr/local/bin/refresh-ocsp-response.sh << 'SH'
#!/bin/bash
# ??? OCSP ?????Postfix ???
DOMAIN="example.com"
CERT="/etc/letsencrypt/live/${DOMAIN}/cert.pem"
CHAIN="/etc/letsencrypt/live/${DOMAIN}/chain.pem"
PRIVKEY="/etc/letsencrypt/live/${DOMAIN}/privkey.pem"
# ??cert.pem ?????OCSP ??????
OCSP_URL=$(openssl x509 -in "$CERT" -noout -ocsp_uri)
# ??OCSP ???????????openssl ocsp -issuer "$CHAIN" -cert "$CERT" \
-url "$OCSP_URL" -header "Host" "$(echo $OCSP_URL | sed 's|https\?://||;s|/.*||')" \
-respout /var/spool/postfix/ocsp-cache/example.com.ocsp \
-noverify 2>/dev/null
# Postfix ?????????response ????????? 644
chmod 644 /var/spool/postfix/ocsp-cache/example.com.ocsp
postfix reload
SH
chmod 755 /usr/local/bin/refresh-ocsp-response.sh
# ???????????? 8 ????????
cat > /etc/systemd/system/refresh-ocsp.service << 'UNIT'
[Unit]
Description=Refresh OCSP stapling response for Postfix
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/refresh-ocsp-response.sh
Unit
cat > /etc/systemd/system/refresh-ocsp.timer << 'TIMER'
[Unit]
Description=Refresh OCSP response every 8 hours
[Timer]
OnCalendar=*-*-* 00,08,16:00:00
Persistent=true
[Install]
WantedBy=timers.target
TIMER
systemctl daemon-reload
systemctl enable --now refresh-ocsp.timer
??? Postfix OCSP Stapling ?????
# ??? Postfix ?????? OCSP ????grep 'tls_staple' /var/log/mail.log
# ??openssl ??? SMTP ????????? OCSP ???
openssl s_client -starttls smtp -connect mx.example.com:25 \
-servername mx.example.com -tlsextdebug -status 2>&1 | \
grep -E "OCSP|TLS server extension"
????ertificate Transparency ???
5.1 CT ????????/h3>
Certificate Transparency??FC 6962???????????CA ????????????**????????? Merkle ?????*?????????????????????????? CT ????????????
- ??????????????????????????????????????
- ???????????/strong>?????30 ???????????/li>
- ??? CA ????????/strong>????????????
5.2 ??? ct-exposer/certspotter ???
???????certspotter??? SSLMate ?????????????? CT ?????????????????????
# ??? certspotter??? Go ????????go install software.sslmate.com/src/certspotter/cmd/certspotter@latest
# ?????????
mkdir -p /etc/certspotter
cat > /etc/certspotter/config.yaml << 'YAML'
# ???????????domains:
- example.com
- mail.example.com
- mx.example.com
# CT ????????oogle??igiCert??ectigo ???
logs:
- "https://ct.googleapis.com/logs/argon2022"
- "https://ct.googleapis.com/logs/argon2023"
- "https://ct.cloudflare.com/logs/nimbus2024"
- "https://ct.sectigo.com/logs/2024"
# ????????????webhook??mail ???
webhook: "https://alertmanager.example.com/api/v1/alerts"
YAML
# ??????
certspotter -config /etc/certspotter/config.yaml --first-run
# ???????????cron
echo "0 */6 * * * certspotter -config /etc/certspotter/config.yaml --report-new >> /var/log/certspotter.log 2>&1" \
> /etc/cron.d/certspotter
5.3 ??? crt.sh API ??????
crt.sh ????????? CT ?????????????????????????????????
# ??? example.com ???????????????????curl -s 'https://crt.sh/?q=%.example.com&output=json' | \
jq '.[] | {issuer: .issuer_name, not_before: .not_before, not_after: .not_after, fingerprint: .fingerprint}' | \
head -20
# ?????? ??????????????
cat > /usr/local/bin/ct-daily-monitor.sh << 'SH'
#!/bin/bash
DOMAIN="example.com"
LAST_KNOWN="/var/lib/ct-monitor/last_known.txt"
DAILY_REPORT="/tmp/ct_new_certs_${DOMAIN}.txt"
mkdir -p /var/lib/ct-monitor
# ???????????????
curl -s "https://crt.sh/?q=%.${DOMAIN}&output=json" | \
jq -r '.[].fingerprint' | sort > /tmp/ct_current.txt
# ??????
if [ -f "$LAST_KNOWN" ]; then
comm -13 "$LAST_KNOWN" /tmp/ct_current.txt > "$DAILY_REPORT"
if [ -s "$DAILY_REPORT" ]; then
mail -s "[ALERT] ??? ${DOMAIN} ????? admin@example.com < "$DAILY_REPORT"
fi
fi
cp /tmp/ct_current.txt "$LAST_KNOWN"
SH
chmod 755 /usr/local/bin/ct-daily-monitor.sh
# ??? cron
echo "0 8 * * * /usr/local/bin/ct-daily-monitor.sh" > /etc/cron.d/ct-daily-monitor
??????????????????????/h2>
6.1 ?????????????/h3>
| ??? | ??? | ?????/th> | ?????? | ?????? |
|---|---|---|---|---|
| CRL | X.509 CRL Distribution Points | ???CA ????????/td> | ??? | ???????????/td> |
| OCSP | RFC 2560 / RFC 5019 | ???????????/td> | ???????????/td> | ????/td> |
| OCSP Stapling | RFC 6066 / RFC 6961 | ???TLS ?????? | ??/td> | ?????? |
| CRLite | RFC 9331 | ?????? CRL ?????/td> | ??/td> | Firefox ??? |
6.2 ?????????????/h3>
???????????????????????????????????et's Encrypt ?????? certbot ?????/p>
# ?????????????????certbot revoke --cert-path /etc/letsencrypt/live/example.com/cert.pem \
--reason keycompromise
# ??? CA ???????????revoked.pem ?????certbot revoke --cert-path /etc/letsencrypt/live/example.com/cert.pem \
--reason keycompromise --key-path /etc/letsencrypt/live/example.com/privkey.pem
# ???????????????
certbot certonly --dns-rfc2136 -d "*.example.com" -d "example.com"
6.3 ????????????
cat > /usr/local/bin/cert-expiry-warning.sh << 'SH'
#!/bin/bash
# ???????Let's Encrypt ??????????????14 ?????WARN_DAYS=14
CRIT_DAYS=3
ADMIN="admin@example.com"
for cert_dir in /etc/letsencrypt/live/*/; do
cert="${cert_dir}fullchain.pem"
[ -f "$cert" ] || continue
expiry=$(openssl x509 -in "$cert" -noout -enddate | cut -d= -f2)
expiry_epoch=$(date -d "$expiry" +%s)
now_epoch=$(date +%s)
days_left=$(( (expiry_epoch - now_epoch) / 86400 ))
domain=$(basename "$cert_dir")
if [ "$days_left" -le 0 ]; then
echo "CRITICAL: Certificate for $domain EXPIRED on $expiry"
echo "???????? certbot renew --force-renewal" | \
mail -s "[CRITICAL] TLS ????????- $domain" "$ADMIN"
elif [ "$days_left" -le "$CRIT_DAYS" ]; then
echo "WARNING: Certificate for $domain expires in $days_left days ($expiry)"
echo "??? $domain ??? $days_left ???????? | \
mail -s "[WARNING] TLS ????????? - $domain" "$ADMIN"
elif [ "$days_left" -le "$WARN_DAYS" ]; then
echo "INFO: Certificate for $domain expires in $days_left days ($expiry)"
fi
done
SH
chmod 755 /usr/local/bin/cert-expiry-warning.sh
# ???????echo "0 9 * * * /usr/local/bin/cert-expiry-warning.sh" > /etc/cron.d/cert-expiry-warning
????? MX ?????????
?????? MX ?????????????????????????????strong>????????/strong>??strong>????????/p>
7.1 ???????????/h3>
????????MX ????????????????????????????/p>
# ??? MX ???????????????
# ??? rsync ??????????????rsync -avz --delete \
/etc/letsencrypt/live/example.com/ \
mx1.example.com:/etc/letsencrypt/live/example.com/
# ??????????????ssh mx1.example.com "certbot renew --post-hook 'postfix reload && dovecot reload'"
7.2 ??? ansible ?????MX ???
?????????????????? Ansible playbook ??????????MX ?????????
# ansible/playbooks/tls-cert-deploy.yml
---
- name: Deploy TLS certificates to all MX hosts
hosts: mail_servers
tasks:
- name: Sync certificate from primary to secondary
synchronize:
src: /etc/letsencrypt/live/example.com/
dest: /etc/letsencrypt/live/example.com/
rsync_opts:
- "--chown=root:ssl-cert"
- "--chmod=D2755,F640"
when: inventory_hostname != 'mx1'
- name: Restart Postfix
systemd:
name: postfix
state: reloaded
- name: Restart Dovecot
systemd:
name: dovecot
state: reloaded
- name: Restart Nginx
systemd:
name: nginx
state: reloaded
??????????????????????????MX ?????SAN ???????MX ????????????????*.example.com ???mx1.example.com??code>mx2.example.com ??????????????????????SAN ?????????????????MX ?????????????/p>
???????/h3>
- RFC 6066 ??Transport Layer Security (TLS) Extensions: Extension Definitions (OCSP Stapling). IETF, January 2011.
- RFC 6962 ??Certificate Transparency. IETF, June 2013.
- RFC 8314 ??Cleartext Considered Obsolete: Use of Transport Layer Security (TLS) for Email Submission and Access. IETF, February 2018.
- RFC 3207 ??SMTP Service Extension for Secure SMTP over Transport Layer Security. IETF, February 2002.
- RFC 7817 ??Updated Transport Layer Security (TLS) Server Identity Check Procedure for Email Related Protocols. IETF, March 2016.
- RFC 7525 ??Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS). IETF, May 2015.
- Let's Encrypt ??ACME Protocol. https://letsencrypt.org/how-it-works/
- SSLMate ??CertSpotter CT Log Monitor. https://sslmate.com/certspotter/
- NIST SP 800-177 Rev. 1 ??Trustworthy Email, Section 5.4: Certificate Management.
- M3AAWG ??Email TLS Certificate Management Best Practices (2025 Update).
引用本文
ztpop.net 知识库编辑. "????????TLS ?????????????????????????????" ztpop.net 知识库.
本站技术文章采用 CC-BY 4.0 许可,可自由引用,仅需标注来源 ztpop.net。
