自动更新DNSPod域名的Let's Encrypt通配符证书

计划给自己的所有域名和子域名配置一个通用 HTTPS证书,包含以下 DNS Name:

DNS Name=*.annhe.net
DNS Name=*.tecbbs.com
DNS Name=annhe.net
DNS Name=tecbbs.com

新申请证书

使用 certbot-auto 申请通配符证书的方法如下

./certbot-auto --server https://acme-v02.api.letsencrypt.org/directory -d "*.tecbbs.com,tecbbs.com,*.annhe.net,annhe.net" --manual --preferred-challenges dns-01 certonly

像这样通配符域名和根域名都申请证书的情况,需要添加两条 TXT 记录

# dig _acme-challenge.annhe.net TXT +short
"KFUyjyiRzP80s6QCL_zrEeyzyhrXrtLicsmUpN9lifQ"
"FGq8ljI24pHy173X3PCQrO3L_B17c9R1fqfTqzAfGvE"

手工更新证书

使用如下命令,但是需要手工修改 TXT 记录。

certbot-auto renew

自动更新证书

certbot-auto 支持 hook,可以在 auth hook 里验证 DNS 记录,调用脚本如下:

#!/bin/bash

DIR=$(cd `dirname $0`;pwd)

$DIR/certbot-auto renew --manual-auth-hook $DIR/dnspod.sh --post-hook "/etc/init.d/nginx reload"

auth hook 脚本基于参考资料1 修改,期望支持多 TXT 记录的情况,暂未验证,稀里糊涂就更新成功了,只能等 3 个月后再看有没有 bug 了(2020.8.13已成功验证)。

#!/bin/bash

#
# Create: certbot certonly --manual --preferred-challenges dns-01 --email mail@domain.com -d laravel.run -d *.laravel.run --server https://acme-v02.api.letsencrypt.org/directory --manual-auth-hook /path/to/certbot-auth-dnspod.sh
# Renew:  certbot renew --manual-auth-hook /path/to/certbot-auth-dnspod.sh
#

# https://www.dnspod.cn/console/user/security
API_TOKEN="id,token"

USER_AGENT="AnDNS/1.0.0 (admin@annhe.net)"
DOMAIN=$(expr match "$CERTBOT_DOMAIN" '.*\.\(.*\..*\)')
[ -z "$DOMAIN" ] && DOMAIN="$CERTBOT_DOMAIN"

if [ -z "$API_TOKEN" ]; then
    [ -f /etc/dnspod_token_$DOMAIN ] && API_TOKEN=$(cat /etc/dnspod_token_$DOMAIN)
fi

if [ -z "$API_TOKEN" ]; then
    [ -f /etc/dnspod_token ] && API_TOKEN=$(cat /etc/dnspod_token)
fi

if [ -z "$API_TOKEN" ]; then
    API_TOKEN="$DNSPOD_TOKEN"
fi

PARAMS="login_token=$API_TOKEN&format=json"

echo "\
CERTBOT_DOMAIN: $CERTBOT_DOMAIN
DOMAIN:         $DOMAIN
VALIDATION:     $CERTBOT_VALIDATION"
#echo "PARAMS:         $PARAMS"

if [ -f /tmp/CERTBOT_$CERTBOT_DOMAIN/VALIDATION ]; then
    VALIDATION_PRE=$(cat /tmp/CERTBOT_$CERTBOT_DOMAIN/VALIDATION)
    if [ "$CERTBOT_VALIDATION" = "$VALIDATION_PRE" ]; then
        echo "Same Validation: $CERTBOT_VALIDATION"
        exit
    fi
fi

RECORDS=$(curl -s -X POST "https://dnsapi.cn/Record.List" \
    -H "User-Agent: $USER_AGENT" \
    -d "$PARAMS&domain=$CERTBOT_DOMAIN&keyword=_acme-challenge" | jq .records[].id |tr -d '"' |tr '\n' ' ')

echo "\
RECORDS:        $RECORDS"

sleep 3

function SelectRecord() {
    # param 1: records
    TMPFILE=/tmp/CERTBOT_WILDCARD_${CERTBOT_DOMAIN}_RECORD_ID
    IDS="$1"
    if [ -f $TMPFILE ];then
        PRE_ID=`cat $TMPFILE`
    fi
    
    SELECTED=`echo $IDS |awk '{print $1}'`
    if [ "$PRE_ID"x == "$SELECTED"x ];then
        SELECTED=`echo $IDS |awk '{print $NF}'`
    fi
    
    echo $SELECTED > $TMPFILE
    echo $SELECTED
}

if [ -n "$RECORDS" ]; then
    # 通配符域名,两个 TXT记录的情况(*.domain.com, domain.com)
    RECORD_ID=`SelectRecord "$RECORDS"`
    RECORD_ID=$(curl -s -X POST "https://dnsapi.cn/Record.Modify" \
        -H "User-Agent: $USER_AGENT" \
        -d "$PARAMS&domain=$CERTBOT_DOMAIN&sub_domain=_acme-challenge&record_type=TXT&value=$CERTBOT_VALIDATION&record_line=默认&record_id=$RECORD_ID" |jq .records[0].id |tr -d '"')
else
    RECORD_ID=$(curl -s -X POST "https://dnsapi.cn/Record.Create" \
        -H "User-Agent: $USER_AGENT" \
        -d "$PARAMS&domain=$CERTBOT_DOMAIN&sub_domain=_acme-challenge&record_type=TXT&value=$CERTBOT_VALIDATION&record_line=默认" |jq .records[0].id |tr -d '"')
fi

echo "\
RECORD_ID:      $RECORD_ID"

# Save info for cleanup
if [ ! -d /tmp/CERTBOT_$CERTBOT_DOMAIN ]; then
    mkdir -m 0700 /tmp/CERTBOT_$CERTBOT_DOMAIN
fi
echo $DOMAIN > /tmp/CERTBOT_$CERTBOT_DOMAIN/DOMAIN
echo $RECORD_ID > /tmp/CERTBOT_$CERTBOT_DOMAIN/RECORD_ID
echo $CERTBOT_VALIDATION > /tmp/CERTBOT_$CERTBOT_DOMAIN/VALIDATION

# Sleep to make sure the change has time to propagate over to DNS
sleep 25

参考资料

1. https://www.wzs.cc/blog/free-ssl
2. certbot-auto: https://github.com/certbot/certbot/blob/master/certbot-auto
3. certbot-auto: https://certbot.eff.org/docs/install.html#certbot-auto

One thought on “自动更新DNSPod域名的Let's Encrypt通配符证书

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注