Merge branch 'uacme' into 'master'
TLS certificates with uacme See merge request ungleich-public/cdist-contrib!25
This commit is contained in:
commit
16b5158ef5
12 changed files with 389 additions and 0 deletions
32
type/__uacme_account/gencode-remote
Normal file
32
type/__uacme_account/gencode-remote
Normal file
|
@ -0,0 +1,32 @@
|
|||
#!/bin/sh
|
||||
|
||||
os="$(cat "${__global:?}"/explorer/os)"
|
||||
|
||||
case "$os" in
|
||||
alpine|ubuntu|debian)
|
||||
default_confdir=/etc/ssl/uacme
|
||||
;;
|
||||
*)
|
||||
echo "This type currently has no implementation for $os. Aborting." >&2;
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
admin_mail=
|
||||
if [ -f "${__object:?}/parameter/admin-mail" ];
|
||||
then
|
||||
admin_mail="$(cat "${__object:?}/parameter/admin-mail")";
|
||||
fi
|
||||
|
||||
confdir="${default_confdir:?}"
|
||||
if [ -f "${__object:?}/parameter/confdir" ];
|
||||
then
|
||||
confdir="$(cat "${__object:?}/parameter/confdir")"
|
||||
fi
|
||||
|
||||
cat << EOF
|
||||
if ! [ -f "${confdir}/private/key.pem" ];
|
||||
then
|
||||
uacme -y new ${admin_mail}
|
||||
fi
|
||||
EOF
|
52
type/__uacme_account/man.rst
Normal file
52
type/__uacme_account/man.rst
Normal file
|
@ -0,0 +1,52 @@
|
|||
cdist-type__uacme_account(7)
|
||||
============================
|
||||
|
||||
NAME
|
||||
----
|
||||
cdist-type__uacme_account - Install uacme and register Let's Encrypt account.
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
This type is used to bootstrap acquiring certificates from the Let's Encrypt
|
||||
C.A by creating an account and accepting terms of use. The
|
||||
`cdist-type__uacme_obtain(7)` type instances expect to depend on this type.
|
||||
|
||||
|
||||
OPTIONAL PARAMETERS
|
||||
-------------------
|
||||
confdir
|
||||
An alternative configuration directory for uacme's private keys and
|
||||
certificates.
|
||||
|
||||
admin-mail
|
||||
Administrative contact email to register the account with.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# Create account with default settings for the OS.
|
||||
__uacme_account
|
||||
|
||||
# Create an account with email and custom location.
|
||||
__uacme_account --confdir /opt/custom/uacme --admin-mail admin@domain.tld
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
:strong:`cdist-type__letsencrypt_cert`\ (7)
|
||||
:strong:`cdist-type__uacme_obtain`\ (7)
|
||||
|
||||
AUTHORS
|
||||
-------
|
||||
Joachim Desroches <joachim.desroches@epfl.ch>
|
||||
|
||||
COPYING
|
||||
-------
|
||||
Copyright \(C) 2020 Joachim Desroches. You can redistribute it and/or modify it
|
||||
under the terms of 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.
|
14
type/__uacme_account/manifest
Normal file
14
type/__uacme_account/manifest
Normal file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/sh
|
||||
|
||||
os="$(cat "${__global:?}"/explorer/os)"
|
||||
|
||||
case "$os" in
|
||||
"alpine"|"debian"|"ubuntu")
|
||||
uacme_package=uacme
|
||||
;;
|
||||
*)
|
||||
echo "__uacme_account is not yet implemented for os $os. Aborting." >&2;
|
||||
exit 1;
|
||||
esac
|
||||
|
||||
__package $uacme_package
|
2
type/__uacme_account/parameter/optional
Normal file
2
type/__uacme_account/parameter/optional
Normal file
|
@ -0,0 +1,2 @@
|
|||
confdir
|
||||
admin-mail
|
0
type/__uacme_account/singleton
Normal file
0
type/__uacme_account/singleton
Normal file
52
type/__uacme_obtain/files/renew.sh.sh
Executable file
52
type/__uacme_obtain/files/renew.sh.sh
Executable file
|
@ -0,0 +1,52 @@
|
|||
#!/bin/sh
|
||||
|
||||
cat << EOF
|
||||
#!/bin/sh
|
||||
|
||||
UACME_CHALLENGE_PATH=${CHALLENGEDIR:?}
|
||||
export UACME_CHALLENGE_PATH
|
||||
|
||||
# Issue certificate.
|
||||
uacme -c ${CONFDIR:?} -h ${HOOKSCRIPT:?} ${DISABLE_OCSP?} ${MUST_STAPLE?} ${KEYTYPE?} \\
|
||||
issue -- ${DOMAIN:?}
|
||||
|
||||
# Note: exit code 0 means that certificate was issued.
|
||||
# Note: exit code 1 means that certificate was still valid, hence not renewed.
|
||||
# Note: exit code 2 means that something went wrong.
|
||||
status=\$?
|
||||
|
||||
# All is well: we can stop now.
|
||||
if [ \$status -eq 1 ];
|
||||
then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# An error occured.
|
||||
if [ \$status -eq 2 ]; then
|
||||
echo "Failed to renew certificate - exiting." >&2
|
||||
exit 1
|
||||
fi
|
||||
EOF
|
||||
|
||||
# Re-deploy, if needed.
|
||||
if [ -n "${KEY_TARGET?}" ] && [ -n "${CERT_TARGET?}" ];
|
||||
then
|
||||
cat << EOF
|
||||
|
||||
# Deploy newly issued certificate.
|
||||
set -e
|
||||
|
||||
CERT_SOURCE=${CONFDIR:?}/${MAIN_DOMAIN:?}/cert.pem
|
||||
KEY_SOURCE=${CONFDIR:?}/private/${MAIN_DOMAIN:?}/key.pem
|
||||
|
||||
mkdir -p -- $(dirname "${CERT_TARGET?}") $(dirname "${KEY_TARGET?}")
|
||||
|
||||
if ! cmp \${CERT_SOURCE:?} ${CERT_TARGET?} >/dev/null 2>&1; then
|
||||
install -m 0640 \${KEY_SOURCE:?} ${KEY_TARGET?}
|
||||
install -m 0644 \${CERT_SOURCE:?} ${CERT_TARGET?}
|
||||
chown ${OWNER?} ${KEY_TARGET?} ${CERT_TARGET?}
|
||||
|
||||
${RENEW_HOOK?}
|
||||
fi
|
||||
EOF
|
||||
fi
|
24
type/__uacme_obtain/gencode-remote
Normal file
24
type/__uacme_obtain/gencode-remote
Normal file
|
@ -0,0 +1,24 @@
|
|||
#!/bin/sh
|
||||
|
||||
# FIXME: this code is duplicated from the manifest -> let's share it somehow.
|
||||
|
||||
os="$(cat "${__global:?}"/explorer/os)"
|
||||
case "$os" in
|
||||
alpine|ubuntu|debian)
|
||||
default_confdir=/etc/ssl/uacme
|
||||
;;
|
||||
*)
|
||||
echo "__uacme_obtain currently has no implementation for $os. Aborting." >&2;
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
|
||||
confdir="${default_confdir:?}"
|
||||
if [ -f "${__object:?}/parameter/confdir" ];
|
||||
then
|
||||
confdir="$(cat "${__object:?}/parameter/confdir")"
|
||||
fi
|
||||
|
||||
# Run renew script 'by hand' for intial issue - renews will be handled by the
|
||||
# cronjob.
|
||||
echo "$confdir/${__object_id:?}/renew.sh"
|
81
type/__uacme_obtain/man.rst
Normal file
81
type/__uacme_obtain/man.rst
Normal file
|
@ -0,0 +1,81 @@
|
|||
cdist-type__uacme_obtain(7)
|
||||
===========================
|
||||
|
||||
NAME
|
||||
----
|
||||
cdist-type__uacme_obtain - obtain, renew and deploy Let's Encrypt certificates
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
This type leverage uacme to issue and renew Let's Encrypt certificates and
|
||||
provides a simple deployment mechanism. It is expected to be called after
|
||||
`__uacme_account`.
|
||||
|
||||
REQUIRED PARAMETERS
|
||||
-------------------
|
||||
None.
|
||||
|
||||
OPTIONAL PARAMETERS
|
||||
-------------------
|
||||
challengedir
|
||||
Path to publicly available (served by a third-party HTTP server, under
|
||||
`$DOMAIN/.well-known/acme-challenge`) challenge directory.
|
||||
|
||||
confdir
|
||||
uacme configuration directory.
|
||||
|
||||
hookscript
|
||||
Path to the challenge hook program.
|
||||
|
||||
owner
|
||||
Owner of installed certificate (e.g. `www-data`), passed to `chown`.
|
||||
|
||||
install-cert-to
|
||||
Installation path of the issued certificate.
|
||||
|
||||
install-key-to
|
||||
Installation path of the certificate's private key.
|
||||
|
||||
renew-hook
|
||||
Renew hook executed on certificate renewal (e.g. `service nginx reload`).
|
||||
|
||||
force-cert-ownership-to
|
||||
Override default ownership for TLS certificate, passed as argument to chown.
|
||||
|
||||
OPTIONAL MULTIPLE PARAMETERS
|
||||
----------------------------
|
||||
altdomains
|
||||
Alternative domain names for this certificate.
|
||||
|
||||
BOOLEAN PARAMETERS
|
||||
------------------
|
||||
no-ocsp
|
||||
When this flag is *not* specified and the certificate has an Authority
|
||||
Information Access extension with an OCSP server location *uacme* makes an
|
||||
OCSP request to the server; if the certificate is reported as revoked *uacme*
|
||||
forces reissuance regardless of the expiration date.
|
||||
|
||||
must-staple
|
||||
Request certificates with the RFC7633 Certificate Status Request
|
||||
TLS Feature Extension, informally also known as "OCSP Must-Staple".
|
||||
|
||||
use-rsa
|
||||
Use RSA instead of EC for the private key. Only applies to newly generated keys.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
:strong:`cdist-type__letsencrypt_cert`\ (7)
|
||||
:strong:`cdist-type__uacme_account`\ (7)
|
||||
|
||||
AUTHORS
|
||||
-------
|
||||
Joachim Desroches <joachim.desroches@epfl.ch>
|
||||
Timothée Floure <timothee.floure@posteo.net>
|
||||
|
||||
COPYING
|
||||
-------
|
||||
Copyright \(C) 2020 Joachim Desroches. You can redistribute it
|
||||
and/or modify it under the terms of 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.
|
121
type/__uacme_obtain/manifest
Normal file
121
type/__uacme_obtain/manifest
Normal file
|
@ -0,0 +1,121 @@
|
|||
#!/bin/sh
|
||||
|
||||
os="$(cat "${__global:?}"/explorer/os)"
|
||||
case "$os" in
|
||||
alpine|ubuntu|debian)
|
||||
__package uacme
|
||||
|
||||
default_challengedir=/var/www/.well-known/acme-challenge
|
||||
default_hookscript=/usr/share/uacme/uacme.sh
|
||||
default_confdir=/etc/ssl/uacme
|
||||
;;
|
||||
*)
|
||||
echo "__uacme_obtain currently has no implementation for $os. Aborting." >&2;
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
|
||||
CHALLENGEDIR=${default_challengedir:?}
|
||||
if [ -f "${__object:?}/parameter/challengedir" ];
|
||||
then
|
||||
CHALLENGEDIR="$(cat "${__object:?}/parameter/challengedir")"
|
||||
fi
|
||||
export CHALLENGEDIR
|
||||
|
||||
CONFDIR="${default_confdir:?}"
|
||||
if [ -f "${__object:?}/parameter/confdir" ];
|
||||
then
|
||||
CONFDIR="$(cat "${__object:?}/parameter/confdir")"
|
||||
fi
|
||||
export CONFDIR
|
||||
|
||||
DISABLE_OCSP=
|
||||
if [ -f "${__object:?}/parameter/no-ocsp" ];
|
||||
then
|
||||
DISABLE_OCSP="--no-ocsp"
|
||||
fi
|
||||
export DISABLE_OCSP
|
||||
|
||||
MAIN_DOMAIN=${__object_id:?}
|
||||
DOMAIN=$MAIN_DOMAIN
|
||||
if [ -f "${__object:?}/parameter/altdomains" ];
|
||||
then
|
||||
# shellcheck disable=SC2013
|
||||
for altdomain in $(cat "${__object:?}/parameter/altdomains");
|
||||
do
|
||||
DOMAIN="$DOMAIN $altdomain"
|
||||
done
|
||||
fi
|
||||
export MAIN_DOMAIN DOMAIN
|
||||
|
||||
HOOKSCRIPT=${default_hookscript}
|
||||
if [ -f "${__object:?}/parameter/hookscript" ];
|
||||
then
|
||||
HOOKSCRIPT="$(cat "${__object:?}/parameter/hookscript")"
|
||||
fi
|
||||
export HOOKSCRIPT
|
||||
|
||||
KEYTYPE="-t EC"
|
||||
if [ -f "${__object:?}/parameter/use-rsa" ];
|
||||
then
|
||||
KEYTYPE="-t RSA"
|
||||
fi
|
||||
export KEYTYPE
|
||||
|
||||
MUST_STAPLE=
|
||||
if [ -f "${__object:?}/parameter/must-staple" ];
|
||||
then
|
||||
MUST_STAPLE="--must-staple"
|
||||
fi
|
||||
export MUST_STAPLE
|
||||
|
||||
OWNER=root
|
||||
if [ -f "${__object:?}/parameter/owner" ];
|
||||
then
|
||||
OWNER="$(cat "${__object:?}/parameter/owner")"
|
||||
fi
|
||||
export OWNER
|
||||
|
||||
KEY_TARGET=
|
||||
if [ -f "${__object:?}/parameter/install-key-to" ];
|
||||
then
|
||||
KEY_TARGET="$(cat "${__object:?}/parameter/install-key-to")"
|
||||
fi
|
||||
export KEY_TARGET
|
||||
|
||||
CERT_TARGET=
|
||||
if [ -f "${__object:?}/parameter/install-cert-to" ];
|
||||
then
|
||||
CERT_TARGET="$(cat "${__object:?}/parameter/install-cert-to")"
|
||||
fi
|
||||
export CERT_TARGET
|
||||
|
||||
RENEW_HOOK=
|
||||
if [ -f "${__object:?}/parameter/renew-hook" ];
|
||||
then
|
||||
RENEW_HOOK="$(cat "${__object:?}/parameter/renew-hook")"
|
||||
fi
|
||||
export RENEW_HOOK
|
||||
|
||||
if [ -n "$KEY_TARGET" ] && [ -z "$CERT_TARGET" ]; then
|
||||
echo "You cannot specify --install-key-to without --install-cert-to." >&2
|
||||
exit 1
|
||||
elif [ -z "$KEY_TARGET" ] && [ -n "$CERT_TARGET" ]; then
|
||||
echo "You cannot specify --install-cert-to without --install-key-to." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure challengedir exist.
|
||||
__directory "$CHALLENGEDIR" --parents
|
||||
|
||||
# Generate and deploy renew script.
|
||||
mkdir -p "${__object:?}/files"
|
||||
"${__type:?}/files/renew.sh.sh" > "${__object:?}/files/uacme-renew.sh"
|
||||
|
||||
__directory "$CONFDIR/$MAIN_DOMAIN"
|
||||
require="__directory/$CONFDIR/$MAIN_DOMAIN" __file "$CONFDIR/$MAIN_DOMAIN/renew.sh" \
|
||||
--mode 0755 --source "${__object:?}/files/uacme-renew.sh"
|
||||
|
||||
# Set up renew cronjob - initial issue done in gencode-remote.
|
||||
__cron "uacme-$MAIN_DOMAIN" --user root --hour 2 --minute 0 \
|
||||
--command "$CONFDIR/$MAIN_DOMAIN/renew.sh"
|
3
type/__uacme_obtain/parameter/boolean
Normal file
3
type/__uacme_obtain/parameter/boolean
Normal file
|
@ -0,0 +1,3 @@
|
|||
no-ocsp
|
||||
must-staple
|
||||
use-rsa
|
7
type/__uacme_obtain/parameter/optional
Normal file
7
type/__uacme_obtain/parameter/optional
Normal file
|
@ -0,0 +1,7 @@
|
|||
challengedir
|
||||
confdir
|
||||
hookscript
|
||||
owner
|
||||
install-cert-to
|
||||
install-key-to
|
||||
renew-hook
|
1
type/__uacme_obtain/parameter/optional_multiple
Normal file
1
type/__uacme_obtain/parameter/optional_multiple
Normal file
|
@ -0,0 +1 @@
|
|||
altdomains
|
Loading…
Reference in a new issue