summaryrefslogtreecommitdiff
path: root/config-parabola-mgmt-certbot.PKGBUILD
diff options
context:
space:
mode:
Diffstat (limited to 'config-parabola-mgmt-certbot.PKGBUILD')
-rw-r--r--config-parabola-mgmt-certbot.PKGBUILD239
1 files changed, 239 insertions, 0 deletions
diff --git a/config-parabola-mgmt-certbot.PKGBUILD b/config-parabola-mgmt-certbot.PKGBUILD
new file mode 100644
index 0000000..0573889
--- /dev/null
+++ b/config-parabola-mgmt-certbot.PKGBUILD
@@ -0,0 +1,239 @@
+. ${BUILDFILE%/*}/common.sh
+pkgver=20180826
+
+package() {
+preamble
+# #### SSL
+
+# Use the [certbot][] ACME client to get certificates from
+# [Let's Encrypt][].
+#
+# [certbot]: https://www.parabola.nu/packages/community/any/certbot/
+# [Let's Encrypt]: https://letsencrypt.org/
+
+depends+=(certbot dialog)
+
+# All domains handled by the server are shoved in as Subject
+# Alternative Names in a single certificate. This makes configuring
+# nginx easier.
+
+# ##### keys user and group
+
+# Files affected manually:
+#
+# * `/etc/passwd`
+# * `/etc/shadow`
+# * `/etc/group`
+# * `/etc/gshadow`
+# * `/etc/letsencrypt`
+# * `/var/lib/letsencrypt`
+# * `/var/log/letsencrypt`
+#
+# In order to run certbot as a non-root user, the keys user and group
+# have been created:
+#
+# useradd --system --user-group --no-create-home --home-dir /etc/ssl --shell /usr/bin/nologin keys
+# chown -R keys:keys /etc/letsencrypt /var/log/letsencrypt /var/lib/letsencrypt
+# chmod 750 /etc/letsencrypt/archive /etc/letsencrypt/live
+#
+# The associated keys group allows users to read the (private) keys in
+# /etc/letsencrypt/live.
+
+# ##### issuance, renewal, and installation
+
+# Unlike acmetool, certbot doesn't have an easy way of saying "please
+# add this domain as a Subject Alternative Name". You have to re-run
+# the same (long) command to get the cert, but with the domain added.
+# So, I've encapsulated this into the script
+# `/etc/ssl/misc/certbot-get`. Edit `/etc/ssl/misc/certbot-get.d/` to
+# manipulate the list of domains, then run the script.
+install -d etc/ssl/misc/certbot-get.d
+add-file -m755 etc/ssl/misc/certbot-get <<<'#!/bin/bash
+{
+ confdir="$(readlink -f -- "$0.d")"
+ set -eu
+ cd /
+
+ # The first name listed should be the canonical host name
+ domains=(
+ $(hostname -f)
+ $(find -L "$confdir" -type f -executable -exec {} \;)
+ )
+
+ if [[ "`whoami`" != '\''keys'\'' ]]; then
+ >&2 printf '\''%q: This script must be run as user `%s'\''\'\'''\''\n'\'' "$0" keys
+ exit 1
+ fi
+
+ msg=(
+
+ Our "\`${0##*/}\`" script is used to '\''*add*'\'' or
+ '\''*remove*'\'' certificates\; use '\''`certbot renew`'\'' to
+ renew them. To use "${0##*/}," edit "\`${0##*/}.d/\`" to
+ manipulate the list of domains, '\''then'\'' run it to get a
+ new certificate with a new Subject Alternative Name field
+ matching the new list of domains.
+
+ $'\''\n\n'\''Are you sure that you are ready to run this?
+ It will eat into the "Let'\''s Encrypt" usage limit.
+
+ )
+
+ dialog --yesno "${msg[*]}" '\'''\'' '\'''\'' || { echo; exit 0; }
+
+ cmd=(
+ certbot certonly
+ --cert-name "${domains[0]}"
+ --email "`whoami`@${domains[0]}"
+ --webroot -w /var/lib/letsencrypt
+ )
+
+ for domain in "${domains[@]}"; do
+ cmd+=(-d "$domain")
+ done
+
+ umask 0027
+ "${cmd[@]}"
+ sudo /etc/ssl/misc/certbot-hook
+}'
+
+# Renewal, however, is very simple. It is handled by
+# `certbot-renew.service` (triggered by the associated `.timer`). It
+# runs `certbot renew` with a couple of flags.
+add-file etc/systemd/system/certbot-renew.timer <<EOF
+[Unit]
+Description=Daily renewal of Let's Encrypt's certificates
+
+[Timer]
+OnCalendar=daily
+Persistent=true
+
+[Install]
+WantedBy=timers.target
+EOF
+add-file etc/systemd/system/certbot-renew.service <<EOF
+[Unit]
+Description=Let's Encrypt certificate renewal
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/certbot renew --quiet --renew-hook 'sudo /etc/ssl/misc/certbot-hook'
+
+User=keys
+UMask=0027
+EOF
+add-unit etc/systemd/system/timers.target.wants/certbot-renew.timer
+
+# Both `certbot-get` and `certbot-renew.service` prove ownership of
+# the domain via the `http-01` challenge. `/etc/nginx/nginx.conf`
+# includes `/etc/nginx/snippets/ssl.conf`, which has a `server{}`
+# block that handles ACME http-01 challenges.
+
+# Both `certbot-get` and `certbot-renew.service` have been written to
+# run `sudo /etc/ssl/misc/certbot-hook` after certificates have been
+# updated, and `sudo` has been configured to allow the keys user to do
+# this without a password. Right now `certbot-hook` just runs
+# `systemctl reload nginx.service`.
+add-file -m755 etc/ssl/misc/certbot-hook <<EOF
+#!/bin/bash
+systemctl reload nginx.service
+EOF
+install -dm750 etc/sudoers.d
+add-file etc/sudoers.d/10-certbot <<EOF
+keys ALL=(ALL) NOPASSWD: /etc/ssl/misc/certbot-hook
+EOF
+
+# ##### other
+
+# Files affected manually:
+#
+# * `/etc/nginx/nginx.conf`
+# * `/etc/ssl/private/dhparam-2048.pem`
+
+# `nginx.conf` includes `snippets/ssl.conf`, which is primarily based
+# on the output of [Mozilla Security's recommended web server
+# configuration generator][0]. It has had the main SSL information
+# promoted to be directly into the `http{}` block, instead of having
+# to be in each `server{}` block. The HTTP->HTTPS redirector has had
+# an exception added to it to have it respond to ACME http-01
+# challenges.
+#
+# [0]: https://mozilla.github.io/server-side-tls/ssl-config-generator/
+add-file etc/nginx/snippets/ssl.conf <<EOF
+# -*- Mode: nginx; nginx-indent-level: 8; indent-tabs-mode: t -*-
+
+# This is based on Mozilla Security's recommended web server
+# configuration generator[1]:
+# Generated date: 2016-06-28
+# Server: Nginx
+# Clients: Intermediate
+# Server Version: 1.10.1
+# OpenSSL Version: 1.0.2h
+# HSTS Enabled: yes
+#
+# [1]: https://mozilla.github.io/server-side-tls/ssl-config-generator/
+#
+# Obviously, all of the '/path/to/' paths have been filled in. The
+# 'resolver' line has been commented out. The SSL information has
+# been promoted to be in the http{} block directly, instead of having
+# to be in each server{} block. The HTTP->HTTPS redirector has had
+# ACME support added.
+
+# Redirect everything on port 80 to HTTPS
+server {
+ listen 80 default_server;
+ listen [::]:80 default_server;
+ server_name _;
+
+ # Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response.
+ location / { return 301 https://\$host\$request_uri; }
+
+ # Except for ACME http-01 validations
+ location /.well-known/acme-challenge {
+ root /var/lib/letsencrypt;
+ default_type "text/plain";
+ }
+}
+
+# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
+ssl_certificate /etc/ssl/private/myhostname/fullchain.pem;
+ssl_certificate_key /etc/ssl/private/myhostname/privkey.pem;
+ssl_session_timeout 1d;
+ssl_session_cache shared:SSL:50m;
+ssl_session_tickets off;
+
+# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
+ssl_dhparam /etc/ssl/private/dhparam-2048.pem;
+
+# intermediate configuration. tweak to your needs.
+ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
+ssl_prefer_server_ciphers on;
+
+# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
+add_header Strict-Transport-Security max-age=15768000;
+
+# OCSP Stapling ---
+# fetch OCSP records from URL in ssl_certificate and cache them
+ssl_stapling on;
+ssl_stapling_verify on;
+
+## verify chain of trust of OCSP response using Root CA and Intermediate certs
+#ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;
+
+#resolver <IP DNS resolver>;
+EOF
+
+# Because certbot is only configured to use http-01 challenges, the
+# all challenges happen over pain HTTP, which means that the
+# configurations for each subdomain (which only serve over
+# HTTPS/HTTP2) do not need to include anything about ACME or SSL
+# (other than mentioning `ssl` in the `listen` directive).
+
+# `ssl.conf` needs to refer to a dhparam PEM file. This has been
+# generated with the command
+#
+# openssl dhparam -out /etc/ssl/private/dhparam-2048.pem 2048
+
+postamble
+}