system-config/playbooks/roles/letsencrypt-acme-sh-install/files/driver.sh

128 lines
5.0 KiB
Bash

#!/bin/bash
ACME_SH=${ACME_SH:-/opt/acme.sh/acme.sh}
CERT_HOME=${CERT_HOME:-/etc/letsencrypt-certs}
CHALLENGE_ALIAS_DOMAIN=${CHALLENGE_ALIAS_DOMAIN:-acme.opendev.org.}
# Set to !0 to use letsencrypt staging rather than production requests
LETSENCRYPT_STAGING=${LETSENCRYPT_STAGING:-0}
LOG_FILE=${LOG_FILE:-/var/log/acme.sh/acme.sh.log}
SERVER=""
if [[ ${LETSENCRYPT_STAGING} != 0 ]]; then
# TODO acme.sh doesn't let us specify staging and also set the server.
# If --staging is passed then the built in default is used. Can/should
# we change this to --server letsencrypt_test?
SERVER="--staging"
#SERVER="--server letsencrypt_test"
else
SERVER="--server letsencrypt"
fi
# Ensure we don't write out files as world-readable
umask 027
echo -e "\n--- start --- ${1} --- $(date -u '+%Y-%m-%dT%k:%M:%S%z') ---" >> ${LOG_FILE}
if [[ ${1} == "issue" ]]; then
# Take output like:
# [Thu Feb 14 13:44:37 AEDT 2019] Domain: '_acme-challenge.test.opendev.org'
# [Thu Feb 14 13:44:37 AEDT 2019] TXT value: 'QjkChGcuqD7rl0jN8FNWkWNAISX1Zry_vE-9RxWF2pE'
#
# and turn it into:
#
# _acme-challenge.test.opendev.org:QjkChGcuqD7rl0jN8FNWkWNAISX1Zry_vE-9RxWF2pE
#
# Ansible then parses this back to a dict.
shift;
for arg in "$@"; do
$ACME_SH ${SERVER} \
--cert-home ${CERT_HOME} \
--no-color \
--yes-I-know-dns-manual-mode-enough-go-ahead-please \
--issue \
--dns \
--challenge-alias ${CHALLENGE_ALIAS_DOMAIN} \
$arg 2>&1 | tee -a ${LOG_FILE} | \
egrep 'Domain:|TXT value:' | cut -d"'" -f2 | paste -d':' - -
# shell magic ^ is
# - extract everything between ' '
# - stick every two lines together, separated by a :
done
elif [[ ${1} == "issue-selfsign" ]]; then
shift;
for arg in "$@"; do
# looks like
# "-d foo01.com -d foo.com " "-d bar01.com -d bar.com"
arr=(${arg})
len=${#arr[@]}
for (( i=0; i<$len; i++ )); do
if [[ $((i%2)) -eq 0 ]]; then
continue # this should be a "-d"
else
# The ACME protocol hashes "stuff" and the TXT record
# is ultimately a sha256 encoded into base64url
# (RFC8555); emulate that here.
base64url=$(echo -n ${arr[$i]}-${RANDOM} | \
openssl dgst -binary -sha256 | \
openssl base64 | sed 's/+/-/g; s,/,_,g; s/=//g')
echo "${arr[$i]}:${base64url}"
fi
done
done
elif [[ ${1} == "renew" ]]; then
shift;
for arg in "$@"; do
# NOTE(ianw) 2020-02-28 : we only set force here because of a
# bug/misfeature in acme.sh dns manual-mode where it does not
# notice that the renewal is required when we update domain
# names in a cert
# (https://github.com/acmesh-official/acme.sh/issues/2763).
# This is safe (i.e. will not explode our quota limits by
# constantly renewing) because Ansible only calls this path
# when TXT records have been installed for this certificate;
# i.e. we will never run this renewal unless it is actually
# required.
$ACME_SH ${SERVER} \
--cert-home ${CERT_HOME} \
--no-color \
--yes-I-know-dns-manual-mode-enough-go-ahead-please \
--force \
--renew \
$arg 2>&1 | tee -a ${LOG_FILE}
done
elif [[ ${1} == "selfsign" ]]; then
# For testing, simulate the key generation
shift;
for arg in "$@"; do
# TODO(ianw): Set SAN names from the other "-d" arguments?;
# it's a pita to parse.
{
read -r -a domain_array <<< "$arg"
domain=${domain_array[1]}
mkdir -p ${CERT_HOME}/${domain}
cd ${CERT_HOME}/${domain}
echo "Creating certs in ${CERT_HOME}/${domain}"
# Create key for domain
openssl genrsa -out ${domain}.key 2048
# openssl makes this 0600; match the permissions acme.sh
# makes it with for general sanity
chmod 0640 ${domain}.key
# Generate a fake CA key
openssl genrsa -out ca.key 2048
# Create fake CA root certificate
openssl req -x509 -new -nodes -key ca.key -sha256 -days 1024 -subj "/C=US/ST=CA/O=opendev" -out ca.cer
# Create localhost certificate signing request
openssl req -sha256 -new -key ${domain}.key -out ${domain}.csr -subj '/CN=localhost'
# Create localhost certificate signed by fake CA
openssl x509 -req -CA ca.cer -CAkey ca.key -CAcreateserial \
-sha256 -days 365 -in ${domain}.csr -out ${domain}.cer
cp ${domain}.cer fullchain.cer
} 2>&1 | tee -a ${LOG_FILE}
done
else
echo "Unknown driver arg: $1"
exit 1
fi
echo "--- end --- $(date -u '+%Y-%m-%dT%k:%M:%S%z') ---" >> ${LOG_FILE}