ssl-tls-management
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSSL/TLS Management
SSL/TLS 证书管理
Manage certificates and secure communications across web servers, Kubernetes clusters, and internal services.
跨Web服务器、Kubernetes集群和内部服务管理证书与安全通信。
When to Use This Skill
何时使用该技能
Use this skill when:
- Setting up HTTPS for a new web application
- Automating certificate renewal with Let's Encrypt
- Deploying cert-manager in Kubernetes
- Configuring TLS for internal service-to-service communication
- Auditing cipher suites and TLS versions for compliance
- Responding to an expiring or compromised certificate
在以下场景中使用本技能:
- 为新Web应用配置HTTPS
- 通过Let's Encrypt实现证书续期自动化
- 在Kubernetes中部署cert-manager
- 为内部服务间通信配置TLS
- 审核加密套件与TLS版本以符合合规要求
- 处理证书过期或泄露问题
Prerequisites
前置条件
- Domain name with DNS control for public certificates
- Root/sudo access on web servers
- installed for Let's Encrypt
certbot - CLI available (installed by default on most Linux distros)
openssl - Kubernetes cluster with Helm for cert-manager deployment
- Understanding of X.509 certificate chain of trust
- 拥有可控制DNS的域名(用于公共证书)
- Web服务器的Root/sudo权限
- 已安装用于Let's Encrypt的
certbot - 具备命令行工具(多数Linux发行版默认安装)
openssl - 带有Helm的Kubernetes集群(用于部署cert-manager)
- 了解X.509证书信任链
Let's Encrypt with Certbot
使用Certbot管理Let's Encrypt证书
Installation and Certificate Issuance
安装与证书签发
bash
undefinedbash
undefinedInstall certbot (Ubuntu/Debian)
Install certbot (Ubuntu/Debian)
apt update && apt install -y certbot python3-certbot-nginx
apt update && apt install -y certbot python3-certbot-nginx
Obtain certificate for nginx (interactive)
Obtain certificate for nginx (interactive)
certbot --nginx -d example.com -d www.example.com
certbot --nginx -d example.com -d www.example.com
Non-interactive mode for automation
Non-interactive mode for automation
certbot certonly --nginx
-d example.com
-d www.example.com
--non-interactive
--agree-tos
--email admin@example.com
-d example.com
-d www.example.com
--non-interactive
--agree-tos
--email admin@example.com
certbot certonly --nginx
-d example.com
-d www.example.com
--non-interactive
--agree-tos
--email admin@example.com
-d example.com
-d www.example.com
--non-interactive
--agree-tos
--email admin@example.com
Standalone mode (when no web server is running)
Standalone mode (when no web server is running)
certbot certonly --standalone
-d example.com
--preferred-challenges http
-d example.com
--preferred-challenges http
certbot certonly --standalone
-d example.com
--preferred-challenges http
-d example.com
--preferred-challenges http
DNS challenge (for wildcard certs)
DNS challenge (for wildcard certs)
certbot certonly --manual
--preferred-challenges dns
-d "*.example.com"
-d example.com
--preferred-challenges dns
-d "*.example.com"
-d example.com
certbot certonly --manual
--preferred-challenges dns
-d "*.example.com"
-d example.com
--preferred-challenges dns
-d "*.example.com"
-d example.com
Using DNS plugin for automation (Cloudflare example)
Using DNS plugin for automation (Cloudflare example)
pip install certbot-dns-cloudflare
cat > /etc/letsencrypt/cloudflare.ini << 'EOF'
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
EOF
chmod 600 /etc/letsencrypt/cloudflare.ini
certbot certonly --dns-cloudflare
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini
-d "*.example.com"
-d example.com
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini
-d "*.example.com"
-d example.com
undefinedpip install certbot-dns-cloudflare
cat > /etc/letsencrypt/cloudflare.ini << 'EOF'
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
EOF
chmod 600 /etc/letsencrypt/cloudflare.ini
certbot certonly --dns-cloudflare
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini
-d "*.example.com"
-d example.com
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini
-d "*.example.com"
-d example.com
undefinedRenewal Automation
续期自动化
bash
undefinedbash
undefinedTest renewal
Test renewal
certbot renew --dry-run
certbot renew --dry-run
Systemd timer (preferred over cron)
Systemd timer (preferred over cron)
cat > /etc/systemd/system/certbot-renewal.service << 'EOF'
[Unit]
Description=Certbot certificate renewal
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"
EOF
cat > /etc/systemd/system/certbot-renewal.timer << 'EOF'
[Unit]
Description=Run certbot renewal twice daily
[Timer]
OnCalendar=--* 00,12:00:00
RandomizedDelaySec=3600
Persistent=true
[Install]
WantedBy=timers.target
EOF
systemctl enable --now certbot-renewal.timer
cat > /etc/systemd/system/certbot-renewal.service << 'EOF'
[Unit]
Description=Certbot certificate renewal
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"
EOF
cat > /etc/systemd/system/certbot-renewal.timer << 'EOF'
[Unit]
Description=Run certbot renewal twice daily
[Timer]
OnCalendar=--* 00,12:00:00
RandomizedDelaySec=3600
Persistent=true
[Install]
WantedBy=timers.target
EOF
systemctl enable --now certbot-renewal.timer
Verify timer is active
Verify timer is active
systemctl list-timers certbot-renewal.timer
systemctl list-timers certbot-renewal.timer
Renewal hooks for post-renewal actions
Renewal hooks for post-renewal actions
mkdir -p /etc/letsencrypt/renewal-hooks/deploy
cat > /etc/letsencrypt/renewal-hooks/deploy/reload-services.sh << 'HOOK'
#!/bin/bash
systemctl reload nginx
mkdir -p /etc/letsencrypt/renewal-hooks/deploy
cat > /etc/letsencrypt/renewal-hooks/deploy/reload-services.sh << 'HOOK'
#!/bin/bash
systemctl reload nginx
Also reload other services using the cert
Also reload other services using the cert
systemctl reload haproxy 2>/dev/null || true
HOOK
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-services.sh
undefinedsystemctl reload haproxy 2>/dev/null || true
HOOK
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-services.sh
undefinedcert-manager for Kubernetes
Kubernetes中的cert-manager
Installation
安装
bash
undefinedbash
undefinedInstall with Helm
Install with Helm
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager
--namespace cert-manager
--create-namespace
--version v1.14.0
--set installCRDs=true
--set prometheus.enabled=true
--namespace cert-manager
--create-namespace
--version v1.14.0
--set installCRDs=true
--set prometheus.enabled=true
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install cert-manager jetstack/cert-manager
--namespace cert-manager
--create-namespace
--version v1.14.0
--set installCRDs=true
--set prometheus.enabled=true
--namespace cert-manager
--create-namespace
--version v1.14.0
--set installCRDs=true
--set prometheus.enabled=true
Verify installation
Verify installation
kubectl get pods -n cert-manager
kubectl get crds | grep cert-manager
undefinedkubectl get pods -n cert-manager
kubectl get crds | grep cert-manager
undefinedClusterIssuer Configurations
ClusterIssuer配置
yaml
undefinedyaml
undefinedletsencrypt-staging (use for testing first)
letsencrypt-staging (use for testing first)
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-staging spec: acme: server: https://acme-staging-v02.api.letsencrypt.org/directory email: admin@example.com privateKeySecretRef: name: letsencrypt-staging solvers: - http01: ingress: class: nginx
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-staging spec: acme: server: https://acme-staging-v02.api.letsencrypt.org/directory email: admin@example.com privateKeySecretRef: name: letsencrypt-staging solvers: - http01: ingress: class: nginx
letsencrypt-prod
letsencrypt-prod
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: admin@example.com privateKeySecretRef: name: letsencrypt-prod solvers: - http01: ingress: class: nginx
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: admin@example.com privateKeySecretRef: name: letsencrypt-prod solvers: - http01: ingress: class: nginx
DNS challenge solver (for wildcard certs with Cloudflare)
DNS challenge solver (for wildcard certs with Cloudflare)
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod-dns spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: admin@example.com privateKeySecretRef: name: letsencrypt-prod-dns solvers: - dns01: cloudflare: apiTokenSecretRef: name: cloudflare-api-token key: api-token
apiVersion: cert-manager.io/v1 kind: ClusterIssuer metadata: name: letsencrypt-prod-dns spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: admin@example.com privateKeySecretRef: name: letsencrypt-prod-dns solvers: - dns01: cloudflare: apiTokenSecretRef: name: cloudflare-api-token key: api-token
Self-signed CA issuer for internal services
Self-signed CA issuer for internal services
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned-ca
spec:
selfSigned: {}
undefinedapiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: selfsigned-ca
spec:
selfSigned: {}
undefinedCertificate Resources
证书资源
yaml
undefinedyaml
undefinedPublic-facing certificate
Public-facing certificate
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: example-cert namespace: default spec: secretName: example-tls issuerRef: name: letsencrypt-prod kind: ClusterIssuer dnsNames: - example.com - www.example.com duration: 2160h # 90 days renewBefore: 720h # 30 days before expiry
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: example-cert namespace: default spec: secretName: example-tls issuerRef: name: letsencrypt-prod kind: ClusterIssuer dnsNames: - example.com - www.example.com duration: 2160h # 90 days renewBefore: 720h # 30 days before expiry
Wildcard certificate
Wildcard certificate
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: wildcard-cert namespace: default spec: secretName: wildcard-tls issuerRef: name: letsencrypt-prod-dns kind: ClusterIssuer dnsNames: - "*.example.com" - example.com
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: wildcard-cert namespace: default spec: secretName: wildcard-tls issuerRef: name: letsencrypt-prod-dns kind: ClusterIssuer dnsNames: - "*.example.com" - example.com
Ingress with automatic TLS
Ingress with automatic TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- example.com
secretName: example-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
undefinedapiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- example.com
secretName: example-tls
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web
port:
number: 80
undefinedOpenSSL Commands Reference
OpenSSL命令参考
bash
undefinedbash
undefinedGenerate a private key
Generate a private key
openssl genrsa -out server.key 4096
openssl genrsa -out server.key 4096
Generate an ECDSA key (preferred for performance)
Generate an ECDSA key (preferred for performance)
openssl ecparam -genkey -name prime256v1 -out server-ec.key
openssl ecparam -genkey -name prime256v1 -out server-ec.key
Generate a CSR (Certificate Signing Request)
Generate a CSR (Certificate Signing Request)
openssl req -new -key server.key -out server.csr
-subj "/C=US/ST=California/L=San Francisco/O=Acme Corp/CN=example.com"
-subj "/C=US/ST=California/L=San Francisco/O=Acme Corp/CN=example.com"
openssl req -new -key server.key -out server.csr
-subj "/C=US/ST=California/L=San Francisco/O=Acme Corp/CN=example.com"
-subj "/C=US/ST=California/L=San Francisco/O=Acme Corp/CN=example.com"
Generate CSR with SAN (Subject Alternative Names)
Generate CSR with SAN (Subject Alternative Names)
openssl req -new -key server.key -out server.csr -config <(cat <<EOF
[req]
default_bits = 4096
distinguished_name = dn
req_extensions = san
prompt = no
[dn]
CN = example.com
O = Acme Corp
C = US
[san]
subjectAltName = DNS:example.com,DNS:www.example.com,DNS:api.example.com
EOF
)
openssl req -new -key server.key -out server.csr -config <(cat <<EOF
[req]
default_bits = 4096
distinguished_name = dn
req_extensions = san
prompt = no
[dn]
CN = example.com
O = Acme Corp
C = US
[san]
subjectAltName = DNS:example.com,DNS:www.example.com,DNS:api.example.com
EOF
)
Generate self-signed certificate (development/testing)
Generate self-signed certificate (development/testing)
openssl req -x509 -nodes -days 365 -newkey rsa:4096
-keyout selfsigned.key -out selfsigned.crt
-subj "/CN=localhost"
-keyout selfsigned.key -out selfsigned.crt
-subj "/CN=localhost"
openssl req -x509 -nodes -days 365 -newkey rsa:4096
-keyout selfsigned.key -out selfsigned.crt
-subj "/CN=localhost"
-keyout selfsigned.key -out selfsigned.crt
-subj "/CN=localhost"
View certificate details
View certificate details
openssl x509 -in cert.pem -noout -text
openssl x509 -in cert.pem -noout -text
Check certificate expiration date
Check certificate expiration date
openssl x509 -in cert.pem -noout -dates
openssl x509 -in cert.pem -noout -dates
Check remote certificate
Check remote certificate
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null |
openssl x509 -noout -dates -subject -issuer
openssl x509 -noout -dates -subject -issuer
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null |
openssl x509 -noout -dates -subject -issuer
openssl x509 -noout -dates -subject -issuer
Verify certificate chain
Verify certificate chain
openssl verify -CAfile ca-bundle.crt server.crt
openssl verify -CAfile ca-bundle.crt server.crt
Check certificate chain from remote server
Check certificate chain from remote server
openssl s_client -connect example.com:443 -showcerts 2>/dev/null |
openssl x509 -noout -text
openssl x509 -noout -text
openssl s_client -connect example.com:443 -showcerts 2>/dev/null |
openssl x509 -noout -text
openssl x509 -noout -text
Convert PEM to PKCS12
Convert PEM to PKCS12
openssl pkcs12 -export -out cert.pfx -inkey server.key -in server.crt -certfile ca.crt
openssl pkcs12 -export -out cert.pfx -inkey server.key -in server.crt -certfile ca.crt
Convert PKCS12 to PEM
Convert PKCS12 to PEM
openssl pkcs12 -in cert.pfx -out cert.pem -nodes
openssl pkcs12 -in cert.pfx -out cert.pem -nodes
Test TLS connection and cipher negotiation
Test TLS connection and cipher negotiation
openssl s_client -connect example.com:443 -tls1_3
openssl s_client -connect example.com:443 -cipher 'ECDHE-RSA-AES256-GCM-SHA384'
undefinedopenssl s_client -connect example.com:443 -tls1_3
openssl s_client -connect example.com:443 -cipher 'ECDHE-RSA-AES256-GCM-SHA384'
undefinedStrong TLS Configuration
安全TLS配置
Nginx
Nginx
nginx
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Protocol versions
ssl_protocols TLSv1.2 TLSv1.3;
# Cipher suites (TLS 1.2)
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# Session settings
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Security headers
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
# HTTP to HTTPS redirect (in separate server block)
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}nginx
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Protocol versions
ssl_protocols TLSv1.2 TLSv1.3;
# Cipher suites (TLS 1.2)
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# Session settings
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Security headers
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
# HTTP to HTTPS redirect (in separate server block)
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}Apache
Apache
apache
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
SSLUseStapling on
SSLStaplingCache shmcb:/tmp/stapling_cache(128000)
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
</VirtualHost>apache
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
SSLUseStapling on
SSLStaplingCache shmcb:/tmp/stapling_cache(128000)
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
</VirtualHost>Certificate Monitoring
证书监控
bash
#!/bin/bashbash
#!/bin/bashcert-monitor.sh - Monitor certificate expiration across hosts
cert-monitor.sh - Monitor certificate expiration across hosts
WARN_DAYS=30
CRIT_DAYS=7
HOSTS=(
"example.com:443"
"api.example.com:443"
"admin.example.com:443"
)
for host in "${HOSTS[@]}"; do
expiry=$(echo | openssl s_client -connect "$host" -servername "${host%%:*}" 2>/dev/null |
openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
if [ -z "$expiry" ]; then
echo "ERROR: Cannot connect to $host"
continue
fi
expiry_epoch=$(date -d "$expiry" +%s)
now_epoch=$(date +%s)
days_left=$(( (expiry_epoch - now_epoch) / 86400 ))
if [ "$days_left" -le "$CRIT_DAYS" ]; then
echo "CRITICAL: $host expires in $days_left days ($expiry)"
elif [ "$days_left" -le "$WARN_DAYS" ]; then
echo "WARNING: $host expires in $days_left days ($expiry)"
else
echo "OK: $host expires in $days_left days ($expiry)"
fi
done
undefinedWARN_DAYS=30
CRIT_DAYS=7
HOSTS=(
"example.com:443"
"api.example.com:443"
"admin.example.com:443"
)
for host in "${HOSTS[@]}"; do
expiry=$(echo | openssl s_client -connect "$host" -servername "${host%%:*}" 2>/dev/null |
openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
if [ -z "$expiry" ]; then
echo "ERROR: Cannot connect to $host"
continue
fi
expiry_epoch=$(date -d "$expiry" +%s)
now_epoch=$(date +%s)
days_left=$(( (expiry_epoch - now_epoch) / 86400 ))
if [ "$days_left" -le "$CRIT_DAYS" ]; then
echo "CRITICAL: $host expires in $days_left days ($expiry)"
elif [ "$days_left" -le "$WARN_DAYS" ]; then
echo "WARNING: $host expires in $days_left days ($expiry)"
else
echo "OK: $host expires in $days_left days ($expiry)"
fi
done
undefinedPrometheus cert-manager Metrics
Prometheus cert-manager指标
yaml
undefinedyaml
undefinedAlert on expiring certificates in Kubernetes
Alert on expiring certificates in Kubernetes
groups:
- name: cert-manager
rules:
-
alert: CertificateExpiringSoon expr: certmanager_certificate_expiration_timestamp_seconds - time() < 7 * 24 * 3600 for: 1h labels: severity: critical annotations: summary: "Certificate {{ $labels.name }} expires in less than 7 days"
-
alert: CertificateNotReady expr: certmanager_certificate_ready_status{condition="True"} == 0 for: 15m labels: severity: warning annotations: summary: "Certificate {{ $labels.name }} is not ready"
-
undefinedgroups:
- name: cert-manager
rules:
-
alert: CertificateExpiringSoon expr: certmanager_certificate_expiration_timestamp_seconds - time() < 7 * 24 * 3600 for: 1h labels: severity: critical annotations: summary: "Certificate {{ $labels.name }} expires in less than 7 days"
-
alert: CertificateNotReady expr: certmanager_certificate_ready_status{condition="True"} == 0 for: 15m labels: severity: warning annotations: summary: "Certificate {{ $labels.name }} is not ready"
-
undefinedTroubleshooting
故障排查
| Problem | Cause | Solution |
|---|---|---|
| Certbot fails with "connection refused" | Port 80 blocked by firewall | Open port 80 for ACME HTTP-01 challenge |
| "Too many certificates already issued" | Let's Encrypt rate limit hit | Use staging endpoint for testing; wait for rate limit reset |
| cert-manager challenge stuck pending | Ingress or DNS misconfigured | Check |
| Mixed content warnings | HTTP resources on HTTPS page | Update all asset URLs to HTTPS; use CSP headers |
| OCSP stapling not working | Resolver not configured | Add |
| Intermediate cert missing | Incomplete chain served | Use |
| TLS handshake failure | Client doesn't support offered ciphers | Add TLS 1.2 support; check cipher suite compatibility |
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Certbot提示“connection refused” | 防火墙阻断了80端口 | 开放80端口以支持ACME HTTP-01挑战 |
| “Too many certificates already issued” | 触发了Let's Encrypt的速率限制 | 使用测试环境端点进行测试;等待速率限制重置 |
| cert-manager挑战处于pending状态 | Ingress或DNS配置错误 | 查看 |
| 混合内容警告 | HTTPS页面中存在HTTP资源 | 将所有资源URL更新为HTTPS;使用CSP头部 |
| OCSP stapling无法工作 | 未配置解析器 | 在nginx中添加 |
| 缺少中间证书 | 证书链不完整 | 使用 |
| TLS握手失败 | 客户端不支持提供的加密套件 | 添加TLS 1.2支持;检查加密套件兼容性 |
Best Practices
最佳实践
- Automate renewal with systemd timers or cert-manager
- Monitor expiration dates with alerting (30-day and 7-day warnings)
- Use only TLS 1.2 and TLS 1.3
- Enable HSTS with long max-age and includeSubDomains
- Enable OCSP stapling to improve handshake performance
- Use ECDSA keys for better performance where possible
- Test configuration with SSL Labs (ssllabs.com/ssltest)
- Keep private keys secure with proper file permissions (0600)
- Rotate certificates before expiry, not after
- Maintain a certificate inventory across all services
- 使用systemd定时器或cert-manager实现续期自动化
- 设置告警监控证书过期(提前30天和7天预警)
- 仅使用TLS 1.2和TLS 1.3版本
- 启用HSTS并设置较长的max-age及includeSubDomains
- 启用OCSP stapling以提升握手性能
- 尽可能使用ECDSA密钥以获得更好性能
- 使用SSL Labs(ssllabs.com/ssltest)测试配置
- 通过正确的文件权限(0600)保护私钥安全
- 在证书过期前完成轮换,而非过期后
- 维护所有服务的证书清单
Related Skills
相关技能
- hashicorp-vault - PKI management
- waf-setup - Web protection
- zero-trust - mTLS and identity-based access
- hashicorp-vault - PKI管理
- waf-setup - Web防护
- zero-trust - mTLS与基于身份的访问