Files
server_proxy/certbot/files/entrypoint.sh

236 lines
6.5 KiB
Bash

#!/bin/sh
# configuration
web_root_path="/service/html"
cert_root_path="/service/ssl"
temp_path="/service/temp"
cert_bot_path="/etc/letsencrypt"
server_retries=10
log_file="" # leave empty for stdout
# variables
local_webserver="http://$(ip route show | awk '/default/ {print $3}')"
domain_file="$temp_path/domains.txt"
certs_updated="$cert_root_path/.updated"
#functions
function log()
{
local time=$(date +%F_%T)
local prefix="LOG"
case $1 in
ERR | ERROR)
prefix="ERR"
shift
;;
WAR | WARNING)
prefix="WAR"
shift
;;
esac
local func=$1; shift
# remove any \n
#local text=$(echo "$@"| tr '\n' '#' | sed 's|#|\\n |g')
case "$log_file" in
"")
echo "[$time]:[$prefix]:[$0][$func]: $@" 2>&1
;;
*)
echo "[$time]:[$prefix]:[$0][$func]: $@" >> log_path
;;
esac
}
function env_domain_file()
{
log env_domain_file $(echo "ENV DOMAINS: $DOMAINS" | tr '\n' '#' | sed 's|#|\\n |g')
echo -e "$DOMAINS" > $1
}
function verify_domain()
{
# TODO: create and verify token in web_root_path via curl
if nslookup $1 > /dev/null 2>&1; then
# domain exists
return 0
else
# false
return 1
fi
}
function read_file()
{
local func=$1
local file=$2
local result=0
while read -r line || [[ -n "$line" ]]; do
# skip empty lines if READ_EMPTY_LINES is not set
[ -z ${READ_EMPTY_LINES+x} ] && [ "${#line}" -lt 1 ] && continue
log read_file "LINE: $line"
log read_file "FUNC START [$func]"
if $func $line; then
log read_file "FUNC END [$func]"
else
result=1
log ERROR read_file "FUNC END [$func]"
fi
done < "$file"
return $result
}
function init_cert()
{
local domain=$1
local cert_path="$cert_root_path/$domain"
if [[ ! -f "$cert_path/fullchain.pem" ]]; then
log init_cert "Creating temporary cert for [$domain]"
mkdir -p "$cert_path"
openssl genrsa -out "$cert_path/privkey.pem" 4096
openssl req -new -key "$cert_path/privkey.pem" -out "$temp_path/$domain.csr" -nodes -subj \
"/C=PT/ST=World/L=World/O=${domain}/OU=temp lda/CN=${domain}/emailAddress=contact@${domain}"
openssl x509 -req -days 365 -in "$temp_path/$domain.csr" -signkey "$cert_path/privkey.pem" -out "$cert_path/fullchain.pem"
fi
}
function copy_cert()
{
local domain=$1
local cert_path="$cert_root_path/$domain"
if [[ -f "$cert_bot_path/live/$domain/privkey.pem" ]]; then
cp "$cert_bot_path/live/$domain/privkey.pem" "$cert_path/privkey.pem"
cp "$cert_bot_path/live/$domain/fullchain.pem" "$cert_path/fullchain.pem"
return 0
else
log ERROR copy_cert "No key exists at "$cert_bot_path/live/$domain/privkey.pem" for [$domain]"
return 1
fi
}
function verify_webserver()
{
wget -q -O /dev/null "$1/check/" > /dev/null 2>&1
}
function verify_local_webserver()
{
local domain=$1
# todo check if configured for domain
wget -q -O /dev/null "$local_webserver/check/" > /dev/null 2>&1
}
function get_cert()
{
local root_domain=$1
local domains=$2 # comma seperated list, first is file path
local retries=0
local webserver_exists=0
verify_local_webserver $root_domain && webserver_exists=1
while [ ! $webserver_exists -eq 1 ] && [ "$retries" -lt "$server_retries" ]; do
retries=$(( retries+1 ))
log get_cert WARNING "Webserver for [$root_domain] not reachable, trying again in 1s"
sleep 1
verify_local_webserver $root_domain && webserver_exists=1
done
if [ $webserver_exists -eq 1 ] ; then
log get_cert "Getting cert for [$root_domain] with [$domains]"
# PRODUCTION needs to be set in env
if [ -z ${PRODUCTION+x} ]; then
log WARNING get_cert "PRODUCTION not set, exiting"
return 0
fi
log get_cert "Running certbot"
certbot certonly \
--config-dir "$cert_bot_path" \
--agree-tos \
--domains "$domains" \
--email "contact@${root_domain}" \
--no-eff-email \
--expand \
--noninteractive \
--webroot \
--webroot-path "$web_root_path"
# $OPTIONS || true
else
log get_cert ERROR "Webserver for [$root_domain] not reachable after $server_retries retries"
return 1
fi
}
function domain_init()
{
if [ "$1" == "" ]; then
log domain_init "Skipping empty input"
return 0
fi
local domain=$1;
# don't really care at this point if the domain exists
# if ! verify_domain $domain; then
# log ERROR domain_init "Root domain [$domain] does not exist"
# return 1
# fi
init_cert $domain
}
function domain_handler()
{
if [ "$1" == "" ]; then
log domain_handler "Skipping empty input"
return 0
fi
local domain=$1; shift
local subs=$@
local domain_string="$domain"
log domain_handler "Checking root domain [$domain]"
if ! verify_domain $domain; then
log ERROR domain_handler "Root domain [$domain] does not exist"
return 1
fi
for sub in $subs ; do
local subdomain="$sub.$domain"
log domain_handler "Checking sub domain [$subdomain]"
if ! verify_domain $subdomain; then
log WARNING domain_handler "Sub domain [$subdomain] does not exist"
else
domain_string="$domain_string,$subdomain"
fi
done
init_cert $domain
if ! get_cert $domain $domain_string; then
log ERROR domain_handler "No cert generated by certbot for [$domain]"
return 1
fi
copy_cert $domain
}
function main()
{
intervall="${1-12h}"
while :; do
log main "Starting intervall"
# load env variable with domains
env_domain_file "$domain_file"
# create temp certs for domains if none exists
# nginx need certs to start
read_file domain_init "$domain_file"
# get or renew domain certs
# requires nginx to be started
# timout is set via $server_retries (default 10s)
read_file domain_handler "$domain_file"
# indicated that certs have been updated to nginx
touch "$certs_updated"
log main "Ending intervall"
log main "Next interval in $intervall"
sleep "$intervall"
done
}
main $@