Skip to content

Instantly share code, notes, and snippets.

@tobz
Created December 7, 2023 18:27
Show Gist options
  • Save tobz/d97bcf9bdf21a8a8acf6fc53453ba0df to your computer and use it in GitHub Desktop.
Save tobz/d97bcf9bdf21a8a8acf6fc53453ba0df to your computer and use it in GitHub Desktop.
#!/usr/bin/env sh
set -euo pipefail
ACME_SH_HOME="/data/acme.sh"
ACME_SERVER="https://acme.zerossl.com/v2/DV90"
contains() {
if [ "$1" ] && [ "$2" ] && [ -z "${1##*"$2"*}" ];
then
echo "true";
else
echo "false";
fi
}
## Phase 0: Initialize our dedicated configuration directory.
if [ ! -d ${ACME_SH_HOME} ]; then
mkdir -p ${ACME_SH_HOME}
cp -R /acme.sh ${ACME_SH_HOME}
fi
## Phase 1: Register the ACME account if not already registered.
if [ ! -f ${ACME_SH_HOME}/ca/acme.zerossl.com/v2/DV90/account.json ]; then
echo "[*] Registering ACME account via ZeroSSL..."
acme.sh --config-home ${ACME_SH_HOME} \
--server ${ACME_SERVER} \
--register-account \
--email ${ACME_ACCOUNT_EMAIL}
echo "[✓] Registered."
fi
## Phase 2: Issue/deploy the certificate if this is the first time... or renew it.
acme_sh_config_dirs=$(find ${ACME_SH_HOME} -type d)
has_domain_dir=$(contains "${acme_sh_config_dirs}" "${ACME_DOMAIN}")
if [ "${has_domain_dir}" = "false" ]; then
echo "[*] Issuing ACME certificate for ${ACME_DOMAIN}..."
acme.sh --config-home ${ACME_SH_HOME} \
--server ${ACME_SERVER} \
--issue \
--dns dns_cf \
--domain ${ACME_DOMAIN} \
--keylength 4096
echo "[✓] Issued."
echo "[*] Deploying ACME certificate for ${ACME_DOMAIN}..."
acme.sh --config-home ${ACME_SH_HOME} \
--insecure \
--deploy \
--domain ${ACME_DOMAIN} \
--deploy-hook ${ACME_SH_DEPLOY_HOOK}
echo "[✓] Deployed."
else
# We're renewing the certificate, which both does the actual certificate renewal but also then
# deploys it, as the deploy method/information is baked into the files acme.sh keeps in its home
# directory after the initial issue/deploy.
echo "[*] Checking if ACME certificate for ${ACME_DOMAIN} needs to be renewed..."
cron_output=$(acme.sh --config-home ${ACME_SH_HOME} --cron)
skipped_renew=$(contains "${cron_output}" "Skipped ${ACME_DOMAIN}")
cron_rc=$?
if [ "${skipped_renew}" = "true" ]; then
echo "[✓] No renewal needed."
else
if [ "${cron_rc}" != "0" ]; then
echo "[✗] Failed to renew or deploy."
else
echo "[✓] Renewed and deployed."
fi
fi
fi
apiVersion: v1
data:
issue-renew-deploy-acme-cert.sh: "<contents of script here>"
kind: ConfigMap
metadata:
name: ext-acme-cert-gen-scripts
---
apiVersion: v1
kind: Secret
metadata:
name: ext-acme-cert-gen-settings
type: Opaque
data:
CF_Token: <base64-encoded token>
CF_Zone_ID: <base64-encoded zone ID>
DEPLOY_TRUENAS_APIKEY: <base64-encoded TrueNAS API key>
DEPLOY_TRUENAS_HOSTNAME: <base64-encoded TrueNAS hostname - used to connect to API>
DEPLOY_TRUENAS_SCHEME: <base64-encoded scheme for TrueNAS API e.g. http/https>
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ext-acme-cert-gen-data
spec:
resources:
requests:
storage: 64Mi # Probably overkill, just needs to hold enough for the cert data and some config files.
accessModes:
- ReadWriteMany
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: generate-external-cert
spec:
schedule: "@monthly"
concurrencyPolicy: Replace
jobTemplate:
spec:
template:
spec:
containers:
- name: acme-sh
image: neilpang/acme.sh:3.0.7
imagePullPolicy: IfNotPresent
command:
- /issue-renew-deploy-acme-cert.sh
env:
- name: ACME_DOMAIN
value: subdomain.company.org
- name: ACME_ACCOUNT_EMAIL
value: someguy@gmail.com
- name: ACME_SH_DEPLOY_HOOK
value: truenas
envFrom:
- secretRef:
name: ext-acme-cert-gen-settings
volumeMounts:
- mountPath: /issue-renew-deploy-acme-cert.sh
name: scripts
subPath: issue-renew-deploy-acme-cert.sh
- name: data
mountPath: /data
restartPolicy: OnFailure
volumes:
- name: scripts
configMap:
name: ext-acme-cert-gen-scripts
defaultMode: 0550
- name: data
persistentVolumeClaim:
claimName: ext-acme-cert-gen-data
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment