initial commit

This commit is contained in:
Matthew Saunders Brown 2021-03-27 16:15:03 -07:00
commit e903be8aed
7 changed files with 297 additions and 0 deletions

4
README.md Normal file
View File

@ -0,0 +1,4 @@
# letsencrypt-tools
etc/letsencrypt/cli.ini
email = hostmaster@example.com

View File

@ -0,0 +1,90 @@
#!/bin/bash
# must be root
if [ "$USER" != "root" ]; then
exec sudo $0
fi
help()
{
thisfilename=$(basename -- "$0")
echo "$thisfilename"
echo "Create a Let's Encrypt certificate."
echo ""
echo "Usage: $thisfilename domain [OPTIONS]"
echo ""
echo " -h Print this help."
echo " -n Dry Run - don't create cert, just echo command to run."
exit
}
# check for and set domain
if [ -n "$1" ]; then
if [ $1 == "-h" ]; then
help
else
domain=$1
shift
# basic but good enough domain name regex validation
if [[ ! $domain =~ ^(([a-zA-Z](-?[a-zA-Z0-9])*)\.)+[a-zA-Z]{2,}$ ]] ; then
echo "ERROR: Invalid domain name: $1"
exit 1
fi
fi
else
help
fi
# set any options that were passed
while getopts "hn" opt; do
case "${opt}" in
h )
help
exit;;
n )
dryrun=true
;;
\? )
echo "Invalid option: $OPTARG" 1>&2
exit;;
: )
echo "Invalid option: $OPTARG requires an argument" 1>&2
exit;;
esac
done
# set vars
command="certbot certonly --cert-name $domain"
dnscheck=false
ips=(`ip -4 -o addr show | awk '{ print $4 }' | cut -d / -f 1`)
# check dns for domain
dns=`host -t A $domain|grep 'has address'|awk '{ print $4 }'`
if [[ " ${ips[@]} " =~ " ${dns} " ]]; then
command="$command -d $domain"
dnscheck=true
fi
# check dns for www subdomain
dns=`host -t A www.$domain|grep 'has address'|awk '{ print $4 }'`
if [[ " ${ips[@]} " =~ " ${dns} " ]]; then
command="$command -d www.$domain"
dnscheck=true
fi
# copy above www subdomain section and modify as desired to
# automatically check for and add additional subdomains to cert
# check if any of the dns lookups passed
if [[ "$dnscheck" = "false" ]]; then
echo "All dns checks failed, can't create cert."
exit 1
fi
# run (or display) command
if [[ "$dryrun" = "true" ]]; then
echo "Run this command to create cert:"
echo "$command"
else
$command
fi

80
bin/letsencrypt-del.sh Normal file
View File

@ -0,0 +1,80 @@
#!/bin/bash
help()
{
thisfilename=$(basename -- "$0")
echo "Delete an existing Let's Encrypt certificate."
echo ""
echo "Usage: $thisfilename cert-name(domain) [OPTIONS]"
echo ""
echo " -h Print this help."
echo " -r Revoke cert from Let's Encrypt before deleting files."
exit
}
# check for and set domain
if [ -n "$1" ]; then
if [ $1 == "-h" ]; then
help
else
domain=$1
shift
# basic but good enough domain name regex validation
if [[ ! $domain =~ ^(([a-zA-Z](-?[a-zA-Z0-9])*)\.)+[a-zA-Z]{2,}$ ]] ; then
echo "ERROR: Invalid domain name: $1"
exit 1
fi
fi
else
help
fi
# set any options that were passed
while getopts "hr" opt; do
case "${opt}" in
h )
help
exit;;
r )
revoke=true
;;
\? )
echo "Invalid option: $OPTARG" 1>&2
exit;;
: )
echo "Invalid option: $OPTARG requires an argument" 1>&2
exit;;
esac
done
# start by checking if the renewal config exits
if test -f "/etc/letsencrypt/renewal/$domain.conf"; then
if [[ "$revoke" = "true" ]]; then
certbot revoke --cert-path /etc/letsencrypt/live/$domain/fullchain.pem
fi
if test -f "/etc/letsencrypt/renewal/$domain.conf"; then
rm "/etc/letsencrypt/renewal/$domain.conf"
fi
if test -d "/etc/letsencrypt/live/$domain"; then
rm -r "/etc/letsencrypt/live/$domain"
fi
if test -d "/etc/letsencrypt/archive/$domain"; then
rm -r "/etc/letsencrypt/archive/$domain"
fi
if test -f "/etc/ssl/letsencrypt/$domain.pem"; then
rm "/etc/ssl/letsencrypt/$domain.pem";
fi
if test -h "/etc/ssl/letsencrypt/mail.$domain.pem"; then
rm "/etc/ssl/letsencrypt/mail.$domain.pem";
fi
else
echo "Did not find cert for $domain."
fi

View File

@ -0,0 +1,4 @@
# ACME (Automatic Certificate Management Environment)
<Location "/.well-known/acme-challenge/">
ProxyPass "http://127.0.0.1:18080/.well-known/acme-challenge/"
</Location>

11
etc/letsencrypt/cli.ini Normal file
View File

@ -0,0 +1,11 @@
# Because we are using logrotate for greater flexibility, disable the
# internal certbot logrotation.
max-log-backups = 0
email = hostmaster@example.com
agree-tos = True
allow-subset-of-names = True
expand = True
keep-until-expiring = True
non-interactive = True
standalone = True
http-01-port=18080

View File

@ -0,0 +1,33 @@
#!/bin/bash
# script is run once per domain after successful renewal with these vars available:
# $RENEWED_LINEAGE=/etc/letsencrypt/live/example.com
# $RENEWED_DOMAINS="example.com www.example.com"
# makes sure vars were passed and LE cert exits
if [ ! -n "$RENEWED_LINEAGE" ]; then
exit 1
fi
if [ ! -f "$RENEWED_LINEAGE/fullchain.pem" ]; then
exit 1
fi
if [ ! -d "/etc/ssl/letsencrypt" ]; then
install --owner=root --group=ssl-cert --mode=750 --directory /etc/ssl/letsencrypt
fi
DOMAIN=`basename $RENEWED_LINEAGE`
PEM="/etc/ssl/letsencrypt/$DOMAIN.pem"
# If the file doesn't already exist first create empty file with correct ownership and
# permissions. Thus the copied cert is *never* world readable, not even for an instant.
if [ ! -f "$PEM" ]; then
install --owner=root --group=ssl-cert --mode=640 /dev/null $PEM
fi
cat $RENEWED_LINEAGE/fullchain.pem > $PEM
cat $RENEWED_LINEAGE/privkey.pem >> $PEM
# set perms & ownership again just for good measure, should be redundant
chmod 640 $PEM
chown root:ssl-cert $PEM

View File

@ -0,0 +1,75 @@
#!/bin/bash
# sync-certs-to-etc-ssl.sh
#
# Takes all Let's Encrypt certs & keys and concats them in
# to pem files for use by apache, dovecot, exim, haproxy, etc.
#
# Install this script in to /etc/letsencrypt/renewal-hooks/post/
# to have it run automatically after attempting to obtain/renew certificates.
#
# Alternatively you can put the script in a different location and then
# run sync-certs-to-etc-ssl.sh manually after creating or renewing certs,
# or specificy the path to the script with the --post-hook cerbot command option
# to have it automatically run when attempting to obtain/renew certificates.
# make dir if it doesn't already exist
if [[ ! -e /etc/ssl/letsencrypt/ ]]; then
install --owner=root --group=ssl-cert --mode=750 --directory /etc/ssl/letsencrypt
fi
# check that Let's Encrpyt archive dir exists before proceeding
if [ ! -d "/etc/letsencrypt/archive" ]; then
exit
fi
# Get list of Let's Encrpyt certs
# Check the "archive" dir instead of "live" as "live"
# has a README file that we don't want in our array.
cd /etc/letsencrypt/archive/
lecerts=(*)
# get list of certs in the SSL dir
cd /etc/ssl/letsencrypt/
sslcerts=(*)
# First cycle thru /etc/ssl/letsencrypt/ and remove any pem
# files that don't have a cert in /etc/ssl/letsencrypt/
# (removes certs that have been deleted from letsencrypt).
for sslcert in "${!sslcerts[@]}"
do
# set cert variable
cert=${sslcerts[$sslcert]}
# remove .pem from end of $cert
cert=$(basename $cert .pem)
if [[ ! " ${lecerts[@]} " =~ " $cert " ]]; then
rm /etc/ssl/letsencrypt/${sslcerts[$sslcert]}
fi
done
# add / update pem files in /etc/ssl/letsencrypt/
for lecert in "${!lecerts[@]}"
do
# set cert variable
cert=${lecerts[$lecert]}
if [ -f "/etc/ssl/letsencrypt/$cert.pem" ]; then
# /etc/ssl/letsencrypt/ pem file already exists
# get modified times and only upate if newer
LECERTTIME=`date +%s -r /etc/letsencrypt/live/$cert/fullchain.pem`
SSLCERTTIME=`date +%s -r /etc/ssl/letsencrypt/$cert.pem`
if [[ $LECERTTIME -gt $SSLCERTTIME ]]; then
# make sure perms are correct, should be redundant
chmod 640 /etc/ssl/letsencrypt/$cert.pem
chown root:ssl-cert /etc/ssl/letsencrypt/$cert.pem
# replace existing cert with new data
cat /etc/letsencrypt/live/$cert/fullchain.pem > /etc/ssl/letsencrypt/$cert.pem
cat /etc/letsencrypt/live/$cert/privkey.pem >> /etc/ssl/letsencrypt/$cert.pem
fi
else
# /etc/ssl/letsencrypt/ pem file does not exists. First create
# empty file with correct ownership and permissions. Thus the
# copied cert is *never* world readable, not even for an instant.
install --owner=root --group=ssl-cert --mode=640 /dev/null /etc/ssl/letsencrypt/$cert.pem
cat /etc/letsencrypt/live/$cert/fullchain.pem > /etc/ssl/letsencrypt/$cert.pem
cat /etc/letsencrypt/live/$cert/privkey.pem >> /etc/ssl/letsencrypt/$cert.pem
fi
done