使用acme.sh部署RSA、ECC双证书

  1. 申请
  2. 启用
  3. 自动更新证书
  4. 自动续期+钉钉告警(参考脚本,根据实际自己改动)

ECC证书 相比 RSA证书, 密钥短了很少,但安全性还是有保证,ECC 是Elliptic curve cryptography的简写, 是一种建立公开密钥加密的算法,基于椭圆曲线。由于其密钥较短,运算速度较快,所以渐渐开始在一些网站上使用。但是由于有些老旧 浏览器/系统 不支持ECC证书,为了使他们能够访问,我们还得提供一份 RSA证书。

申请

下面这个脚本使用acme.sh配置、部署RSA、ECC双证书

根据自己的DNS提供商,按照DNSAPI对应着去申请API,并使用 export 命令声明变量

#!/bin/sh
DOMAIN="example.com"            # 域名
CERT_FOLDER="/etc/nginx/certs"  # 证书存放的目录,结尾不能是"/"字符
#export Ali_Key="123456AbCdEfGh1234567890"           # 阿里云
#export Ali_Secret="aBcDEfGhHiJkLmNOpQrStUvWxYz234"  # 阿里云
#export DP_Key="123456AbCdEfGh1234567890"            # DNSPod
#export DP_Id="aBcDEfGhHiJkLmNOpQrStUvWxYz234"       # DNSPod

#######################################################################

# 安装acme.sh
# apt install socat # 仅stand alone模式需要
curl https://get.acme.sh | sh
alias acme.sh='/root/.acme.sh/acme.sh'

acme.sh  --upgrade  --auto-upgrade                 # 更新acme.sh
acme.sh --set-default-ca  --server  letsencrypt    # 设置默认CA为let's Encrypt
# 申请RSA证书
acme.sh --issue -d ${DOMAIN} -d *.${DOMAIN} --dns dns_ali \
        --dnssleep 30 --ocsp --days 30 --keylength 2048

# 申请ECC证书
acme.sh --issue -d ${DOMAIN} -d *.${DOMAIN} --dns dns_ali \
        --dnssleep 30 --ocsp --days 30 --keylength ec-256

# 创建证书安装所需要的目录
mkdir ${CERT_FOLDER}
mkdir ${CERT_FOLDER}/rsa
mkdir ${CERT_FOLDER}/ecc

# 安装RSA证书
acme.sh --install-cert -d ${DOMAIN} \
        --cert-file       ${CERT_FOLDER}/rsa/$(DOMAIN).cer \
        --key-file        ${CERT_FOLDER}/rsa/$(DOMAIN).key \
        --fullchain-file  ${CERT_FOLDER}/rsa/$(DOMAIN).fullchain.cer \
        --reloadcmd       "systemctl restart nginx"

# 安装ECC证书
acme.sh --install-cert -d ${DOMAIN} --ecc \
        --cert-file       ${CERT_FOLDER}/ecc/$(DOMAIN).cer \
        --key-file        ${CERT_FOLDER}/ecc/$(DOMAIN).key \
        --fullchain-file  ${CERT_FOLDER}/ecc/$(DOMAIN).fullchain.cer.fullchain.pem \
        --reloadcmd       "systemctl restart nginx"

# 手动更新证书
#acme.sh --renew -d example.com --force
#acme.sh --renew -d example.com --force --ecc

启用

Web 服务器我使用的Nginx,一切准备妥当之后,将证书配置改为双份,一份填写ecc证书地址,另一份则填写rsa证书地址

ssl_certificate     /etc/nginx/certs/rsa/fullchain.rsa.cer;
ssl_certificate_key /etc/nginx/certs/rsa/rsa.key;

ssl_certificate     /etc/nginx/certs/ecc/fullchain.ecc.cer;
ssl_certificate_key /etc/nginx/certs/ecc/ecc.key;

修改ssl_ciphers

