This is article 63 of the Stick to Technical Writing Project (including translation). Set a small goal of 999, at least 2 articles per week.
Apisix does not support automatic renewal of SSL certificates, but the API is open. This article mainly explains how to use the renew-hook feature of acme.sh to automatically update apisix HTTPS certificates.
Create/update apisix SSL script
NOTE: OpenSSL, jq, acme.sh needs to be installed
My script supports retrieving the existing SSL list to see if the certificate exists. If it exists, it will be updated, and if it does not, it will be created. Snis uses the PEM read by OpenSSL, and the valid start and end time is also the PEM read by OpenSSL
Save my GIST as an executable script and add execute permissions
$ curl --output /root/.acme.sh/renew-hook-update-apisix.sh --silent https://gist.githubusercontent.com/anjia0532/9ebf8011322f43e3f5037bc2af3aeaa6/raw/65b359a4eed0ae990f9188c2afa22bacd84716 52/renew-hook-update-apisix.sh $ chmod +x /root/.acme.sh/renew-hook-update-apisix.sh $ /root/.acme.sh/renew-hook-update-apisix.sh Usage : /root/.acme.sh/renew-hook-update-apisix.sh -h <apisix admin host> -p <certificate pem file> -k <certificate private key file> -a <admin api key> -t <print debug info switch off/on,default off>
Copy the code
Considering the domestic network environment, the code of renew-hook-update-apisix.sh is posted here, but note that the subsequent updates are mainly gist
#! /usr/bin/env bash
# author [email protected]
# blog https://anjia0532.github.io/
# github https://github.com/anjia0532
# this script depend on jq,check it first
RED='\033[0;31m'
NC='\033[0m' # No Color
if ! [ -x "$(command -v jq)" ]; then
echo -e "${RED}Error: jq is not installed.${NC}"2 > &exit 1
fi
if ! [ -x "$(command -v openssl)" ]; then
echo -e "${RED}Error: openssl is not installed.${NC}"2 > &exit 1
fi
if ! [ -x "$(command -v ~/.acme.sh/acme.sh)" ]; then
echo -e "${RED}Error: acme.sh is not installed.(doc https://github.com/acmesh-official/acme.sh/wiki/How-to-install)${NC}"2 > &exit 1
fi
usage () { echo "Usage : $0 -h <apisix admin host> -p <certificate pem file> -k <certificate private key file> -a <admin api key> -t <print debug info switch off/on,default off>"; }
# parse args
while getopts "h:p:k:a:t:" opts; do
case ${opts} in
h) HOST=${OPTARG} ;;
p) PEM=${OPTARG} ;;
k) KEY=${OPTARG} ;;
a) API_KEY=${OPTARG} ;;
t) DEBUG=${OPTARG} ;;
*) usage; exit;;
esac
done
# those args must be not null
if[!"$HOST" ] || [ ! "$PEM" ] || [ ! "$KEY" ] || [ ! "$API_KEY" ]
then
usage
exit 1
fi
# optional args,set default value
[ -z "$DEBUG" ] && DEBUG=off
# print vars key and value when DEBUG eq on
[[ "on"= ="$DEBUG"&&]]echo -e "HOST:${HOST} API_KEY:${API_KEY} PEM FILE:${PEM} KEY FILE:${KEY} DEBUG:${DEBUG}"
# get all ssl and filter this one by sni name
cert_content=$(curl --silent --location --request GET "${HOST}/apisix/admin/ssl/" \
--header "X-API-KEY: ${API_KEY}" \
--header 'Content-Type: application/json' | jq "first(.node.nodes[]| select(.value.snis[] | contains(\"$(openssl x509 -in $PEM -noout -text|grep -oP '(? <=DNS:|IP Address:)[^,]+'|sort|head -n1)\")))")
# create a new ssl when it not exist
if [ -z "$cert_content" ]
then
cert_content="{\"snis\":[],\"status\": 1}"
# read domains from pem file by openssl
snis=$(openssl x509 -in $PEM -noout -text|grep -oP '(? <=DNS:|IP Address:)[^,]+'|sort)
for sni in ${snis[@]} ; do
cert_content=$(echo $cert_content | jq ".snis += [\"$sni\] "")
done
validity_start=$(date --date="$(openssl x509 -startdate -noout -in $PEM|cut -d= -f 2)" +"%s")
validity_end=$(date --date="$(openssl x509 -enddate -noout -in $PEM|cut -d= -f 2)" +"%s")
cert_content=$(echo $cert_content | jq ".|.cert = \"$(cat $PEM)\"|.key = \"$(cat $KEY)\"|.validity_start=${validity_start}|.validity_end=${validity_end}")
cert_update_result=$(curl --silent --location --request POST "${HOST}/apisix/admin/ssl/" \
--header "X-API-KEY: ${API_KEY}" \
--header 'Content-Type: application/json' \
--data "$cert_content" )
[[ "on"= ="$DEBUG"&&]]echo -e "cert_content: \n${cert_content}\n\ncreate result json:\n\n${cert_update_result}"
else
# get exist ssl id
URI=$(echo $cert_content | jq -r ".key")
ID=$(echo ${URI##*/})
# get exist ssl certificate json , modify cert and key value
cert_content=$(echo $cert_content | jq ".value|.cert = \"$(cat $PEM)\"|.key = \"$(cat $KEY)\"|.id=\"${ID}\"|.update_time=$(date +'%s')")
# update apisix ssl
cert_update_result=$(curl --silent --location --request PUT "${HOST}/apisix/admin/ssl/${ID}" \
--header "X-API-KEY: ${API_KEY}" \
--header 'Content-Type: application/json' \
--data "$cert_content" )
[[ "on"= ="$DEBUG"&&]]echo -e "cert_content: \n${cert_content}\n\nupdate result json:\n\n${cert_update_result}"
fi
exit 0
Copy the code
Acme. Sh
- Install the acme. Sh
See the official documentation github.com/acmesh-offi…
curl https://get.acme.sh | sh -s [email protected]
Copy the code
- Renew -hook add renew-hook
See the official documentation github.com/acmesh-offi… And renew-hook documentation github.com/acmesh-offi…
$ acme.sh --issue --staging -d demo.domain --renew-hook "/root/.acme.sh/renew-hook-update-apisix.sh -h http://apisix-admin:port -p /root/.acme.sh/demo.domain/demo.domain.cer -k /root/.acme.sh/demo.domain/demo.domain.key -a xxxxxxxxxxxxx"
$ acme.sh --renew --domain demo.domain
Copy the code
As an aside, if you use Ansible, you can also use mineansible galaxy, Document referenceGithub.com/anjia0532/a…
ansible-galaxy install anjia0532.acme_sh
Copy the code
Want ads
Friends in Jinan, Shandong, welcome to join us and do things together. Long-term recruitment, Java programmer, big data engineer, operation and maintenance engineer, front-end engineer.
The resources
- My blog
- I’m the nuggets
- request help: How to auto upgrade SSL certificate, such as using let’s encrypt #3841