利用 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":""},{"url":"https://image.baidu.com/search/down?url=https://gzw.sinaimg.cn/mw690/0085UwQ9ly1htnmshmwllj30z60redm3.jpg","alt":""}]
生成证书 - 阿里云
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":""},{"url":"https://image.baidu.com/search/down?url=https://gzw.sinaimg.cn/mw2000/0085UwQ9ly1htnobak1vfj31tq0konjf.jpg","alt":""}]
使用子账号的 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-前端知识记录!
评论