利用 Github Actions 和 Acme 自动申请、更新和部署至阿里云、腾讯云 CDN Lets Encrypt SSl\TLS ECC RSA 双证书
ACME: Automatic Certificate Management Environment(自动证书管理环境),是一种用于自动化管理和获取SSL\TLS证书的协议。
ACME提供了一种标准化的方式,使能够自动请求、验证和获取证书,无需人工干预。完成标准化的获取证书流程需要ACME客户端与ACME服务端进行通信,常见的ACME的客户端有:acme.sh、certbot 等
acme.sh
相关命令
安装 acme.sh
curl  https://get.acme.sh | sh -s email=$EMAIL
生成证书 - DNSpod
- 使用 DNSpod 
api(--dns dns_dp)进行自动域名TXT解析,验证域名所有权。 - 将 DNSpod Token 中获取的 
ID(对应DP_Id) 和Token(对应DP_Key) - 使用 证书 
CA为letsencrypt--server letsencrypt -d为ksh7.com、*.ksh7.com为多个域名申请证书(或泛域名证书)
export DP_Id="1234"
export DP_Key="sADDsdasdgdsf"
acme.sh --issue --server letsencrypt --dns dns_dp -d ksh7.com -d *.ksh7.com
更换 CA
创建 DNSpod Token
[{"url":"https://image.baidu.com/search/down?url=https://gzw.sinaimg.cn/mw690/0085UwQ9ly1htnn096gjdj30go0jcdif.jpg","alt":"","title":""},{"url":"https://image.baidu.com/search/down?url=https://gzw.sinaimg.cn/mw690/0085UwQ9ly1htnmshmwllj30z60redm3.jpg","alt":"","title":""}]
  生成证书 - 阿里云
export Ali_Key="<key>"
export Ali_Secret="<secret>"
acme.sh --issue --dns dns_ali -d ksh7.com -d *.ksh7.com --server letsencrypt
使用主账号的 AccessKey
[{"url":"https://image.baidu.com/search/down?url=https://gzw.sinaimg.cn/mw690/0085UwQ9ly1htnobahaorj30hs0fkn1j.jpg","alt":"","title":""},{"url":"https://image.baidu.com/search/down?url=https://gzw.sinaimg.cn/mw2000/0085UwQ9ly1htnobak1vfj31tq0konjf.jpg","alt":"","title":""}]
  使用子账号的 AccessKey
子账号创建流程参考 CertCloud
更多关于DNS API的说明或其他平台(如cloudflare、aws等)请参考 How to use DNS API
安装证书
acme.sh --installcert -d ksh7.com -d *.ksh7.com --key-file /mycertify/ssl/ksh7.com.key --fullchain-file /mycertify/ssl/ksh7.com.cer
部署证书
腾讯 Cdn
账户需要权限:QcloudCDNFullAccess、QcloudSSLFullAccess
deploy-to-tencent-cdn:
  name: Deploy certificate to Tencent Cloud CDN
  runs-on: ubuntu-latest
  # 需要在申请完证书后进行部署任务
  needs: issue
  steps:
    - name: Check out
      uses: actions/checkout@v2
      with:
        ref: ${{ github.ref }}
    - uses: renbaoshuo/deploy-certificate-to-tencentcloud@v2
      with:
        secret-id: ${{ secrets.SECRETID }}
        secret-key: ${{ secrets.SECRETKEY }}
        # cert file like ksh7.com.cer
        # 证书路径
        fullchain-file: ${{ env.CERTS_OUTPUT_DIRECTORY }}/${{ env.FILE_FULLCHAIN }}
        # 私钥路径
        key-file: ${{ env.CERTS_OUTPUT_DIRECTORY }}/${{ env.FILE_KEY }}
        cdn-domains: |
          ksh7.com
阿里云 CDN
deploy-to-aliyun:
  name: Deploy Certificate to Aliyun
  runs-on: ubuntu-latest
  needs: issue-ssl-certificate
  steps:
    - name: Checkout
      uses: actions/checkout@v2
    # 上传证书
    - name: Deploy certificate to aliyun
      uses: Menci/deploy-certificate-to-aliyun@beta-v1
      with:
        access-key-id: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
        access-key-secret: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
        fullchain-file: ${{ env.CERTS_OUTPUT_DIRECTORY }}/${{ env.FILE_FULLCHAIN }}
        key-file: ${{ env.CERTS_OUTPUT_DIRECTORY }}/${{ env.FILE_KEY }}
        certificate-name: example.com
        cdn-domains: |
          ksh7.com
申请证书
Menci/acme
jobs:
  issue-ssl-certificate:
    name: Issue SSL certificate
    runs-on: ubuntu-latest
    steps:
      - uses: Menci/acme@v2
        with:
          version: 3.0.2
          # Register your account and try issue a certificate with DNS API mode
          # Then fill with the output of `tar cz ca account.conf | base64 -w0` running in your `~/.acme.sh`
          account-tar: ${{ secrets.ACME_SH_ACCOUNT_TAR }}
          domains: example.com example.net example.org example.edu
          domains-file: ''
          append-wildcard: true
          arguments: --dns dns_cf --challenge-alias example.com
          arguments-file: ''
          output-fullchain: output/fullchain.pem
          output-key: output/key.pem
          output-pfx: output/certificate.pfx
          output-pfx-password: qwq
          # uninstall: true # Uninstall acme.sh after this action by default
