Let’s Encrypt 是一个免费、开放,自动化的证书颁发机构,由 ISRG(Internet Security Research Group)运作。
然而有一个问题,Let’s Encrypt 的证书只有三个月的有效期,虽说服务器会自动续签,但是续签之后的证书不能自动推送到阿里云 CDN,博主手上有几个站点都使用的 Let’s Encrypt,手动上传证书是在是太麻烦了。
前几个月,朋友 Hintay 写了一个 Python 脚本,利用了阿里云 OpenAPI 的 SDK,实现推送 Let’s Encrypt 证书到阿里云 CDN,脚本只能提交一个域名。前段时间一直很忙,就没有跟进这件事,今天有空把脚本改成批量推送了,并且在服务器上用 Crontab
开了定时,因为证书会至少提前一个月自动续期,所以设置成每周一检,就很舒服了。
下面上 Python
#!/usr/bin/python # -*- coding:utf-8 -*- # # Copyright (c) 2017 Hintay <hintay@me.com> & 0xJacky <jacky-943572677@qq.com> # # !请先使用 pip install aliyun-python-sdk-cdn 安装 sdk! from aliyunsdkcore import client from aliyunsdkcdn.request.v20141111 import SetDomainServerCertificateRequest import datetime import os import collections import hashlib import json ABS_PATH = os.path.abspath('.') JSON_PATH = os.path.join(ABS_PATH, 'data.json') ## 配置开始 # 访问 https://ak-console.aliyun.com/index#/accesskey 获取 AccessKeyId = '' AccessKeySecret = '' # 指定证书所属加速域名,需属于https加速类型 # !!! 修改域名元组后请将 data.json 删除 DomainName = ['jackyu.cn', 'beta.uozi.org'] Letsencrypt_path = os.path.join('/etc/letsencrypt') live_cert = os.path.join(Letsencrypt_path, 'live') ## 配置结束 # 获取证书 md5 返回: 字典 def key_md5(): domain = collections.OrderedDict() for d in DomainName: privkey = os.path.join(live_cert, d, 'privkey.pem') file = open(privkey, 'rb') md5 = hashlib.md5(file.read()).hexdigest() domain[d] = md5 return domain # 写入数据 def write_data(domain): with open(JSON_PATH, 'w') as json_file: json_file.write(json.dumps(domain)) # 获取数据 def load_data(): with open(JSON_PATH) as json_file: data = json.load(json_file) return data # 判断数据文件是否存在 if not os.path.exists(JSON_PATH): # 将私钥的 md5 写入 Json write_data(key_md5()) domain = key_md5() data = load_data() for d in DomainName: if not data[d] == domain[d]: try: Client = client.AcsClient(AccessKeyId, AccessKeySecret, 'cn-hangzhou') request = SetDomainServerCertificateRequest.SetDomainServerCertificateRequest() request.set_accept_format('json') CertName = d + '_' + datetime.datetime.now().strftime("%Y%m%d_%H%M%S") # 证书名称,默认域名+日期时间 ServerCertificate_path = os.path.join(live_cert, d, 'fullchain.pem') # 安全证书路径 PrivateKey_path = os.path.join(live_cert, d, 'privkey.pem') # 私钥路径 request.set_DomainName(d) request.set_CertName(CertName) request.set_ServerCertificateStatus('on') ServerCertificate = open(ServerCertificate_path, 'r').read() ServerCertificate = open(ServerCertificate_path, 'r').read() PrivateKey = open(PrivateKey_path, 'r').read() request.set_ServerCertificate(ServerCertificate) request.set_PrivateKey(PrivateKey) result = Client.do_action_with_exception(request) print(result) except ServerException as e: print('Domain:'+d+'Error:'+e) # 更新数据文件 os.remove(JSON_PATH) write_data(key_md5())
文章最后修订于 2020年5月14日
为啥是if not data[d] == domain[d]:
不是 if data[d] == domain[d]:
@jilmy: md5值相等的话就不用重复推送了
@Jacky: 是的,我刚刚发现,感谢
@jilmy: 扩展项目是这个 https://github.com/0xJacky/cdn_cert 如果您发现代码有逻辑问题可以提个 pr
@Jacky: 好的,学习了
PrivateKey 需要为RSA格式啊,要先转一下吧
@Harry: 这个 issue 已经在 cdn_cert 项目中修正