Commit 16b8589d authored by ale's avatar ale

Simplify lifecycle management of public certificates

There is no need to hold on to selfsigned certs once the ACME
automation takes over: this removes the requirement for the link-based
switch mechanism we had in place. We can instead just make everything
in /etc/credentials/public a real directory, create the selfsigned
cert there if missing, and just overwrite everything periodically from
the replds@acme directory.
parent 6dd7fc72
Pipeline #4279 passed with stage
in 5 minutes and 5 seconds
#!/bin/sh
#
# Periodically check the contents of the repository
# managed by replds@acme, and replace public SSL
# certificates if they are selfsigned.
# Periodically check the contents of the repository managed by
# replds@acme, and merge it onto /etc/credentials/public.
#
public_creds_dir=/etc/credentials/public
selfsigned_dir=/etc/credentials/selfsigned
replds_dir=/var/lib/replds/acme
# Find certificates that are self-signed (i.e.
# that point to /etc/credentials/selfsigned), and
# replace them with a link to the replds@acme cert.
changed=
selfsigned=$(find ${public_creds_dir} -mindepth 1 -maxdepth 1 -lname "${selfsigned_dir}/*" -printf "%f\n")
for cn in ${selfsigned}; do
test -d ${replds_dir}/${cn} || continue
rm ${public_creds_dir}/${cn}
ln -s ${replds_dir}/${cn} ${public_creds_dir}/${cn}
changed=y
done
# To see if rsync has changed anything, we can check the output of
# rsync --stats.
rsync_files_changed=$( \
rsync --archive --copy-links --stats ${replds_dir}/ ${public_creds_dir}/ \
| awk '/Number of regular files transferred:/ {print $2}' \
)
# Find new certificates that are not yet linked.
acmecerts=$(find ${replds_dir} -mindepth 1 -maxdepth 1 -type d -printf "%f\n")
for cn in ${acmecerts}; do
test -e ${public_creds_dir}/${cn} && continue
ln -s ${replds_dir}/${cn} ${public_creds_dir}/${cn}
changed=y
done
# Restart the NGINX service if something has changed.
if [ -n "${changed}" ]; then
systemctl restart nginx
if [ "$rsync_files_changed" -gt 0 ]; then
systemctl reload nginx
fi
exit 0
......@@ -37,8 +37,8 @@ server {
server_name _;
ssl on;
ssl_certificate /etc/credentials/selfsigned/default/fullchain.pem;
ssl_certificate_key /etc/credentials/selfsigned/default/privkey.pem;
ssl_certificate /etc/credentials/public/default/fullchain.pem;
ssl_certificate_key /etc/credentials/public/default/privkey.pem;
root /var/www/html;
index index.html;
......
---
# This role simply creates a self-signed SSL certificate for initial
# service startup (which happens before the ACME automation has a
# chance to run) in /etc/credentials/public.
#
# The 'cn' parameter must be defined by the calling role.
#
# The naming scheme for the credentials follows somewhat a common
# ACME convention: the full chain of public certificates (including
# the Letsencrypt roots) is stored in 'fullchain.pem', the private
# key in 'privkey.pem'.
- stat:
path: "/etc/letsencrypt/live/{{ cn }}/cert.pem"
register: public_cert_letsencrypt_stat
- include_tasks: selfsigned.yml
when: not public_cert_letsencrypt_stat.stat.exists
# Maintain a link at /etc/credentials/public/CN that points at the right
# certificates directory, either the self-signed one or LE.
- stat:
- file:
path: "/etc/credentials/public/{{ cn }}"
follow: no
register: public_cert_stat
state: directory
- set_fact:
ssl_cert_dir: "{{ '/etc/letsencrypt/live/' if public_cert_stat.stat.exists else '/etc/credentials/selfsigned' }}/{{ cn }}"
- name: "Create a self-signed certificate for {{ cn }}"
shell: "openssl req -x509 -newkey rsa:2048 -keyout /etc/credentials/public/{{ cn }}/privkey.pem -nodes -out /etc/credentials/public/{{ cn }}/fullchain.pem -days 3650 -subj '/CN={{ cn }}'"
args:
creates: "/etc/credentials/public/{{ cn }}/fullchain.pem"
- file:
path: "/etc/credentials/public/{{ cn }}"
src: "{{ ssl_cert_dir }}"
state: link
when: not public_cert_stat.stat.exists
path: "/etc/credentials/public/{{ cn }}/privkey.pem"
owner: root
group: public-credentials
mode: 0440
---
# For public credentials, we always generate self-signed certificates
# and store them in /etc/credentials/public. These are good for
# testing, and as a fallback. In production, some sort of automation
# will manage these credentials and the services will use those
# instead.
- file:
path: "/etc/credentials/selfsigned/{{ cn }}"
state: directory
- name: "Create a self-signed certificate for {{ cn }}"
shell: "openssl req -x509 -newkey rsa:2048 -keyout /etc/credentials/selfsigned/{{ cn }}/privkey.pem -nodes -out /etc/credentials/selfsigned/{{ cn }}/fullchain.pem -days 3650 -subj '/CN={{ cn }}'"
args:
creates: "/etc/credentials/selfsigned/{{ cn }}/fullchain.pem"
- file:
path: "/etc/credentials/selfsigned/{{ cn }}/privkey.pem"
owner: root
group: public-credentials
mode: 0440
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment