acme init

This commit is contained in:
Dominik Chilla 2020-03-23 00:18:11 +01:00
parent 70b3ed4c44
commit ba3be527e9
6 changed files with 203 additions and 0 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "acme/dehydrated"]
path = acme/dehydrated
url = https://github.com/dehydrated-io/dehydrated.git

18
acme/README.md Normal file
View File

@ -0,0 +1,18 @@
# ACME - snippet to obtain let´s encrpyt certificates authenticated by DNS-01
## Dockerfile:
```
ADD ./snippets/acme/dehydrated /dehydrated/
ADD ./snippets/acme/config /dehydrated/config
ADD ./snippets/acme/get_cert_ddns01.sh /app/get_cert_ddns01.sh
ADD ./snippets/acme/zwackl_hook.sh /app/zwackl_hook.sh
```
**Do not forget to include the crond-snippet!**
## Environment
* ACME_FQDNS (required)
* ACME_RELOAD_CMD (required)
* ACME_STAGING_ENABLED (optional)
* STAGING_URI (optional)
* DDNS01URI (required)
* DDNS01KEY (required)

3
acme/config Normal file
View File

@ -0,0 +1,3 @@
PRIVATE_KEY_RENEW="no"
PRIVATE_KEY_ROLLOVER="no"
%STAGING%

1
acme/dehydrated Submodule

@ -0,0 +1 @@
Subproject commit 307eaadddfd49aeafda6984f11e6731329372cd5

67
acme/get_cert_ddns01.sh Executable file
View File

@ -0,0 +1,67 @@
#!/bin/bash
# ACME@LETSENCRYPT - DEHYDRATED
if [ ! -z "${ACME_FQDNS+x}" ]; then
if [ -f /dehydrated/lock ]; then
unlink /dehydrated/lock
fi
if [ -z "${ACME_RELOAD_CMD}" ]; then
echo "ENV[ACME_RELOAD_CMD] is mandatory!"
exit 1
fi
if [ ! -d /secrets/ssl ]; then
mkdir -p /secrets/ssl
fi
if [ ! -z "${ACME_STAGING_ENABLED+x}" ]; then
STAGING_URI='CA="https://acme-staging-v02.api.letsencrypt.org/directory"' \
ESCAPED=$(echo "${STAGING_URI}" | sed -e 's/\//\\\//g')
sed -i -e "s/%STAGING%/${ESCAPED}/g" /dehydrated/config
else
sed -i -e "s/%STAGING%//g" /dehydrated/config
fi
if [ ! -z "${DDNS01URI+x}" ]; then
ESCAPED=$(echo "${DDNS01URI}" | sed -e 's/\//\\\//g')
sed -i -e "s/%DDNS01URI%/${ESCAPED}/g" /app/zwackl_hook.sh
else
echo "ENV[DDNS01URI] is mandatory!"
exit 1
fi
if [ ! -z "${DDNS01KEY+x}" ]; then
ESCAPED=$(echo "${DDNS01KEY}" | sed -e 's/\//\\\//g')
sed -i -e "s/%DDNS01KEY%/${ESCAPED}/g" /app/zwackl_hook.sh
else
echo "ENV[DDNS01KEY] is mandatory!"
exit 1
fi
if [ -d /dehydrated ]; then
echo -n "" > /dehydrated/domains.txt
for fqdn in ${ACME_FQDNS}; do
echo "${fqdn}" >> /dehydrated/domains.txt
if [ ! -d "/secrets/ssl/${fqdn}" ]; then
mkdir -p "/secrets/ssl/${fqdn}"
fi
done
chmod +x /app/zwackl_hook.sh
chmod +x /dehydrated/renew_certs
ln -f -s /dehydrated/renew_certs /etc/periodic/daily/renew_certs
if [ -z "$(ls -A /dehydrated/accounts)" ]; then
cd /dehydrated && /dehydrated/dehydrated --register --accept-terms
fi
RUN_DEHYDRATED=''
for fqdn in ${ACME_FQDNS}; do
if [ ! -f "/dehydrated/certs/${fqdn}/fullchain.pem" ]; then
RUN_DEHYDRATED='yes'
fi
ln -f -s "/dehydrated/certs/${fqdn}/privkey.pem" "/secrets/ssl/${fqdn}/key.pem"
ln -f -s "/dehydrated/certs/${fqdn}/fullchain.pem" "/secrets/ssl/${fqdn}/cert.pem"
done
if [ ! -z "${RUN_DEHYDRATED}" ]; then
/dehydrated/dehydrated --cron -t dns-01 -k /app/zwackl_hook.sh
fi
export CROND_ENABLE='acme'
else
echo "Directory /dehydrated not found!"
exit 1
fi
fi

