使用七牛云 API 上传 letsencrypt SSL 证书并绑定到 CDN

Scroll Down

可先阅读 CentOS7 Certbot 自动更新 Let's Encrypt SSL 证书(Nginx,https) 一文。

certbot 生成的 letsencrypt 证书,可惜只有3个月有效期,好在可以无限续命,nginx 配置在上文中已经实现了自动刷新证书。

另外笔者使用了七牛云的 CDN,同样需要SSL证书,但是每次更新后都需要手动上传。今日下班后闲着无聊研究了一下七牛的API,不想使用 Java 等程序实现,感觉太重,想找一个轻量化的方案,研究了一晚上,简单实现了证书上传脚本。

1.上传证书 & 修改 CDN 证书 python 脚本

本人 python 技能很渣,勉强实现了可以运行的脚本。。基于 python3,python2 不保证可以运行。

# -*- coding: utf-8 -*-
from qiniu import Auth
import os
import sys
import requests
import datetime

# 从命令行参数列表中读取cdn域名
cert_domain = sys.argv[1]

access_key = ''
secret_key = ''

if len(sys.argv) < 3:
    #从环境变量中获取 Access Key 和 Secret Key
    access_key = os.getenv('QINIU_ACCESS_KEY')
    secret_key = os.getenv('QINIU_SECRET_KEY')

access_key = sys.argv[2]
print('QINIU_ACCESS_KEY: ' + access_key)
secret_key = sys.argv[3]
print('QINIU_SECRET_KEY: ' + secret_key)

# 构建七牛鉴权对象
auth = Auth(access_key, secret_key)

# 上传证书
## 上传 api 地址
sslcertUploadUrl = 'http://api.qiniu.com/sslcert'
## 生成 上传证书 api accesstoken
sslcert_accesstoken = auth.token_of_request(sslcertUploadUrl)
print('上传证书 api accesstoken: ' + sslcert_accesstoken)

## 证书信息
sslcertFolder = '/etc/letsencrypt/live/' + cert_domain
sslcertPriFile = open(sslcertFolder + '/privkey.pem')
sslcertChainFile = open(sslcertFolder + '/fullchain.pem')
sslcertPriStr = sslcertPriFile.read()
sslcertChainStr = sslcertChainFile.read()
nowDate = datetime.date.today().strftime("%Y%m%d")
sslcertData = {
    'name': cert_domain + '-letsencrypt-' + nowDate,
    'common_name': cert_domain,
    'pri': sslcertPriStr,
    'ca': sslcertChainStr
}
sslcertHeaders = {
    'Authorization': 'QBox ' + sslcert_accesstoken,
    'Content-Type': 'application/json'
}
print('证书JSON数据如下:')
print(sslcertData)
## 执行请求
sslcertUploadResponse = requests.post(sslcertUploadUrl, json=sslcertData, headers=sslcertHeaders).json()
print(sslcertUploadResponse)
certID = sslcertUploadResponse['certID']
if certID is None:
    print('证书上传失败!')
    sys.exit()

# 修改 cdn 证书
## 修改证书 api 地址
cdnHttpsconfUrl = 'http://api.qiniu.com/domain/{}/httpsconf'.format(cert_domain)
## 生成 cdn 修改证书 api accesstoken
cdn_httpsconf_accesstoken = auth.token_of_request(cdnHttpsconfUrl)
print('修改证书 api accesstoken: ' + cdn_httpsconf_accesstoken)
## 执行修改请求
httpsconfData = {
    'certId': certID,
    'forceHttps': False,
    'http2Enable': True
}
httpsconfHeaders = {
    'Authorization': 'QBox ' + cdn_httpsconf_accesstoken,
    'Content-Type': 'application/json'
}
httpsconfResponse = requests.put(cdnHttpsconfUrl, json=httpsconfData, headers=httpsconfHeaders).json()
print(httpsconfResponse)
print('修改七牛 CDN SSL 证书完成~')

1.1 运行脚本

运行前需要先安装 qiniu python sdk

pip3 install qiniu

安装后,运行脚本,需要在参数列表指定 cdn 域名和七牛密钥(个人中心-密钥管理处获取)

python3 qiniu_cdn_ssl_cert_auto_renew.py xxx.yyy.com {qiniu_AK} {qiniu_SK}

如果配置了环境变量 QINIU_ACCESS_KEY、QINIU_SECRET_KEY 则无需在参数指定七牛密钥,可直接使用以下命令:

python3 qiniu_cdn_ssl_cert_auto_renew.py xxx.yyy.com

上传证书 & 修改 CDN 证书 shell 脚本

shell 脚本无法自动生成 accesstoken,已废弃,请参考上一章节 python 脚本方案

废话不多说,直接上成品脚本

#!/bin/bash
## V1.0.0.20200516

## 七牛证书accesstoken(需要根据api文档计算出,旧版api和参数无关,只与uri相关)
sslcert_accesstoken='aaa:bbb='

echo '############# 开始上传七牛SSL证书。。。'
## 从参数列表获取域名
cert_domain=halo.cdn.sherlocky.com
echo "域名:$cert_domain"

## 指定证书目录位置
cert_live_path='/etc/letsencrypt/live/'$cert_domain
echo "证书目录:$cert_live_path"

## 替换私钥和证书链中换行为\n,七牛云接口需要
sslcert_pri=`sed ':a;N;s/\n/\\\n/;ta;' $cert_live_path/privkey.pem`
sslcert_ca=`sed ':a;N;s/\n/\\\n/;ta;' $cert_live_path/fullchain.pem`

## 获取当前日期
sslcert_date=`date '+%Y%m%d'`
echo "当前日期:$sslcert_date"

## 将证书链和私钥json写入本地临时文件,作为api post的请求body
sslcert_tmp=/tmp/qiniu_sslcert_tmp
echo '{"name":"'$cert_domain'-letsencrypt-'$sslcert_date'","common_name":"'$cert_domain'","pri":"'$sslcert_pri'","ca":"'$sslcert_ca'"}' > $sslcert_tmp
echo "将证书上传信息写入临时文件 $sslcert_tmp 成功"

## 上传证书,-v 展示执行过程,-d '@file' 读取临时文件中的证书信息
sslcert_result=/tmp/qiniu_sslcert_result
curl -v -X POST http://api.qiniu.com/sslcert -H 'Content-Type: application/json' -H 'Authorization: QBox '$sslcert_accesstoken -d '@'$sslcert_tmp > $sslcert_result
echo '
############# 上传七牛SSL证书完成~'

## 形如 {"code":200,"error":"","certID":"5ebe9dab54be51671600130c"}
cat $sslcert_result

## 获取 certid
sslcert_certid=`awk -F"\"" '{ print $10 }' $sslcert_result`
echo '上传后证书的id:$sslcert_certid'

## 七牛证书cdn accesstoken(需要根据api文档计算出,旧版api和参数无关,只与uri相关)
sslcert_cdn_accesstoken='xxx:yyy='

## 修改 cdn 证书
curl -v -X PUT http://api.qiniu.com/domain/$cert_domain/httpsconf -H 'Content-Type: application/json' -H 'Authorization: QBox '$sslcert_cdn_accesstoken -d '{"certId":"'$sslcert_certid'","forceHttps":false,"http2Enable":true}'

echo '
############# 修改CDN SSL证书完成~'

脚本中的sslcert_accesstokensslcert_cdn_accesstoken需要使用 API 中方法计算,官方建议在服务端实现,这里我为了方便,直接写到了脚本中。

七牛官方文档地址:
API接入方式管理凭证历史文档(脚本中的accesstoken主要看这篇)
上传证书APICDN修改证书