阿里云自动续签SSL证书

3 分钟

前言

由于国内法律法规的限制,免费的SSL证书由1年变成了3个月,对于在弄了一个带有自己域名博客的人来说,这是一件比较无语的事情,每3个月重复性的工作需要手动更换SSL证书。网上也有很多docker版本的自动续签的应用,如宝塔acme.sh等等。但是安装这种软件的话,功能就多了许多其它的,个人又不需要。因此自己简单弄一个脚本去实现就十分必要。

操作过程

1、首先需要在工作台创建一个子账号,并取得账号分配的keysecret,给子用户分配AliyunDNSFULLAccessAliyunYunDunCertAccess权限。

1745635476433

1745635557143

2、生成2048位的crs证书,一般以RSA算法为主,通过Linux系统中自带的openssl命令生成即可

#openssl req -new -nodes -sha256 -newkey rsa:2048   -keyout blog.key   -out blog.csr   -config openssl.cnf
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = req_ext

[dn]
CN = aiwin.net.cn
emailAddress = test@foxmail.com
O = zirong
OU = liu
L = Guangzhou
ST = Guangdong
C = CN

[req_ext]
subjectAltName = @alt_names

[alt_names]
DNS.1 = aiwin.net.cn
DNS.2 = www.aiwin.net.cn

3、通过crontab定时任务每3个月执行脚本,注意脚本中的crs需要带上\r\n\n,最好通过一行直接写完,否则传输到阿里云接口会因为没有固定格式的分行而报错。

import os
import time
import logging
from alibabacloud_cas20200407.client import Client as cas20200407Client
from alibabacloud_credentials.client import Client as CredentialClient
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_cas20200407 import models as cas_20200407_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_alidns20150109.client import Client as Alidns20150109Client
from alibabacloud_alidns20150109 import models as alidns_20150109_models

logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')

'''
全局存储OrderId与RecordId
'''
OrderIdList = []
RecordIdList = []

