. ${BUILDFILE%/*}/common.sh pkgver=20180910 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 sudo) # 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 <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 <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 ; 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 }