zoukankan      html  css  js  c++  java
  • 使用Certbot实现阿里云泛域名证书的自动续期

    不得不说,支持泛域名证书的certbot真的太香了!

    很久之前就利用certbot给网站开通了泛域名证书(利用certbot-auto生成证书 ),唯一麻烦是每隔90天就得手动执行续期。

    主要障碍就是利用阿里云的DNS解析接口自动完成域名校验,趁着最近有时间好好研究了一下,最终效果非常固的,再也不用担心证书过期了。

    涉及的一些资源或文档:

    1、云解析 - OpenAPI 概览https://next.api.aliyun.com/document/Alidns/2015-01-09/overview

    2、certbot-auth-alidns:https://github.com/zphiliam/certbot-auth-alidns

    主要步骤:

    1、获取阿里云AccessKey

    包括id和secret,成对儿使用,登录阿里云控制台,可以使用主账号的AccessKey,推荐利用RAM创建子账号的AccessKey,更安全。

    2、安装阿里云SDK(python环境)

    pip3 install aliyun-python-sdk-core
    pip3 install aliyun-python-sdk-cms

    阿里云SDK要求python3.0以上,所以上面使用pip3安装。

    第一个sdk是阿里云的核心库,第二个是RAM库

    3、准备脚本

    1)脚本存放目录:/mnt/runtime/certbot-auth-alidns

     

    2)安装certbot-auto入口文件

    wget https://dl.eff.org/certbot-auto
    chmod a+x certbot-auto

    如果之前安装过certbot-auto,直接复制过来也可以。

     

    3)创建AccessKey存放文件:config.py(将其中的id和secret换成实际值)

    #!/usr/bin/env python
    # coding:utf-8
    
    # 阿里云控制台 api 访问账户
    ACCESS_KEY_ID = 'ACCESS_KEY_ID'
    ACCESS_KEY_SECRET = 'ACCESS_KEY_SECRET'

     

    4)创建域名校验逻辑文件:alidns.py

    #!/usr/bin/env python
    # coding=utf-8
    
    from aliyunsdkcore.client import AcsClient
    from aliyunsdkcore.request import CommonRequest
    from config import *
    import json
    from sys import argv
    # client = AcsClient('<accessKeyId>', '<accessSecret>', 'cn-hangzhou')
    
    client = AcsClient(ACCESS_KEY_ID, ACCESS_KEY_SECRET, 'nothing')
    
    
    class AliDNS(object):
    
        def __init__(self, domain_name=''):
            self.domain_name = domain_name
    
        def add_domain_record(self, rr, value, type='TXT'):
            # https://help.aliyun.com/document_detail/29772.html?spm=a2c4g.11186623.6.647.5fce1ba8XGwW3b
            # https://api.aliyun.com/?spm=a2c1g.8271268.10000.1.751edf252XRbqs#product=Alidns&api=AddDomainRecord&params={}&tab=DEMO&lang=PYTHON
            request = CommonRequest()
            request.set_accept_format('json')
            request.set_domain('alidns.aliyuncs.com')
            request.set_method('POST')
            request.set_version('2015-01-09')
            request.set_action_name('AddDomainRecord')
    
            request.add_query_param('Type', type)
            request.add_query_param('RR', rr)
            request.add_query_param('DomainName', self.domain_name)
            request.add_query_param('Value', value)
    
            response = client.do_action(request)
            print(response.decode('utf-8'))
    
        def describe_domain_records(self):
            # https://help.aliyun.com/document_detail/29751.html?spm=a2c4g.11186623.6.627.30e77d8cBvKO4T
            # https://api.aliyun.com/?spm=a2c1g.8271268.10000.1.751edf252XRbqs#product=Alidns&api=DescribeDomainRecords&params={}&tab=DEMO&lang=PYTHON
            request = CommonRequest()
            request.set_accept_format('json')
            request.set_domain('alidns.aliyuncs.com')
            request.set_method('POST')
            request.set_version('2015-01-09')
            request.set_action_name('DescribeDomainRecords')
    
            request.add_query_param('DomainName', self.domain_name)
            request.add_query_param('PageNumber', '1')
            request.add_query_param('PageSize', '500')
            response = client.do_action(request)
            rs = response.decode('utf-8')
            # print(response.decode('utf-8'))
            # print(str(response, encoding='utf-8'))
            data = json.loads(rs)
            return data
    
        def delete_domain_record(self, record_id):
            # https://help.aliyun.com/document_detail/29773.html?spm=a2c4g.11186623.6.648.4bc76e00EoOIru
            # https://api.aliyun.com/?spm=a2c1g.8271268.10000.1.751edf252XRbqs#product=Alidns&api=DeleteDomainRecord&params={}&tab=DEMO&lang=PYTHON
            request = CommonRequest()
            request.set_accept_format('json')
            request.set_domain('alidns.aliyuncs.com')
            request.set_method('POST')
            request.set_version('2015-01-09')
            request.set_action_name('DeleteDomainRecord')
    
            request.add_query_param('RecordId', record_id)
    
            response = client.do_action(request)
            # print(response.decode('utf-8'))
    
        def update_domain_record(self, rid, rr, value, type='TXT'):
            request = CommonRequest()
            request.set_accept_format('json')
            request.set_domain('alidns.aliyuncs.com')
            request.set_method('POST')
            request.set_version('2015-01-09')
            request.set_action_name('UpdateDomainRecord')
    
            request.add_query_param('RecordId', rid)
            request.add_query_param('RR', rr)
            request.add_query_param('Type', type)
            request.add_query_param('Value', value)
    
            response = client.do_action(request)
            # print(str(response, encoding='utf-8'))
    
    
    if __name__ == '__main__':
    
        # import time
        # domain = 'iot-c.top'
        # acme_challenge = 'test.z'
        # validation = str(time.time())
    
        print(argv)
        file_name, domain, acme_challenge, validation = argv
    
        dns = AliDNS(domain)
    
        # 列出所有解析记录
        data = dns.describe_domain_records()
        # print(json.dumps(data, indent=2))
    
        record_list = data["DomainRecords"]["Record"]
        # print(len(record_list))
    
        if record_list:
            for item in record_list:
                if acme_challenge == item['RR']:
                    # 删除原有的记录
                    dns.delete_domain_record(item['RecordId'])
        print("阿里云DNS添加 TXT 记录:\n"
              "{} --> {}".format(acme_challenge + "." + domain, validation))
    
        # 添加新记录
        dns.add_domain_record(acme_challenge, validation)
    

     

    5)创建校验脚本文件:auth.sh

    #!/usr/bin/env bash
    
    path=$(cd `dirname $0`; pwd)
    
    # 调用 python 脚本,自动设置 DNS TXT 记录。
    # 第一个参数:需要为那个域名设置 DNS 记录
    # 第二个参数:需要为具体那个 RR 设置
    # 第三个参数: letsencrypt 动态传递的 value 值
    
    echo $CERTBOT_DOMAIN "_acme-challenge" $CERTBOT_VALIDATION
    
    python3.6  $path"/alidns.py"  $CERTBOT_DOMAIN "_acme-challenge"  $CERTBOT_VALIDATION
    
    # DNS TXT 记录刷新时间
    /bin/sleep 5
    
    echo "auth.sh end"
    

    我本地的python版本是3.6,所以命令名称是python3.6,要根据实际情况进行修改。

    为脚本添加可执行权限:

    chmod +x auth.sh

     

    6)创建自动续期脚本:renew.sh

    #!/usr/bin/env bash
    # https://certbot.eff.org/docs/using.html#manual
    # --pre-hook and --post-hook hooks run before and after every renewal attempt.
    # If you want your hook to run only after a successful renewal,
    # use --deploy-hook in a command like this.
    # certbot renew --deploy-hook /path/to/deploy-hook-script
    # cron 每天2点执行:
    # 0 2 * * * /mnt/runtime/certbot-auth-alidns/renew.sh
    
    path=$(cd `dirname $0`; pwd)
    cd ${path}
    echo ------------------
    pwd
    date
    ./certbot-auto renew --manual --preferred-challenges dns --manual-auth-hook ${path}/auth.sh --deploy-hook "nginx -s reload"

    为脚本添加可执行权限:

    chmod +x renew.sh

    4、手动创建新证书

    ./certbot-auto certonly  -d *.domain.cn  --manual --preferred-challenges dns  --manual-auth-hook /mnt/runtime/certbot-auth-alidns/auth.sh

    注:在使用certbot命令时,可以附加 --dry-run 参数,避免操作次数限制,等测试无误后,再进行真实操作。

    5、手动续期所有证书(命令)

    ./certbot-auto renew --manual --preferred-challenges dns --manual-auth-hook /mnt/runtime/certbot-auth-alidns/auth.sh --deploy-hook "nginx -s reload"

    6、手动续期所有证书(引用脚本)

    ./renew.sh

    7、创建自动执行

    crontab -e
    0 2 1 * * /mnt/runtime/certbot-auth-alidns/renew.sh

    以上规则是每月1日凌晨2点自动执行续期操作

    8、相关文件打包下载

    certbot-auth-alidns.zip

    版权声明: 本文为博主 网无忌 原创文章,欢迎转载,但请务必标注原文链接。

    本文链接: https://www.cnblogs.com/netWild/p/15797664.html

  • 相关阅读:
    IFRAME自适应高度
    项目支出数据产生过程
    hbase体系结构以及说明
    PLSQL 设置
    hadoop编程模型
    捕捉桌面上的窗口信息
    在不修改代码的情况下无限扩展应用项目
    跟我一起玩Win32开发(25):监视剪贴板
    跟我一起玩Win32开发(24):计时器
    跟我一起玩Win32开发(23):渐变颜色填充
  • 原文地址:https://www.cnblogs.com/netWild/p/15797664.html
Copyright © 2011-2022 走看看