Rewrite __letsencrypt_cert type

This commit adds the following features:

 * Ability to expand existing certificate
 * Ability to manage object state
 * Ability to obtain test certificate
 * Ability to promote test certificate to production
 * Ability to specify custom certificate name
 * Ability to specify multiple domains per certificate
 * Ability to use Certbot in standalone mode
 * Messaging

This commit also introduces the following behavioral changes:

 * Attempt to install Certbot only when it is not installed
   already
 * Installation of the cron job has to be enabled using
   `--automatic-renewal` parameter

**Note:** Object ID is now treated as certificate name and new
required parameter `--domain` was added.
This commit is contained in:
lubo 2018-05-07 12:57:48 +02:00
parent 543bc8fed9
commit 22d570ae60
14 changed files with 239 additions and 105 deletions

View file

@ -0,0 +1,3 @@
#!/bin/sh -e
command -v certbot 2>/dev/null || true

View file

@ -0,0 +1,4 @@
#!/bin/sh -e
certbot certificates --cert-name "${__object_id:?}" | grep ' Domains: ' | \
cut -d ' ' -f 6- | tr ' ' '\n'

View file

@ -0,0 +1,7 @@
#!/bin/sh -e
if certbot certificates | grep -q " Certificate Name: ${__object_id:?}$"; then
echo yes
else
echo no
fi

View file

@ -0,0 +1,8 @@
#!/bin/sh -e
if certbot certificates --cert-name "${__object_id:?}" | \
grep -q 'INVALID: TEST_CERT'; then
echo yes
else
echo no
fi

View file

@ -1,5 +0,0 @@
domain=$__object_id
if [ -f "/etc/letsencrypt/live/$domain/fullchain.pem" ]; then
echo yes
fi

83
cdist/conf/type/__letsencrypt_cert/gencode-remote Normal file → Executable file
View file

@ -1,18 +1,75 @@
domain="$__object_id" #!/bin/sh -e
exists=$(cat "$__object/explorer/exists") certificate_exists=$(cat "${__object:?}/explorer/certificate-exists")
webroot="$(cat "$__object/parameter/webroot")" name="${__object_id:?}"
admin_email="$(cat "$__object/parameter/admin-email")" state=$(cat "${__object}/parameter/state")
if [ -n "$exists" ]; then case "${state}" in
absent)
if [ "${certificate_exists}" = "no" ]; then
exit 0 exit 0
fi fi
cat <<EOF echo "certbot delete --cert-name '${name}' --quiet"
if [ ! -d "$webroot" ]; then
mkdir -p "$webroot"
fi
certbot certonly -n --agree-tos --email '$admin_email' --quiet --webroot \ echo remove >> "${__messages_out:?}"
-w '$webroot' -d '$domain' ;;
EOF present)
requested_domains="${__object}/parameter/domain"
staging=no
if [ -f "${__object}/parameter/staging" ]; then
staging=yes
fi
if [ "${certificate_exists}" = "yes" ]; then
existing_domains="${__object}/explorer/certificate-domains"
certificate_is_test=$(cat "${__object}/explorer/certificate-is-test")
sort -uo "${requested_domains}" "${requested_domains}"
sort -uo "${existing_domains}" "${existing_domains}"
if [ -z "$(comm -23 "${requested_domains}" "${existing_domains}")" ] && \
[ "${certificate_is_test}" = "${staging}" ]; then
exit 0
fi
fi
admin_email="$(cat "$__object/parameter/admin-email")"
webroot="$(cat "$__object/parameter/webroot")"
cat <<-EOF
certbot certonly \
--agree-tos \
--cert-name '${name}' \
--email '${admin_email}' \
--expand \
--non-interactive \
--quiet \
$(if [ "${staging}" = "yes" ]; then
echo "--staging"
elif [ "${certificate_is_test}" != "${staging}" ]; then
echo "--force-renewal"
fi) \
$(if [ -z "${webroot}" ]; then
echo "--standalone"
else
echo "--webroot --webroot-path '${webroot}'"
fi) \
$(while read -r domain; do
echo "--domain '${domain}' \\"
done < "${requested_domains}")
EOF
if [ "${certificate_exists}" = "no" ]; then
echo create >> "${__messages_out}"
else
echo change >> "${__messages_out}"
fi
;;
*)
echo "Unsupported state: ${state}" >&2
exit 1
;;
esac