111
acme/zwackl_hook.sh Executable file
View File

@ -0,0 +1,111 @@
#!/bin/bash
function deploy_challenge {
# This hook is called once for every domain that needs to be
# validated, including any alternative names you may have listed.
#
# Parameters:
# - DOMAIN
# The domain name (CN or subject alternative name) being
# validated.
# - TOKEN_FILENAME
# The name of the file is irrelevant for the DNS challenge, yet still provided
# - TOKEN_VALUE
# The token value that needs to be served for validation. For DNS
# validation, this is what you want to put in the _acme-challenge
# TXT record. For HTTP validation it is the value that is expected
# be found in the $TOKEN_FILENAME file.
local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}"
echo;
echo "Deploying challenge for domain $DOMAIN: $TOKEN_VALUE"
CMD_OUT=$(/usr/bin/curl -s --noproxy '*' "%DDNS01URI%/update?fqdn=_acme-challenge.${DOMAIN}&txtdata=${TOKEN_VALUE}&key=%DDNS01KEY%")
if [ $? -ne 0 ]
then
echo "${DOMAIN} -> ${TOKEN_VALUE}: ${CMD_OUT}"
exit 1;
else
echo "OK: ${CMD_OUT}"
fi
echo "Sleeping for 66 seconds to avoid timing conflicts"
sleep 66
}
function clean_challenge {
local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}"
echo;
echo "Cleaning challenge for domain $DOMAIN"
# This hook is called after attempting to validate each domain,
# whether or not validation was successful. Here you can delete
# files or DNS records that are no longer needed.
#
# The parameters are the same as for deploy_challenge.
}
function deploy_cert {
# This hook is called once for each certificate that has been
# produced. Here you might, for instance, copy your new certificates
# to service-specific locations and reload the service.
#
# Parameters:
# - DOMAIN
# The primary domain name, i.e. the certificate common
# name (CN).
# - KEYFILE
# The path of the file containing the private key.
# - CERTFILE
# The path of the file containing the signed certificate.
# - FULLCHAINFILE
# The path of the file containing the full certificate chain.
# - CHAINFILE
# The path of the file containing the intermediate certificate(s).
local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}"
}
function unchanged_cert {
# This hook is called once for each certificate that is still valid at least 30 days
#
# Parameters:
# - DOMAIN
# The primary domain name, i.e. the certificate common
# name (CN).
# - KEYFILE
# The path of the file containing the private key.
# - CERTFILE
# The path of the file containing the signed certificate.
# - FULLCHAINFILE
# The path of the file containing the full certificate chain.
# - CHAINFILE
# The path of the file containing the intermediate certificate(s).
local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" CHAINFILE="${5}"
echo "Certificate for domain $DOMAIN is still valid - no action taken"
}
generate_csr() {
local DOMAIN="${1}" CERTDIR="${2}" ALTNAMES="${3}"
}
startup_hook() {
# This hook is called before the cron command to do some initial tasks
# (e.g. starting a webserver).
:
}
exit_hook() {
# This hook is called at the end of the cron command and can be used to
# do some final (cleanup or other) tasks.
:
}
HANDLER="$1"; shift
if [[ "${HANDLER}" =~ ^(deploy_challenge|clean_challenge|deploy_cert|unchanged_cert|invalid_challenge|request_failure|generate_csr|startup_hook|exit_hook)$ ]]; then
"$HANDLER" "$@"
fi