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

  1. Install the acme. Sh

See the official documentation github.com/acmesh-offi…

curl https://get.acme.sh | sh -s [email protected]
Copy the code
  1. 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