class SSL:
    def __init__(self, client, endpoint):
        self.client = self.create_client(client, endpoint)

    '''
    环境变量设置id与secret,根据不同的方法与endpoint创建不同的安全功能客户端
    @ALIBABA_CLOUD_ACCESS_KEY_ID
    @ALIBABA_CLOUD_ACCESS_KEY_SECRET
    '''

    @staticmethod
    def create_client(func, endpoint):
        credential = CredentialClient()
        config = open_api_models.Config(
            credential=credential,
            region_id='cn-hangzhou',
            endpoint=endpoint,
            connect_timeout=5000,
            read_timeout=5000

        )
        return func(config)

    '''
    请求创建SSL证书并获取订单ID
    '''
    @staticmethod
    def main(self):
        create_certificate_for_package_request_request = cas_20200407_models.CreateCertificateForPackageRequestRequest(
            csr='''-----BEGIN CERTIFICATE REQUEST-----\r\n内容\r\n-----END CERTIFICATE REQUEST-----''',
            product_code='digicert-free-1-free',
            username='xxxx',
            phone='xxxx',
            email='test@foxmail.com',
            domain='aiwin.net.cn',
            validate_type='DNS'
        )
        runtime = util_models.RuntimeOptions()
        try:
            response = self.client.create_certificate_for_package_request_with_options(
                create_certificate_for_package_request_request, runtime)
            OrderIdList.append(response.body.order_id)
            self.parseOrderId(self)
        except Exception as error:
            logging.error(error)

    '''
    通过订单Id,请求SSL证书详情,获取验证时需要设置的域名与TXT记录,并且每相隔60秒请求一次是否已签发接口,签发即删除DNS记录并获取pem与key
    '''
    @staticmethod
    def parseOrderId(self):
        describe_certificate_state_request = cas_20200407_models.DescribeCertificateStateRequest(
            order_id=OrderIdList[0]
        )
        runtime = util_models.RuntimeOptions()
        try:
            response = self.client.describe_certificate_state_with_options(describe_certificate_state_request, runtime)
            self.addDNS(self, response.body.record_domain, response.body.record_value)
            IssuedResult = self.ConfirmSSLIssued(self)
            while not IssuedResult:
                time.sleep(60)
                IssuedResult = self.ConfirmSSLIssued(self)
            self.delDNS(self)
            self.getPrivatePem(self)
        except Exception as error:
            logging.error(error)

    '''
    添加DNS记录
    '''
    @staticmethod
    def addDNS(self, domain, value):
        self.client = self.create_client(Alidns20150109Client, 'alidns.cn-hangzhou.aliyuncs.com')
        add_domain_record_request = alidns_20150109_models.AddDomainRecordRequest(
            lang='zh',
            type='TXT',
            value='wdadawdawd.txt',
            rr='_dnsauth.aiwin.net.cn',
            # value=value,
            # rr=domain,
            domain_name='aiwin.net.cn'
        )
        runtime = util_models.RuntimeOptions()
        try:
            response = self.client.add_domain_record_with_options(add_domain_record_request, runtime)
            RecordIdList.append(response.body.record_id)
        except Exception as error:
            logging.error(error)

    '''
    根据RecordId删除DNS记录,并清空RecordId
    '''
    @staticmethod
    def delDNS(self) -> None:
        self.client = self.create_client(Alidns20150109Client, 'alidns.cn-hangzhou.aliyuncs.com')
        delete_domain_record_request = alidns_20150109_models.DeleteDomainRecordRequest(
            record_id=RecordIdList[0],
            lang='zh'
        )
        runtime = util_models.RuntimeOptions()
        try:
            response = self.client.delete_domain_record_with_options(delete_domain_record_request, runtime)
            if response.status_code == 200:
                RecordIdList.clear()
                print(RecordIdList)
        except Exception as error:
            logging.error(error)

    '''
    验证创建的证书是否已签发状态
    '''
    @staticmethod
    def ConfirmSSLIssued(self):
        self.client = self.create_client(cas20200407Client, 'cas.aliyuncs.com')
        list_user_certificate_order_request = cas_20200407_models.ListUserCertificateOrderRequest(status='ISSUED')
        runtime = util_models.RuntimeOptions()
        try:
            response = self.client.list_user_certificate_order_with_options(list_user_certificate_order_request,
                                                                            runtime)
            for ResponseBodyCertificateOrderList in response.body.certificate_order_list:
                if OrderIdList[0] == ResponseBodyCertificateOrderList.order_id:
                    return True
            return False
        except Exception as error:
            logging.error(error)

    '''
    根据订单ID,查看证书的详情,并取得certificate与private_key,即nginx文件中的pem和key内容
    '''

    @staticmethod
    def getPrivatePem(self):
        self.client = self.create_client(cas20200407Client, 'cas.aliyuncs.com')
        describe_certificate_state_request = cas_20200407_models.DescribeCertificateStateRequest(
            order_id=OrderIdList[0]
        )
        runtime = util_models.RuntimeOptions()
        try:
            response = self.client.describe_certificate_state_with_options(describe_certificate_state_request, runtime)
            self.CreateFile(self, "\n".join(response.body.certificate.splitlines()),
                            "\n".join(response.body.private_key.splitlines()))
        except Exception as error:
            logging.error(error)

    '''
    移除原文件,将新内容写入到nginx.conf路径文件当中
    '''

    @staticmethod
    def CreateFile(self, pem_body, key_body):
        try:
            os.remove('nginx中pem的路径')
            os.remove('nginx中key的路径')
            KeyFile = open('替换为域名.key', 'a')
            PemFile = open('替换为域名.pem', 'a')
            KeyFile.write(key_body)
            PemFile.write(pem_body)
            logging.info('pem与key文件创建成功')
        except Exception as error:
            logging.error(error)

if __name__ == '__main__':
    ssl = SSL(cas20200407Client, 'cas.aliyuncs.com')
    ssl.main(ssl)
~  ~  The   End  ~  ~


 赏 
承蒙厚爱,倍感珍贵,我会继续努力哒!
logo图像
tips
文章二维码 分类标签:开发开发
文章标题:阿里云自动续签SSL证书
文章链接:https://www.aiwin.net.cn/index.php/archives/4443/
最后编辑:2025 年 5 月 6 日 20:50 By Aiwin
许可协议: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
(*) 3 + 9 =
快来做第一个评论的人吧~