ssl_ciphers    ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE+AES128:RSA+AES128:ECDHE+AES256:RSA+AES256:ECDHE+3DES:RSA+3DES;

也可以参考Mozilla提供的

ssl_ciphers    ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS

重启nginx后使用ssllabs检查应该是能发现有两张证书的

自动更新证书

#!/usr/bin/env bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

DOMAIN="example.com"
CERT_FOLDER="/etc/nginx/certs"

systemctl stop nginx &> /dev/null
sleep 1
"/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" &> /dev/null
"/root/.acme.sh"/acme.sh --installcert -d ${DOMAIN} --fullchainpath ${CERT_FOLDER}/rsa/fullchain.cer --keypath ${CERT_FOLDER}/rsa/${DOMAIN}.key
"/root/.acme.sh"/acme.sh --installcert -d ${DOMAIN} --fullchainpath ${CERT_FOLDER}/ecc/fullchain.cer --keypath ${CERT_FOLDER}/ecc/${DOMAIN}.key --ecc
sleep 1
systemctl start nginx &> /dev/null

将这个脚本添加到crontab

0 3 * * 0 bash /root/.acme.sh/ssl_update.sh

自动续期+钉钉告警(参考脚本,根据实际自己改动)

#!/bin/bash

set -x

DOMAIN_LIST="
admin.example.com
api.example.com
www.example.com
"
SSL_DIR="/etc/nginx/certs"
WEBROOT="/var/nginx/html"
ACMESH="/root/.acme.sh/acme.sh"
NOTICE_DINGDING_TOBOT="https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

noticeDingding(){
  msg="{\"msgtype\": \"text\",\"text\": {\"content\": "\'"${1}"\'"},\"at\": {\"isAtAll\": true}}"
  curl "$NOTICE_DINGDING_TOBOT" -H 'Content-Type: application/json' -d "$msg"
}

applyFreeSSLCertificate(){
    status=0
    # 1、强制申请免费ssl证书
    $ACMESH --issue -d $domain -w $WEBROOT --force
    [ $? -eq 0 ] && status=`expr $status + 1`
    # 2、安装ssl证书到nginx
    $ACMESH --install-cert -d ${domain} --key-file "${SSL_DIR}/${domain}.key" --fullchain-file "${SSL_DIR}/${domain}.cer" --reloadcmd "nginx -s reload"  # 自动部署到nginx
    [ $? -eq 0 ] && status=`expr $status + 1`

    if [ $status -eq 2 ];then
      noticeDingding "申请并部署、续期(提前一周)免费ssl证书"${domain}"成功!"
    else
      noticeDingding "申请并部署、续期(提前一周)免费ssl证书"${domain}"失败!请手动执行本脚本程序再次申请、续期以观测失败原因!"
    fi
}

for domain in $DOMAIN_LIST;do
  echo "自动申请部署并续期ssl证书,域名=$domain"

  # 申请部署免费SSL证书
  # 如果证书文件不存在则自动申请并部署免费的SSL证书
  if [ ! -e ${SSL_DIR}/${domain}.cer ];then
    applyFreeSSLCertificate
  fi

  # 自动续期
  # 检查ssl证书到期时间,提前一周自动续期并部署新的ssl证书
  expirationTimeGMT=`openssl x509 -in ${SSL_DIR}/${domain}.cer -noout -dates|grep notAfter|awk -F '=' '{print $2}'`  # 证书到期GMT时间
  expirationTime=`date -d "$expirationTimeGMT" +%s`  # 证书到期时间,转换为以秒为单位的时间戳
  currTime=`date +%s`  # 当前时间戳

  echo "当前证书到期时间还有$(expr $(expr $expirationTime - $currTime) / 60 / 60 / 24)天"
  if [ $(expr $(expr $expirationTime - $currTime) / 60 / 60 / 24) -lt 7 ];then
    applyFreeSSLCertificate
  fi
done


转载请注明来源