一个Github Action相关的问题请教一下大家

论坛帖子的启发
也想借助ai写一份Github Actions 通过 acme.sh 申请证书的yaml

现在项目出了点… bug?
当CA为 zerossl 时, issue 证书会失败
letencrypt_test测试没有问题

下面是yaml文件

name: Auto SSL

on:
  watch:
    types: [started]
  schedule:
    - cron: "0 17 * * *" # 北京时间凌晨1点的cron (UTC时间17:00)
  workflow_dispatch: 

env:
  ACME: /home/runner/.acme.sh/acme.sh
  EMAIL: ${{ secrets.ACCOUNT_EMAIL }}
  DNSAPI: ${{ secrets.DNSAPI }}
  CA: ${{ vars.CA }}
  BACKUP_CA: ${{ vars.BACKUP_CA }}
  DOH_USE: ${{ vars.DOH_USE }}
  ECC_KEYLENGTH: ${{ vars.ECC_KEYLENGTH }}
  RSA_KEYLENGTH: ${{ vars.RSA_KEYLENGTH }}
  ZEROSSL_EAB_KEY_ID: ${{ secrets.ZEROSSL_EAB_KEY_ID }}
  ZEROSSL_EAB_HMAC_KEY: ${{ secrets.ZEROSSL_EAB_HMAC_KEY }}