自定义 acme.sh 的 Actions
使用
腾讯 CDN的完整案例,详细文档和参数请转至:auto-ssl-cert
name: DnsPod SSL Certificates
on:
  schedule: # execute every 24 hours
    - cron: '35 6 * * *'
  workflow_dispatch:
env:
  ACME: /home/runner/.acme.sh/acme.sh
  DP_ID: ${{ secrets.DP_ID }}
  DP_KEY: ${{ secrets.DP_KEY }}
  EMAIL: ${{ secrets.EMAIL }}
jobs:
  issue-cert:
    runs-on: ubuntu-latest
    outputs:
      certificate_updated: ${{ steps.check_certificate.outputs.certificate_updated }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Install & Configure acme.sh
        run: |
          curl  https://get.acme.sh | sh -s email=$EMAIL
      - name: Issue & Deploy Certificates
        id: check_certificate
        run: |
          export DP_Id=$DP_ID
          export DP_Key=$DP_KEY
          git config --global user.email $EMAIL
          git config --global user.name acme
          # 如果想要其他证书发行机构,可以把 acme.sh 的ca目录拷贝到 repo 的 ca目录
          # mkdir -p /home/runner/.acme.sh/ca/
          # cp -r ca/* /home/runner/.acme.sh/ca/          
          certificate_updated=false
          check_certificate_validity() {
            cert_path=$1
            if [ -f "$cert_path" ]; then
              if openssl x509 -checkend $(( 30 * 86400 )) -noout -in "$cert_path"; then
                echo "Certificate at $cert_path is valid for more than 30 days, skipping..."
                return 0
              else
                return 1
              fi
            else
              return 1
            fi
          }
          issue_and_install_certificate() {
            domain=$1
            cert_type=$2 # "EC" or "RSA"
            acme_server=$3 # default choose "letsencrypt" 其他 CA 请参考 https://github.com/acmesh-official/acme.sh/wiki/CA
            keylength=$4 # empty for EC, "3072" for RSA
            cert_path="./ssl/$domain"
            [ "$cert_type" = "RSA" ] && cert_path="$cert_path/rsa"
            cert_file="$cert_path/$domain.cer"
            key_file="$cert_path/$domain.key"
            
            # Issue certificate          
            issue_status=0
            $ACME --issue --server $acme_server --debug --dns dns_dp -d "$domain" -d "*.$domain" ${keylength:+--keylength $keylength}|| issue_status=$?
            if [ $issue_status -ne 0 ]; then
              echo "Failed to issue $cert_type certificate for $domain, skipping..."
              return
            fi
            # Install certificate          
            install_status=0
            $ACME --installcert -d "$domain" --key-file "$key_file" --fullchain-file "$cert_file" || install_status=$?
            if [ $install_status -ne 0 ]; then
              echo "Failed to install $cert_type certificate for $domain, skipping..."
              return
            fi
            certificate_updated=true
            TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
            git add $cert_path/
            git commit -m "Update $cert_type certificate files for $domain at $TIMESTAMP"
          }
          while IFS= read -r domain || [ -n "$domain" ]; do
            mkdir -p "./ssl/$domain/rsa"
            # Check and issue/install EC certificate
            if ! check_certificate_validity "./ssl/$domain/$domain.cer"; then
              issue_and_install_certificate "$domain" "EC" "letsencrypt" ""
            fi
            # Check and issue/install RSA certificate
            if ! check_certificate_validity "./ssl/$domain/rsa/$domain.cer"; then
              issue_and_install_certificate "$domain" "RSA" "letsencrypt" "3072"
            fi
          done < dnspod_domains_list.txt
          echo "certificate_updated=$certificate_updated" >> $GITHUB_OUTPUT
      - name: Push changes
        if: steps.check_certificate.outputs.certificate_updated == 'true'
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
  deploy-to-tencent-cdn:
    name: Deploy certificate to Tencent Cloud CDN
    runs-on: ubuntu-latest
    needs: issue-cert
    if: needs.build.outputs.certificate_updated == 'true'
    steps:
      - name: Check out
        uses: actions/checkout@v2
        with:
          ref: ${{ github.ref }}
      - uses: renbaoshuo/deploy-certificate-to-tencentcloud@v2
        with:
          secret-id: ${{ secrets.SECRETID }}
          secret-key: ${{ secrets.SECRETKEY }}
          # cert file like ksh7.com.cer
          fullchain-file: ${{ env.CERTS_OUTPUT_DIRECTORY }}/${{ env.FILE_FULLCHAIN }}
          key-file: ${{ env.CERTS_OUTPUT_DIRECTORY }}/${{ env.FILE_KEY }}
          cdn-domains: |
            ksh7.com
其他推荐
httpsok
相关链接
申请证书与部署证书参考: auto-ssl-cert
申请证书参考:auto-ssl
部署腾讯 CDN Action deploy-certificate-to-tencentcloud
部署腾讯 CDN Action 功能更完善 qcloud-ssl-cdn
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 kshao-blog-前端知识记录!
 评论










