SwordArMor

Script de regénération d’un certificat let’s encrypt à la création d’un site sur wordpress

Dans le cadre de gozmail, nous proposons également l’hébergement de blogs pour nos adhérents. Nous utilisons wordpress car il dispose d’une fonctionnalité qui permet de créer un réseau de sites. Ainsi, chaque adhérent dispose de sonsite.log.bzh et ne peut pas aller fouiner chez son voisin.

Au bout d’un moment, nous nous sommes dit que ça serait pas mal d’avoir du SSL. Premièrement parce que ça évite d’envoyer son mot de passe en clair, deuxièmement parce que le chiffrement devient de plus en plus nécessaire dans notre monde actuel. Comme l’asso n’a pas spécialement envie de payer un certificat global *.log.bzh, nous avons décidé d’utiliser let’s encrypt et de mettre chaque nom de domaine dans le certificat. Jusqu’à présent il s’agissait d’un cron qui tournait tous les jours et redemandait un certificat si un nouveau site a été créé. En soit ça ne marche pas si mal, mais tout nouveau site se retrouve avec un mauvais certificat le premier jour, on peut faire mieux.
Il faut donc régénérer le certificat au moment de la création du compte. Pour ça nous pouvions soit utiliser les hooks de wordpress (et donc se taper du code en PHP, et personne n’a envie de faire du PHP), soit écrire un petit wrapper shell qui crée un compte wordpress en se basant sur wp-cli puis lance la tambouille let’s encrypt avec acme-tiny.
Le script que je vous propose ici part donc du principe que ces deux projets sont utilisables sur la machine depuis laquelle vous le lancez. Les chemins sont spécifiques à log.bzh, vous devrez donc les modifier en fonction de vos besoins. Il faudra également modifier les variables $DBUSER, $DBPASS et $DBNAME.

#!/bin/sh

usage() {
cat <<EOF
Usage of $0:
	-h, --help	Print this help
	-u, --user	User name
			Create a site \$user.log.bzh
	-e, --email	User’s mail
EOF
}

die() {
	echo "$@" >&2
	exit 1
}

nargs=$(($#/2))

OPTS=$(getopt -o u:,e:,h -l user:,email:,help -- "$@") || die

if [ $# -eq 0 ]; then
        >&2 usage
        exit 1
fi

eval set -- "$OPTS"

while :; do
	case "$1" in
		-h | --help)	usage;
				exit 0;;
		-u | --user)	USER="$2";
				shift 2;;
		-e | --email)	EMAIL="$2";
				shift 2;;
		--) shift; break;;
	esac
done

PASSWORD="$(head -c 12 /dev/urandom | base64)"

if [ $nargs -ne 2 ]; then
	>&2 printf "Error, username or email not specified\n"
	>&2 usage
	exit 1
fi

cd /var/www/html/log.bzh

su www-data -s /bin/sh -c "wp site create --slug=$USER --email=$EMAIL" || die "Error while creating site"
su www-data -s /bin/sh -c "wp user update $USER --user_pass=$PASSWORD" || die "Error while setting password"

cd $OLDPWD

DBUSER="coucou"
DBPASS="je"
DBNAME="teste"

# Very ugly code here.
# Just for memory, because insane ;)
#openssl req -nodes -sha256 -newkey rsa:4096 \
# -keyout /etc/ssl/nginx/blogs.log.bzh.key \
# -out /etc/ssl/nginx/blogs.log.bzh.csr -subj "/" -reqexts SAN \
# -config <(cat /etc/ssl/blogs.cnf \
#  <(printf '[SAN]\nsubjectAltName=DNS:log.bzh,DNS:www.log.bzh,'; \
#  while read fqdn; do printf "DNS:${fqdn},"; done < \
#   <(echo 'SELECT domain FROM wp_blogs;' | mysql -u $DBUSER -p$DBPASS $DBNAME \
#    | sed -e '1d' | grep -v "^log\.bzh$") | sed 's/,$//'; printf '\n'))

# A bit less ugly
(	printf '[SAN]\nsubjectAltName=DNS:log.bzh,DNS:www.log.bzh,'; \
	echo 'SELECT domain FROM wp_blogs;' | \
	mysql -u $DBUSER -p$DBPASS $DBNAME | \
	sed -e '1d' | \
	grep -v '^log\.bzh$' | \
	while read fqdn; do \
		printf "DNS:${fqdn},"; \
	done | \
	sed 's/,$//'; printf '\n') | \
cat /etc/ssl/blogs.cnf - | \
openssl req \
	-nodes \
	-sha256 \
	-newkey rsa:4096 \
	-keyout /etc/ssl/nginx/blogs.log.bzh.key \
	-out /etc/ssl/nginx/blogs.log.bzh.csr \
	-subj "/" \
	-reqexts SAN \
	-config /dev/stdin \
|| die "Error while getting site list"

acme_tiny.py --account-key /usr/local/var/lib/sslle/account.key \
 --csr /etc/ssl/nginx/blogs.log.bzh.csr --acme-dir /var/www/le-challenges/ > \
 /etc/ssl/nginx/blogs.log.bzh.crt || die "Error while signing certificate"

cat /etc/ssl/nginx/blogs.log.bzh.crt \
 /etc/ssl/certs/lets-encrypt-x3-cross-signed.pem > \
 /etc/ssl/nginx/blogs.log.bzh-chained.crt || die "Error while chaining certificate"

service nginx reload || die "Error while reloading nginx"

SUBJECT=$(perl -wse "use utf8; use Encode qw(encode); print encode(\"MIME-Q\",\
 \"Votre site https://${USER}.log.bzh vient d’être créé\");")

echo "From: Admins log.bzh <log@gozmail.bzh>
To: $EMAIL
Cc: Admins log.bzh <log@gozmail.bzh>
Content-Type: text/plain; charset=UTF-8
Subject: $SUBJECT

Bonjour,
Votre site vient d’être créé. Son adresse est https://${USER}.log.bzh
Pour vous connecter, rendez-vous sur https://${USER}.log.bzh/wp-admin/

Votre identifiant est $USER
Votre mot de passe est $PASSWORD

Cordialement,
--
Les admins de log.bzh" | /usr/sbin/sendmail -f log@gozmail.bzh -t


exit 0

# À la base je voulais la faire simple, j’ai glissé chef.