jobs:
  build:
    runs-on: ubuntu-latest
    if: github.event_name == 'schedule' || github.event.repository.owner.id == github.event.sender.id

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Git
        run: |
          git config --global user.email $EMAIL
          git config --global user.name acme

      - name: Install Dependencies
        run: |
          sudo apt-get update && sudo apt-get install -y tree
          wget -O yq_linux_amd64 https://github.com/mikefarah/yq/releases/download/v4.28.1/yq_linux_amd64
          chmod +x yq_linux_amd64
          sudo mv yq_linux_amd64 /usr/local/bin/yq

      - name: Install & Configure acme.sh
        run: |
          curl https://get.acme.sh | sh -s email=$EMAIL
          echo "$DNSAPI" >> /home/runner/.acme.sh/account.conf

          ZEROSSL_CONF_PATH="/home/runner/.acme.sh/ca/acme.zerossl.com/v2/DV90/ca.conf"
          mkdir -p "$(dirname "$ZEROSSL_CONF_PATH")"
          echo "CA_EAB_KEY_ID='${{ secrets.ZEROSSL_EAB_KEY_ID }}'" > "$ZEROSSL_CONF_PATH"
          echo "CA_EAB_HMAC_KEY='${{ secrets.ZEROSSL_EAB_HMAC_KEY }}'" >> "$ZEROSSL_CONF_PATH"
          cat "$ZEROSSL_CONF_PATH"

      - name: Update Certificate Status
        run: |
          CURRENT_TIME=$(date +"%Y-%m-%d %H:%M:%S")
          CERT_FILE="Certificate.md"

          echo "## Certificate Status (Updated at $CURRENT_TIME)" > $CERT_FILE
          echo "| Domain Group | Primary Domain | Expiry Date (ECC) | Issuer O (ECC) | Issuer CN (ECC) | Expiry Date (RSA) | Issuer O (RSA) | Issuer CN (RSA) |" >> $CERT_FILE
          echo "|--------------|----------------|------------------|---------------|----------------|-------------------|----------------|-----------------|" >> $CERT_FILE

          while IFS= read -r provider; do
            provider=${provider#- }
            while IFS= read -r domain_group; do
              domain_group=${domain_group#- }
              domain_group=$(echo "$domain_group" | sed 's/ && / /g')
              primary_domain=$(echo "$domain_group" | awk '{print $1}')

              expiry_date_ecc="N/A"
              issuer_o_ecc="N/A"
              issuer_cn_ecc="N/A"
              expiry_date_rsa="N/A"
              issuer_o_rsa="N/A"
              issuer_cn_rsa="N/A"

              if [ -f "./ssl/$primary_domain/ECC/$primary_domain.cer" ]; then
                expiry_date_ecc=$(openssl x509 -enddate -noout -in "./ssl/$primary_domain/ECC/$primary_domain.cer" | cut -d= -f2)
                issuer_info=$(openssl x509 -issuer -noout -in "./ssl/$primary_domain/ECC/$primary_domain.cer")
                issuer_o_ecc=$(echo "$issuer_info" | grep -oP 'O = \K[^,]*')
                issuer_cn_ecc=$(echo "$issuer_info" | grep -oP 'CN = \K.*')
              fi

              if [ -f "./ssl/$primary_domain/RSA/$primary_domain.cer" ]; then
                expiry_date_rsa=$(openssl x509 -enddate -noout -in "./ssl/$primary_domain/RSA/$primary_domain.cer" | cut -d= -f2)
                issuer_info=$(openssl x509 -issuer -noout -in "./ssl/$primary_domain/RSA/$primary_domain.cer")
                issuer_o_rsa=$(echo "$issuer_info" | grep -oP 'O = \K[^,]*')
                issuer_cn_rsa=$(echo "$issuer_info" | grep -oP 'CN = \K.*')
              fi

              echo "| $domain_group | $primary_domain | $expiry_date_ecc | $issuer_o_ecc | $issuer_cn_ecc | $expiry_date_rsa | $issuer_o_rsa | $issuer_cn_rsa |" >> $CERT_FILE
            done < <(yq eval ".[\"$provider\"]" domains.yaml)
          done < <(yq eval 'keys' domains.yaml)

          git add $CERT_FILE
          git commit -m "Update Certificate.md with certificate expiry dates and execution time at $CURRENT_TIME"

      - name: Issue & Deploy Certificates
        run: |
          create_github_issue() {
            title=$1
            body=$2
            repo=${GITHUB_REPOSITORY}
            curl -X POST -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
                 -H "Accept: application/vnd.github+json" \
                 -H "X-GitHub-Api-Version: 2022-11-28" \
                 -d "{\"title\": \"$title\", \"body\": \"$body\"}" \
                 https://api.github.com/repos/$repo/issues
          }

          mkdir -p ./ssl

          declare -A dns_plugins=(
            ["dnspod"]="dns_dp" 
            ["aliyun"]="dns_ali" 
            ["tencent"]="dns_tencent" 
            ["cloudflare"]="dns_cf" 
            ["aws"]="dns_aws" 
            ["gadaddy"]="dns_gd"
          )

          check_certificate_validity() {
            cert_path=$1
            if [ -f "$cert_path" ] && 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
          }

          verify_certificate_domains() {
            cert_file=$1
            domain_group=$2
            cert_domains=$(openssl x509 -in "$cert_file" -text -noout | grep -oP '(?<=DNS:)[^,]*')
            missing_domains=()
            for domain in $domain_group; do
              if ! echo "$cert_domains" | grep -qw "$domain"; then
                missing_domains+=("$domain")
              fi
            done
            if [ ${#missing_domains[@]} -gt 0 ]; then
              echo "${missing_domains[@]}"
            else
              echo ""
            fi
          }

          issue_and_install_certificate() {
            domains=$1
            cert_type=$2
            acme_server=$3
            keylength=$4
            dns_plugin=${dns_plugins[$5]}
            ca_type=$6
            cert_path="./ssl/$primary_domain/$cert_type"
            if [ "$ca_type" = "BACKUP" ]; then
              cert_path="./backup_ssl/$primary_domain/$cert_type"
            fi
            cert_file="$cert_path/$primary_domain.cer"
            key_file="$cert_path/$primary_domain.key"
            domain_args=""
            for domain in $domains; do
              domain_args="$domain_args -d $domain"
            done

            echo "[+] Issue $cert_type certificate for $domains using $ca_type CA"
            if [ "$ca_type" = "BACKUP" ]; then
              if ! $ACME --issue --server $acme_server --dns $dns_plugin $domain_args ${keylength:+--keylength $keylength} --force --debug 2; then
                echo "[-] Failed to issue $cert_type certificate for $domains using $ca_type CA, skipping..."
                return 1
              fi
            else
              if ! $ACME --issue --server $acme_server --dns $dns_plugin $domain_args ${keylength:+--keylength $keylength} --debug 2; then
                echo "[-] Failed to issue $cert_type certificate for $domains using $ca_type CA, skipping..."
                return 1
              fi
            fi

            echo "[+] Install $cert_type certificate for $domains using $ca_type CA"
            if ! $ACME --installcert -d "$primary_domain" --key-file "$key_file" --fullchain-file "$cert_file"; then
              echo "[-] Failed to install $cert_type certificate for $domains using $ca_type CA, skipping..."
              return 1
            fi

            git add "$cert_path"
            git commit -m "Update $cert_type certificate for $domains using $ca_type CA at $(date)"
          }

          while IFS= read -r provider; do
            provider=${provider#- }
            while IFS= read -r domain_group; do
              domain_group=${domain_group#- }
              domain_group=$(echo "$domain_group" | sed 's/ && / /g')
              primary_domain=$(echo "$domain_group" | awk '{print $1}')
              mkdir -p "./ssl/$primary_domain/ECC" "./ssl/$primary_domain/RSA"
              if [ -n "${{ vars.BACKUP_CA }}" ]; then
                mkdir -p "./backup_ssl/$primary_domain/ECC" "./backup_ssl/$primary_domain/RSA"
              fi
              echo "[+] DNS provider: $provider, Domains: $domain_group"

              missing_domains_ecc=$(verify_certificate_domains "./ssl/$primary_domain/ECC/$primary_domain.cer" "$domain_group")
              if [ -n "$missing_domains_ecc" ]; then
                echo "[+] Missing domains in PRIMARY ECC certificate: $missing_domains_ecc"
                issue_and_install_certificate "$missing_domains_ecc" "ECC" "${{ vars.CA }}" "${{ vars.ECC_KEYLENGTH }}" "$provider" "PRIMARY"
                if [ -n "${{ vars.BACKUP_CA }}" ]; then
                  echo "[+] Applying for BACKUP ECC certificate"
                  issue_and_install_certificate "$missing_domains_ecc" "ECC" "${{ vars.BACKUP_CA }}" "${{ vars.ECC_KEYLENGTH }}" "$provider" "BACKUP"
                fi
              else
                echo "[-] PRIMARY ECC certificate for $primary_domain is up-to-date and valid."
              fi

              missing_domains_rsa=$(verify_certificate_domains "./ssl/$primary_domain/RSA/$primary_domain.cer" "$domain_group")
              if [ -n "$missing_domains_rsa" ]; then
                echo "[+] Missing domains in PRIMARY RSA certificate: $missing_domains_rsa"
                issue_and_install_certificate "$missing_domains_rsa" "RSA" "${{ vars.CA }}" "${{ vars.RSA_KEYLENGTH }}" "$provider" "PRIMARY"
                if [ -n "${{ vars.BACKUP_CA }}" ]; then
                  echo "[+] Applying for BACKUP RSA certificate"
                  issue_and_install_certificate "$missing_domains_rsa" "RSA" "${{ vars.BACKUP_CA }}" "${{ vars.RSA_KEYLENGTH }}" "$provider" "BACKUP"
                fi
              else
                echo "[-] PRIMARY ECC certificate for $primary_domain is up-to-date and valid."
              fi

            done < <(yq eval ".[\"$provider\"]" domains.yaml)
          done < <(yq eval 'keys' domains.yaml)

      - name: Output Directory Structures
        run: |
          if [ -d "ssl" ]; then
            echo "SSL Directory Structure:"
            tree -a ssl || echo "Failed to list SSL directory."
          else
            echo "SSL directory does not exist."
          fi

          if [ -d "backup_ssl" ]; then
            echo "Backup SSL Directory Structure:"
            tree -a backup_ssl || echo "Failed to list backup SSL directory."
          else
            echo "Backup SSL directory does not exist."
          fi

      - name: Push changes
        uses: ad-m/github-push-action@master
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}

及环境变量

acme.sh 在 linux上 不是默认就会集成到系统的crontab里面嘛 :face_with_peeking_eye:


你要把这些文件提前放到目录里面

已经这么做了
不过谢谢,经过一段时间的努力
我选择跳过了这个问题继续action(
在第二次action时issue就成功了

奇怪的bug

项目已经发在github上了,晚些我应该也会在论坛发帖 (应该?