Utilizzare letsencrypt.sh per gestire certificati SSL generici senza utilizzare un webserver
Il client standard di letsencrypt necessita di molte dipendenze e non agevole per richiedere certificati non utilizzati con webserver (Ad esempio per server SMTP o IMAP), perchè richiede che sia accessibile un webserver per verificare la richiesta del certificato.
Si può quindi utilizzare il client letsencrypt.sh, cheè un semplice file bash, che richiede solo openssl e poco altro.
Inoltre questo client supporta il challenge dns-01 che permette di autenticare le richieste facendo uso di un record TXT
Naturalmente per utilizzare questo challenge, è necessario avere accesso alla gestione del DNS, e preferibilemnte, avere la possibilità di aggiornare dei record TXT da script.
Predisposizione server DNS
Se si vuole utilizzare una procedura automatica per la richiesta ed il rinnovo, se si ha un server DNS bind, si può utilizzare nsupdate per crear eil record TXT richiesto.
Vedere Creazione di un sistema DDNS con Bind
Configurazione ambiente
- Creare uno user di sistema apposito
sudo adduser --system --force-badname letsencrypt.sh sudo usermod -d /etc/letsencrypt.sh letsencrypt.sh
- Creare le directories necessarie:
sudo mkdir -p /etc/letsencrypt.sh/{hooks,cron,config}
sudo touch /etc/letsencrypt.sh/config/dummy.sh
sudo chown -R letsencrypt.sh /etc/letsencrypt.sh
- ATTENZIONE: LA MACCHINA DA CUI SI ESEGUE LO SCRIPT DEVE AVERE ACCESSO AL DNS PRIMARIO DEL DOMINIO (PORTE TCP/UDP 53 APERT, ED AVERE ACCESSO LIBERO HTTP ED HTTP
- Se si deve utilizzare un server proxy, dichiaralo in:
sudoedit -u letsencrypt.sh /etc/letsencrypt.sh/.curlrc
proxy = proxy.example.priv:3128
Preparazione script update DNS
- Copiare la chiave generata la punto precedente
sudo cp Kletsencrypt.myhost.example.priv.+157+60414.* /etc/letsencrypt.sh/
- Creare lo script di update del recod TXT:
sudoedit /etc/letsencrypt.sh/hooks/hook-nsupdate.sh
#!/usr/bin/env bash
#
# Example how to deploy a DNS challange using nsupdate
#
. /etc/letsencrypt.sh/config
umask 077
updatefile="$(mktemp)"
NSUPDATE="nsupdate -v -k /etc/letsencrypt.sh/${DNS_KEY}"
done="no"
if [[ "$1" = "deploy_challenge" ]]; then
echo "* Writing TXT Record:"
printf "update add _acme-challenge.%s. 300 in TXT \"%s\"\n\n" "${2}" "${4}"
printf "update add _acme-challenge.%s. 300 in TXT \"%s\"\n\n" "${2}" "${4}" > "${updatefile}"
$NSUPDATE "${updatefile}"
done="yes"
#sudo rndc -k /etc/bind/rndc.key -s localhost freeze
#sudo rndc -k /etc/bind/rndc.key -s localhost thaw
#sudo /etc/init.d/bind9 reload
echo "The challenge is ${4}"
echo "The TXT record on primary DNS is:"
host -t txt _acme-challenge.${2}. ${DNS_SERVER}
#read -p "Please reload slave" P
#echo "The TXT record on secondary DNS is:"
#host -t txt _acme-challenge.${2}. dns2.rvmgroup.it
#read -p "Press any key ..." P
fi
if [[ "$1" = "clean_challenge" ]]; then
echo "* Deleting TXT Record"
printf "update delete _acme-challenge.%s. 300 in TXT \"%s\"\n\n" "${2}" "${4}" > "${updatefile}"
$NSUPDATE "${updatefile}"
#sudo rndc -k /etc/bind/rndc.key -s localhost freeze
#sudo rndc -k /etc/bind/rndc.key -s localhost thaw
#sudo /etc/init.d/bind9 reload
done="yes"
fi
if [[ "${1}" = "deploy_cert" ]]; then
# do nothing for now
done="yes"
fi
rm -f "${updatefile}"
if [[ ! "${done}" = "yes" ]]; then
echo Unkown hook "${1}"
exit 1
fi
exit 0
- Renderlo eseguibile:
sudo chmod +x /etc/letsencrypt.sh/hooks/hook-nsupdate.sh
Installazione Client letsencrypt.sh
- Installare le dipendenze:
sudo apt-get install ca-certificates git openssl curl
- Installare l'eseguibile:
cd /tmp git clone https://github.com/lukas2511/letsencrypt.sh.git sudo cp letsencrypt.sh/letsencrypt.sh /usr/local/bin/
- Modificare la configurazione:
cd /etc/letsencrypt.sh/
sudoedit config
CONFIG_D=/etc/letsencrypt.sh/config.d BASEDIR=/etc/letsencrypt.sh WELLKNOWN="/etc/letsencrypt.sh/.well-known/acme-challenge/" CONTACT_EMAIL=admin@example.com CHALLENGETYPE="dns-01" DNS_KEY="Kletsencrypt.myhost.example.priv.+157+60414.private" DNS_SERVER="dns1.example.com"
- Creare il wrapper che sarà eseguito da cron per rinnovare i certificati:
sudoedit cron/letsencrypt.cron.sh
#!/bin/bash cd /etc/letsencrypt.sh /usr/local/bin/letsencrypt.sh --cron --challenge dns-01 --hook /etc/letsencrypt.sh/hooks/hook-nsupdate.sh
- Renderlo eseguibile:
sudo chmod +x cron/letsencrypt.cron.sh
- Sistemare i diritti dei files creati:
sudo chown -R letsencrypt.sh /etc/letsencrypt.sh
Configurazione richiesta certificati
- Creare il file contenente i certificati da richiedere
cd /etc/letsencrypt.sh
sudoedit domains.txt
mail.example.com webmail.example.com
Test richiesta certificati
- ATTENZIONE: SE IL TEST FALLISCE, TENERE PRESENTE CHE LETSENCRYPT HA UN RATE LIMIT (*Rate Limits for Let's Encrypt - Documentation - Let's Encrypt Community Support)
- Testare:
sudo -u letsencrypt.sh /etc/letsencrypt.sh/cron/letsencrypt.cron.sh
- Se tutto funziona, i certificati saranno in
/etc/letsencrypt.sh/certs/mail.example.com/
- privkey.pem è la private key
- fullchain.pem è il certificato concatenato con le CA
- cert.pem è il certificato standalone
Impostazione Cron per il rinnovo automatico
- Creare il file di cron
sudoedit /etc/cron.d/letsencrypt
01 11 * * * letsencrypt.sh /etc/letsencrypt.sh/cron/letsencrypt.cron.sh > /dev/null
Dichiarazione certificati per Apache
SSLCertificateKeyFile /etc/ssl/private/mail.example.com.key SSLCertificateFile /etc/ssl/certs/mail.example.com.crt SSLCertificateChainFile /etc/ssl/certs/mail.example.com.crt
Dichiarazione certificati per Dovecot
sudoedit /etc/dovecot/conf.d/10-ssl.conf
ssl_cert = </etc/ssl/certs/mail.example.com.crt ssl_key = </etc/ssl/private/mail.example.com.key
Dichiarazione certificati per Postfix
sudoedit /etc/postfix/main.cf
smtpd_tls_cert_file=/etc/ssl/certs/mail.example.com.crt smtpd_tls_key_file=/etc/ssl/private/mail.example.com.key smtpd_tls_CAfile = /etc/ssl/certs/letsencrypt.org.pem
Script di deploy dei certificati
- Ora letsencrypt.sh provvederà rinnovare il certificato quando avrà meno di 30 giorni di validità. Dobbiamo implementare il meccanismo con cui i certificati vengono ricaricati in Apache al loro rinnovo
- I certificati dovranno essere spostati nelle relative directory sotto /etc/ssl
- Creiamo un altro script, che dovrà esere eseguito come root, che confronta i certificati in uso con quelli
sudoedit /etc/letsencrypt.sh/hooks/deploy.sh
#!/bin/bash
#
# MUST BE RUN AS ROOT
#
set -x
BASEDIR="/etc/letsencrypt.sh"
SSLDIR="/etc/ssl"
CERTS=$(/bin/ls -x ${BASEDIR}/certs/)
for CERT in $CERTS
do
# Check if CA certificate has changed
if !(diff -q ${BASEDIR}/certs/${CERT}/chain.pem ${SSLDIR}/certs/letsencrypt.org.pem > /dev/null)
then
cp -L ${BASEDIR}/certs/${CERT}/chain.pem /usr/local/share/ca-certificates/letsencrypt.org.crt
update-ca-certificates > /dev/null
fi
# Check if the certificate has changed
if !(diff -q ${BASEDIR}/certs/${CERT}/fullchain.pem ${SSLDIR}/certs/${CERT}.crt > /dev/null)
then
echo "Certificate for ${CERT} has been renewed."
cp -L "${BASEDIR}/certs/${CERT}/privkey.pem" "${SSLDIR}/private/${CERT}.key"
cp -L "${BASEDIR}/certs/${CERT}/fullchain.pem" "${SSLDIR}/certs/${CERT}.crt"
chmod 400 "${SSLDIR}/private/${CERT}.key"
chmod 644 "${SSLDIR}/certs/${CERT}.crt"
# Restart relevant services
# [[ "${jail}" = "http" ]] && jexec ${jail} service apache24 restart
#[[ "${jail}" = "mail" ]] && jexec ${jail} service smtpd restart
/etc/init.d/apache2 restart > /dev/null
/etc/init.d/postfix restart > /dev/null
/etc/init.d/dovecot restart > /dev/null
# Clean up old keys and certs
sudo -u letsencrypt.sh /usr/local/bin/letsencrypt.sh --cleanup --hook /etc/letsencrypt.sh/hooks/hook-nsupdate.sh > /dev/null
fi
done
- Renderlo eseguibile, e testarlo: non deve fare nulla:
sudo chmod a+x /etc/letsencrypt.sh/hooks/deploy.sh
sudo /etc/letsencrypt.sh/hooks/deploy.sh
- Impostarne l'esecuzione COME ROOT subito dopo il lancio di letsencrypt. Attenzione: viene usato sudo nello script:
sudoedit /etc/cron.d/letsencrypt
11 11 * * * root /etc/letsencrypt.sh/hooks/deploy.sh