NiceLeeのBlog 用爱发电 bilibili~

备忘录 证书与CF Workers KV Storage

2025-02-13
nIceLee

阅读:


前情提要: 我在一台机器上部署了acme.sh脚本,申请通配符证书,确保证书在这台机器上是一直有效的。
当机器有多台的时候,我想共用申请的证书,而不是在每一台上都再来一次。
这就要有一个存放证书的地方。
本着不额外花费资源的原则,托管我域名DNS的CF本身似乎是一个挺好的选择。

上传证书

  • 获取CF鉴权id和token
    需要Workers KV Storage ReadWorkers KV Storage Write权限

  • 创建 KV namespace
    仅需执行一次,需要获取NAMESPACE_ID

    ACCOUNT_ID="aaa"
    ACCOUNT_TOKEN="bbb"
    
    curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces \
      -H "Authorization: Bearer $ACCOUNT_TOKEN" \
      -H "Content-Type:application/json" \
      -d '{
        "title": "SSL Certs"
      }'
    

    从返回内容中获取.result.id示例

    {
      "result": {
        "id": ">>>>>>NAMESPACE_ID<<<<<<<<",
        "title": "SSL Certs",
        "supports_url_encoding": true
      },
      "success": true,
      "errors": [],
      "messages": []
    }
    
  • 上传证书公私钥 以上传公钥文件为例子,这个脚本在每次申请证书成功后执行。

    ACCOUNT_ID="aaa"
    ACCOUNT_TOKEN="bbb"
    NAMESPACE_ID="cccc"
      
    KEY_NAME="you_domain_cert_public"
    KEY_DATA=$(cat /path/to/you_domain_cert_public.pem)
      
    curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces/$NAMESPACE_ID/values/$KEY_NAME \
        -X PUT \
        -H "Authorization: Bearer $ACCOUNT_TOKEN" \
        -H "Content-Type:application/json" \
        -d "{ \"value\": \"$KEY_DATA\" }"
          
    KEY_NAME="you_domain_cert_private"
    KEY_DATA=$(cat /path/to/you_domain_cert_private.pem)
      
    curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces/$NAMESPACE_ID/values/$KEY_NAME \
        -X PUT \
        -H "Authorization: Bearer $ACCOUNT_TOKEN" \
        -H "Content-Type:application/json" \
        -d "{ \"value\": \"$KEY_DATA\" }"
    

同步证书

  • 创建 KV namespace
    crontab每天执行即可。
    脚本中的sed命令是针对证书内容,去掉第一个---之前的内容,和最后一个---之后的内容。
    这样不需要额外依赖jq来解析json。
#!/bin/bash

# 修改为你的CF配置
ACCOUNT_ID="aaa"
ACCOUNT_TOKEN="bbb"
NAMESPACE_ID="cccc"

CERT_PATH="${1:-/path/to/you_domain_cert_public.pem}"  # 修改为你的证书路径
KEY_PATH="${2:-/path/to/you_domain_cert_private.pem}"  # 修改为你的证书路径
EXPIRY_WARNING_DAYS=7  # 过期前多少天开始同步证书

# 获取证书过期时间的时间戳
EXPIRY_DATE=$(openssl x509 -in "$CERT_PATH" -noout -enddate | sed 's/^notAfter=//')
EXPIRY_TIMESTAMP=$(date -d "$EXPIRY_DATE" +%s)

# 获取当前时间的时间戳
CURRENT_TIMESTAMP=$(date +%s)

# 计算剩余秒数
REMAINING_SECONDS=$((EXPIRY_TIMESTAMP - CURRENT_TIMESTAMP))

# 计算剩余天数
REMAINING_DAYS=$((REMAINING_SECONDS / (60 * 60 * 24)))

# 获取过期日期 (YYYY-MM-DD)
EXPIRY_DATE=$(date -d @$EXPIRY_TIMESTAMP +%Y-%m-%d)


# 大于365的判断是因为一般都是几年十几年的自签的证书
if [ "$REMAINING_DAYS" -lt "$EXPIRY_WARNING_DAYS" ] || [ "$REMAINING_DAYS" -gt 365 ]; then
    echo "证书快要过期了,过期时间${EXPIRY_DATE},还剩 ${REMAINING_DAYS} 天"

    KEY_NAME="you_domain_cert_public"
    public_cert=$(curl -s https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces/$NAMESPACE_ID/values/$KEY_NAME -H "Authorization: Bearer $ACCOUNT_TOKEN" | sed ':a;N;$!ba;s/^[^---]*---/---/;s/---[^---]*$/---/')
    echo "$public_cert" > $CERT_PATH
    
    KEY_NAME="you_domain_cert_private"
    private_cert=$(curl -s https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/storage/kv/namespaces/$NAMESPACE_ID/values/$KEY_NAME -H "Authorization: Bearer $ACCOUNT_TOKEN" | sed ':a;N;$!ba;s/^[^---]*---/---/;s/---[^---]*$/---/')
    echo "$private_cert" > $KEY_PATH
    
    nginx -s reload
else
  echo "证书过期还早,过期时间${EXPIRY_DATE},还剩 ${REMAINING_DAYS} 天"
fi

相似文章

内容
隐藏