This commit is contained in:
Zhong Lufan 2019-12-31 23:36:16 +08:00
parent 052bbe6dd0
commit 5151206472
No known key found for this signature in database
GPG Key ID: 30191289A9BD0B15
3 changed files with 58 additions and 51 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
* text=auto
*.sh text eol=lf

View File

@ -8,16 +8,16 @@ done
_AliAccessKeyId=$(printenv AliAccessKeyId) _AliAccessKeyId=$(printenv AliAccessKeyId)
_AliAccessKeySecret=$(printenv AliAccessKeySecret) _AliAccessKeySecret=$(printenv AliAccessKeySecret)
_Format=JSON _ali_format_rpc=JSON
_SignatureMethod=HMAC-SHA1 _ali_signature_method=HMAC-SHA1
_SignatureVersion=1.0 _ali_signature_version=1.0
_urlencode_pycode="from sys import stdin;from urllib.parse import quote;print(quote(stdin.read(), '-_.~'))" _urlencode_pycode="from sys import stdin;from urllib.parse import quote;print(quote(stdin.read(), '-_.~'))"
# aliapi_rpc <host> <http_method> <api_version> <api_action> <api_custom_key[]> <api_custom_value[]> # aliapi_rpc <host> <http_method> <api_version> <api_action> <api_custom_key[]> <api_custom_value[]>
aliapi_rpc() { aliapi_rpc() {
[[ $# -lt 6 ]] && return 66 [[ $# -lt 6 ]] && return 66
# 公共查询参数键 # 公共查询参数键
local _ali_common_key=( local _api_common_key=(
"Format" "Format"
"AccessKeyId" "AccessKeyId"
"SignatureMethod" "SignatureMethod"
@ -29,20 +29,22 @@ aliapi_rpc() {
) )
# 公共查询参数值 # 公共查询参数值
local _ali_common_value=( local _ali_common_value=(
"$_Format" "$_ali_format_rpc"
"$_AliAccessKeyId" "$_AliAccessKeyId"
"$_SignatureMethod" "$_ali_signature_method"
"$(_ali_sign_timestamp)" "$(_ali_timestamp_rpc)"
"$_SignatureVersion" "$_ali_signature_version"
"$(_ali_sign_nonce)" "$(_ali_signature_nonce)"
"$3" "$3"
"$4" "$4"
) )
local _ali_custom_key=() _ali_custom_value=() # 自定义查询参数键值 # 自定义查询参数键值
local _ali_custom_key=() _ali_custom_value=()
read -r -a _ali_custom_key <<< "$5" read -r -a _ali_custom_key <<< "$5"
read -r -a _ali_custom_value <<< "$6" read -r -a _ali_custom_value <<< "$6"
local _ali_key=() _ali_value=() # 合并查询键值 # 合并查询键值
read -r -a _ali_key <<< "${_ali_common_key[*]} ${_ali_custom_key[*]}" local _ali_key=() _ali_value=()
read -r -a _ali_key <<< "${_api_common_key[*]} ${_ali_custom_key[*]}"
read -r -a _ali_value <<< "${_ali_common_value[*]} ${_ali_custom_value[*]}" read -r -a _ali_value <<< "${_ali_common_value[*]} ${_ali_custom_value[*]}"
local _http_host=$1 _http_method=$2 local _http_host=$1 _http_method=$2
local _query_str="" local _query_str=""
@ -50,13 +52,14 @@ aliapi_rpc() {
for (( i = 0; i < ${#_ali_key[@]}; ++i )); do for (( i = 0; i < ${#_ali_key[@]}; ++i )); do
_key=${_ali_key[$i]} _key=${_ali_key[$i]}
_value=${_ali_value[$i]} _value=${_ali_value[$i]}
[[ $(grep -E "^.+\(\)$" <<< "$_value") == "$_value" ]] && _value=$(${_value//()/}) # 参数值如果是以 () 结束,代表需要执行命令获取值。 # 参数值如果是以 () 结束,代表需要执行命令获取值。
[[ $(grep -E "^.+\(\)$" <<< "$_value") == "$_value" ]] && _value=$(${_value//()/})
_value=$(_urlencode "$_value") _value=$(_urlencode "$_value")
_query_str+="$_key=$_value&" _query_str+="$_key=$_value&"
done done
local _ali_signature local _ali_signature_value
_ali_signature=$(_ali_sign "$_http_method" "$_query_str") _ali_signature_value=$(_ali_signature_rpc "$_http_method" "$_query_str")
_query_str+="Signature=$(_urlencode "$_ali_signature")" _query_str+="Signature=$(_urlencode "$_ali_signature_value")"
local _curl_out _result_code _http_url="https://${_http_host}/?${_query_str}" local _curl_out _result_code _http_url="https://${_http_host}/?${_query_str}"
_curl_out=$(mktemp) _curl_out=$(mktemp)
_result_code=$(curl -L -s -X "$_http_method" -o "$_curl_out" --write-out "%{http_code}" "$_http_url" || echo $?) _result_code=$(curl -L -s -X "$_http_method" -o "$_curl_out" --write-out "%{http_code}" "$_http_url" || echo $?)
@ -65,20 +68,20 @@ aliapi_rpc() {
[[ ${_result_code} -eq 200 ]] && return 0 || return 1 [[ ${_result_code} -eq 200 ]] && return 0 || return 1
} }
_ali_sign() { _ali_signature_rpc() {
local _http_method _str _query_str _sign_str local _http_method=$1 _str _query_str _sign_str
_http_method=$1
_str=$(echo -n "$2" | tr "&" "\n" | sort) _str=$(echo -n "$2" | tr "&" "\n" | sort)
_query_str=$(echo -n "$_str" | tr "\n" "&") _query_str=$(echo -n "$_str" | tr "\n" "&")
_sign_str="${_http_method}&$(_urlencode "/")&$(_urlencode "$_query_str")" _sign_str="${_http_method}&$(_urlencode "/")&$(_urlencode "$_query_str")"
echo -n "$_sign_str" | openssl sha1 -hmac "${_AliAccessKeySecret}&" -binary | openssl base64 -e echo -n "$_sign_str" | openssl sha1 -hmac "${_AliAccessKeySecret}&" -binary | openssl base64 -e
} }
_ali_sign_timestamp() { _ali_timestamp_rpc() {
TZ="UTC" date "+%FT%TZ" # ISO8601 UTC
date -u +%FT%TZ
} }
_ali_sign_nonce() { _ali_signature_nonce() {
date "+%s%N" date "+%s%N"
} }

View File

@ -1,13 +1,19 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# https://help.aliyun.com/document_detail/126507.html # CAS https://help.aliyun.com/document_detail/126507.html
# https://help.aliyun.com/document_detail/106661.html # CDN https://help.aliyun.com/document_detail/106661.html
# 可用于 acme.sh 的 renewHook 脚本,可以自动更新阿里云 SSL 证书并更新对应 CDN 域名,然后删除对应域名的证书。 # 可配合 acme.sh 使用的 renewHook 脚本:自动将新证书上传至阿里云并更新对应 CDN 域名,然后删除对应域名的证书。
# 每次 API 执行都会检测是否失败,如果失败,会中断脚本执行并返回自定义错误代码 # 每次 API 执行都会检测是否失败,如果失败,会中断脚本执行并返回自定义错误代码
# acme.sh 导出的环境变量 # 导出 AliAccessKeyId 和 AliAccessKeySecret
ENV_NAME=( export AliAccessKeyId="<AliAccessKeyId>"
export AliAccessKeySecret="<AliAccessKeySecret>"
# shellcheck disable=SC1091
. ../AliyunOpenAPI.sh
# acme.sh 执行 renewHook 时导出的环境变量列表
ACME_ENV_LIST=(
"CERT_PATH" "CERT_PATH"
"CERT_KEY_PATH" "CERT_KEY_PATH"
"CA_CERT_PATH" "CA_CERT_PATH"
@ -15,81 +21,77 @@ ENV_NAME=(
"Le_Domain" "Le_Domain"
) )
# 检查环境变量是否存在 # 检查环境变量是否存在
for value in "${ENV_NAME[@]}" ; do for value in "${ACME_ENV_LIST[@]}" ; do
printenv "$value" > /dev/null || exit 1 printenv "$value" > /dev/null || exit 1
done done
# 获取证书自定义函数 # 获取证书自定义函数
get_cert() { get_cert() {
sed -e "/^$/d" "$(printenv CERT_FULLCHAIN_PATH)" # 使用 sed 删除掉证书文件的空行 # 使用 sed 删除掉证书文件的空行
sed -e "/^$/d" "$(printenv CERT_FULLCHAIN_PATH)"
} }
# 获取密钥自定义函数 # 获取密钥自定义函数
get_key() { get_key() {
cat "$(printenv CERT_KEY_PATH)" cat "$(printenv CERT_KEY_PATH)"
} }
# 导出 AliAccessKeyId 和 AliAccessKeySecret
export AliAccessKeyId="<AliAccessKeyId>"
export AliAccessKeySecret="<AliAccessKeySecret>"
DOMAIN=$(printenv Le_Domain) DOMAIN=$(printenv Le_Domain)
CERT_NAME="${DOMAIN}-$(date +%s)" # 证书名称 # 证书名称
CERT_NAME="${DOMAIN}-$(date +%s)"
# 需要更新证书的 CDN 域名列表 # 需要更新证书的 CDN 域名列表
DOMAIN_LIST=( DOMAIN_LIST=(
"example.example.com" "example.example.com"
) )
# shellcheck disable=SC1091
. ../AliyunOpenAPI.sh
ali_custom_name=( api_custom_key=(
"CurrentPage" "CurrentPage"
"ShowSize" "ShowSize"
) )
# 获取第一页的 50 个结果,如果你的证书列表条目较多,可以考虑增加获取数量。 api_custom_value=(
ali_custom_value=(
"1" "1"
"50" "50"
) )
# 获取证书列表 # 获取证书列表
result=$(aliapi_rpc "cas.aliyuncs.com" "GET" "2018-07-13" "DescribeUserCertificateList" "${ali_custom_name[*]}" "${ali_custom_value[*]}" || exit 101) result=$(aliapi_rpc "cas.aliyuncs.com" "GET" "2018-07-13" "DescribeUserCertificateList" "${api_custom_key[*]}" "${api_custom_value[*]}" || exit 101)
# 使用 jq 处理返回的 JSON 数据并提取出匹配当前证书域名的证书列表的 ID用于稍后的删除旧证书操作。 # 使用 jq 处理返回的 JSON 数据并提取出匹配当前证书域名的证书列表的 ID用于稍后的删除旧证书操作。
cert_list=$(echo "$result" | jq -cr ".CertificateList|map(select(.common == \"${DOMAIN}\"))|map(.id)|.[]") cert_list=$(echo "$result" | jq -cr ".CertificateList|map(select(.common == \"${DOMAIN}\"))|map(.id)|.[]")
ali_custom_name=(
api_custom_key=(
"Cert" "Cert"
"Key" "Key"
"Name" "Name"
) )
# 使用自定义函数获取证书和密钥,保证内容可以被安全的传递过去 # 使用自定义函数获取证书和密钥,保证内容可以被完整的传递。
ali_custom_value=( api_custom_value=(
"get_cert()" "get_cert()"
"get_key()" "get_key()"
"$CERT_NAME" "$CERT_NAME"
) )
# 上传新的证书 # 上传新的证书
aliapi_rpc "cas.aliyuncs.com" "GET" "2018-07-13" "CreateUserCertificate" "${ali_custom_name[*]}" "${ali_custom_value[*]}" || exit 102 aliapi_rpc "cas.aliyuncs.com" "GET" "2018-07-13" "CreateUserCertificate" "${api_custom_key[*]}" "${api_custom_value[*]}" || exit 102
# 设置 CDN 域名列表使用新的证书 # 设置 CDN 域名列表使用新的证书
for domain in "${DOMAIN_LIST[@]}"; do for domain in "${DOMAIN_LIST[@]}"; do
ali_custom_name=( api_custom_key=(
"DomainName" "DomainName"
"ServerCertificateStatus" "ServerCertificateStatus"
"CertName" "CertName"
"CertType" "CertType"
) )
ali_custom_value=( api_custom_value=(
"$domain" "$domain"
"on" "on"
"$CERT_NAME" "$CERT_NAME"
"cas" "cas"
) )
aliapi_rpc "cdn.aliyuncs.com" "GET" "2018-05-10" "SetDomainServerCertificate" "${ali_custom_name[*]}" "${ali_custom_value[*]}" || _exit 103 "Set cdn domain cert fail: $domain" aliapi_rpc "cdn.aliyuncs.com" "GET" "2018-05-10" "SetDomainServerCertificate" "${api_custom_key[*]}" "${api_custom_value[*]}" || exit 103
done done
# 删除旧的证书 # 删除旧的证书
for id in ${cert_list}; do for id in ${cert_list}; do
ali_custom_name=( api_custom_key=(
"CertId" "CertId"
) )
ali_custom_value=( api_custom_value=(
"$id" "$id"
) )
aliapi_rpc "cas.aliyuncs.com" "GET" "2018-07-13" "DeleteUserCertificate" "${ali_custom_name[*]}" "${ali_custom_value[*]}" || _exit 104 "Delete old cert fail: $id" aliapi_rpc "cas.aliyuncs.com" "GET" "2018-07-13" "DeleteUserCertificate" "${api_custom_key[*]}" "${api_custom_value[*]}" || exit 104
done done