View file

@ -3,54 +3,95 @@ cdist-type__letsencrypt_cert(7)
NAME NAME
---- ----
cdist-type__letsencrypt_cert - Get an SSL certificate from Let's Encrypt
cdist-type__letsencrypt_cert - Get an SSL certificate from Let's Encrypt
DESCRIPTION DESCRIPTION
----------- -----------
Automatically obtain a Let's Encrypt SSL certificate. Uses certbot's webroot
method. You must set up your web server to work with webroot.
Automatically obtain a Let's Encrypt SSL certificate using Certbot.
REQUIRED PARAMETERS REQUIRED PARAMETERS
------------------- -------------------
webroot
The path to your webroot, as set up in your webserver config.
admin-email admin-email
Where to send Let's Encrypt emails like "certificate needs renewal". Where to send Let's Encrypt emails like "certificate needs renewal".
REQUIRED MULTIPLE PARAMETERS
----------------------------
domain
A domain to be included in the certificate.
OPTIONAL PARAMETERS OPTIONAL PARAMETERS
------------------- -------------------
None.
state
'present' or 'absent', defaults to 'present' where:
present
if the certificate does not exist, it will be obtained
absent
the certificate will be removed
webroot
The path to your webroot, as set up in your webserver config. If this
parameter is not present, Certbot will be run in standalone mode.
OPTIONAL MULTIPLE PARAMETERS OPTIONAL MULTIPLE PARAMETERS
---------------------------- ----------------------------
renew-hook renew-hook
Renew hook command directly passed to certbot in cron job. Renew hook command directly passed to Certbot in cron job.
BOOLEAN PARAMETERS
------------------
automatic-renewal
Install a cron job, which attempts to renew certificates daily.
staging
Obtain a test certificate from a staging server.
MESSAGES
--------
change
Certificte was changed.
create
Certificte was created.
remove
Certificte was removed.
EXAMPLES EXAMPLES
-------- --------
.. code-block:: sh .. code-block:: sh
__letsencrypt_cert example.com --admin-email root@example.com --webroot /data/letsencrypt/root __letsencrypt_cert example.com \
--admin-email root@example.com \
__letsencrypt_cert example.com --admin-email root@example.com --webroot /data/letsencrypt/root --renew-hook "service nginx reload" --automatic-renewal \
--domain example.com \
--domain foo.example.com \
--domain bar.example.com \
--renew-hook "service nginx reload" \
--webroot /data/letsencrypt/root
AUTHORS AUTHORS
------- -------
| Nico Schottelius <nico-cdist--@--schottelius.org> | Nico Schottelius <nico-cdist--@--schottelius.org>
| Kamila Součková <kamila--@--ksp.sk> | Kamila Součková <kamila--@--ksp.sk>
| Darko Poljak <darko.poljak--@--gmail.com> | Darko Poljak <darko.poljak--@--gmail.com>
| Ľubomír Kučera <lubomir.kucera.jr at gmail.com>
COPYING COPYING
------- -------
Copyright \(C) 2017 Nico Schottelius, Kamila Součková, Darko Poljak. You can redistribute it
and/or modify it under the terms of the GNU General Public License as Copyright \(C) 2017-2018 Nico Schottelius, Kamila Součková, Darko Poljak and
published by the Free Software Foundation, either version 3 of the Ľubomír Kučera. You can redistribute it and/or modify it under the terms of
License, or (at your option) any later version. the GNU General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.

52
cdist/conf/type/__letsencrypt_cert/manifest Normal file → Executable file
View file

@ -1,7 +1,12 @@
os=$(cat "$__global/explorer/os") #!/bin/sh
os_version=$(cat "$__global/explorer/os_version")
case "$os" in certbot_fullpath="$(cat "${__object:?}/explorer/certbot-path")"
if [ -z "${certbot_fullpath}" ]; then
os="$(cat "${__global:?}/explorer/os")"
os_version="$(cat "${__global}/explorer/os_version")"
case "$os" in
debian) debian)
case "$os_version" in case "$os_version" in
8*) 8*)
@ -10,8 +15,10 @@ case "$os" in
--distribution jessie-backports \ --distribution jessie-backports \
--component main --component main
require="__apt_source/jessie-backports" __package_apt python-certbot --target-release jessie-backports require="__apt_source/jessie-backports" __package_apt python-certbot \
require="__apt_source/jessie-backports" __package_apt certbot --target-release jessie-backports --target-release jessie-backports
require="__apt_source/jessie-backports" __package_apt certbot \
--target-release jessie-backports
# Seems to be a missing dependency on debian 8 # Seems to be a missing dependency on debian 8
__package python-ndg-httpsclient __package python-ndg-httpsclient
;; ;;
@ -21,8 +28,10 @@ case "$os" in
--distribution stretch-backports \ --distribution stretch-backports \
--component main --component main
require="__apt_source/stretch-backports" __package_apt python-certbot --target-release stretch-backports require="__apt_source/stretch-backports" __package_apt python-certbot \
require="__apt_source/stretch-backports" __package_apt certbot --target-release stretch-backports --target-release stretch-backports
require="__apt_source/stretch-backports" __package_apt certbot \
--target-release stretch-backports
;; ;;
*) *)
echo "Unsupported OS version: $os_version" >&2 echo "Unsupported OS version: $os_version" >&2
@ -40,8 +49,10 @@ case "$os" in
--distribution jessie-backports \ --distribution jessie-backports \
--component main --component main
require="__apt_source/jessie-backports" __package_apt python-certbot --target-release jessie-backports require="__apt_source/jessie-backports" __package_apt python-certbot \
require="__apt_source/jessie-backports" __package_apt certbot --target-release jessie-backports --target-release jessie-backports
require="__apt_source/jessie-backports" __package_apt certbot \
--target-release jessie-backports
# Seems to be a missing dependency on debian 8 # Seems to be a missing dependency on debian 8
__package python-ndg-httpsclient __package python-ndg-httpsclient
;; ;;
@ -62,18 +73,21 @@ case "$os" in
echo "Unsupported os: $os" >&2 echo "Unsupported os: $os" >&2
exit 1 exit 1
;; ;;
esac esac
renew_hook_param="$__object/parameter/renew-hook"
renew_hook=""
if [ -f "$renew_hook_param" ]; then
while read hook; do
renew_hook="$renew_hook --renew-hook \"$hook\""
done < "$renew_hook_param"
fi fi
__cron letsencrypt-certbot \ if [ -f "${__object}/parameter/automatic-renewal" ]; then
renew_hook_param="${__object}/parameter/renew-hook"
renew_hook=""
if [ -f "${renew_hook_param}" ]; then
while read hook; do
renew_hook="${renew_hook} --renew-hook \"${hook}\""
done < "${renew_hook_param}"
fi
__cron letsencrypt-certbot \
--user root \ --user root \
--command "$certbot_fullpath renew -q $renew_hook" \ --command "${certbot_fullpath} renew -q ${renew_hook}" \
--hour 0 \ --hour 0 \
--minute 47 --minute 47
fi

View file

@ -0,0 +1,2 @@
automatic-renewal
staging

View file

@ -0,0 +1 @@
present

View file

@ -0,0 +1,2 @@
state
webroot

View file

@ -1,2 +1 @@
admin-email admin-email
webroot

View file

@ -0,0 +1 @@
domain