git clone git://git.garbash.com/alex/www
Log | Files | Refs | README | LICENSE

commit e7d332a40477730be99b006f59413b3a18958d5b
parent 539d947ef2d8f39cee6f0743be7ba549353f3df8
Author: alex <alex@garbash.com>
Date:   Thu, 28 Apr 2022 21:49:55 -0400

notes: Add note on a wildcard cert

MMakefile | 4+++-
Mindex.md | 2+-
Anotes/013-wildcard-cert.md | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 97 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile @@ -23,7 +23,9 @@ BUILT = index.html \ notes/011-backups.html \ notes/011-backups.txt \ notes/012-mailing-lists.html \ - notes/012-mailing-lists.txt + notes/012-mailing-lists.txt \ + notes/013-wildcard-cert.html \ + notes/013-wildcard-cert.txt build: $(BUILT) diff --git a/index.md b/index.md @@ -17,7 +17,6 @@ Game Plan --------- ### TODO: -* Wildcard cert for internal services * Start inviting people * Automate account creation * Homepage @@ -40,3 +39,4 @@ Game Plan * [Set up IRC bouncer](notes/010-irc-bouncer.html) * [Basic backup solution](notes/011-backups.html) * [Primitive Mailing Lists and Archive](notes/012-mailing-lists.html) +* [Wildcard certificate for internal services](notes/013-wildcard-cert.html) diff --git a/notes/013-wildcard-cert.md b/notes/013-wildcard-cert.md @@ -0,0 +1,93 @@ +--- +title: 013-wildcard-cert +--- + +# 013-wildcard-cert + +Thur Apr 28, 2022 + +I've been running two internal services for a while: + +* lists.garbash.com -- mailing list archive +* irc.garbash.com -- [soju](https://soju.im) IRC client + +Because we're not using split DNS (hosting our own DNS server for +clients on the VPN), these are kept internal only by having the public +DNS have the internal IP addresses: + + $ host irc.garbash.com + irc.garbash.com has address + +This works great, except it becomes harder to obtain a TLS certificate. +My favorite way to get a TLS certificate on OpenBSD is acme-client(8), +which is in base and works out of the box but does not support dns-01 +ACME challenges required for wildcard certs. As such, all sites requiring +certs need to be publicly accessible for HTTP challenges. + +It would have been OK to serve over plain HTTP (in the sense that the +services are served over a wireguard tunnel, so they're already encrypted), +but browsers only allow desktop notifications for HTTPS sites, so to get +notifications for `soju`, I needed a wildcard cert. + +The wildcard cert turned out to be not too hard. For a couple months I +used [`uacme`](https://github.com/ndilieto/uacme) because it was in ports, +but getting the client to update our DNS in Linode wasn't supported in +the upstream project (as far I can tell). So for a couple times I actually +ran the tool with manual DNS mode--updating the TXT records by hand myself. + +This clearly isn't sustainable (mostly because it requires remembering every +couple months to redo it), so I moved to [`acme.sh`](https://github.com/acmesh-official/acme.sh), +which, despite not being in ports, was super easy to install and use. + +To get the new certs, I created a new user: + + # adduser + ... acmesh, nologin, daemon, etc ... + +Then I created a `certs` group so that all the services that need the certs +can read the certificates: + + # addgroup certs + # usermod -G _soju certs + # usermod -G acmesh certs + +I had to manually `chmod` some of the directories of `acme.sh` to allow +group-writable, and `chown` those directories to `acmesh:certs`. + +Finally, installing the cert was as simple as: + + $ export LINODE_V4_API_KEY=... + $ ./acme.sh --install -m alex@garbash.com # one time + $ ./acme.sh --issue --dns dns_linode_v4 --dnssleep 300 -d *.garbash.com + +This installed the certs to `/home/acmesh/.acme.sh`. `httpd(8)` needs the +fullchain and private key: + + + server "lists.garbash.com" { + listen on * tls port 443 + directory auto index + root "/htdocs/lists" + tls { + certificate "/home/acmesh/.acme.sh/*.garbash.com/fullchain.cer" + key "/home/acmesh/.acme.sh/*.garbash.com/*.garbash.com.key" + } + location "/.well-known/acme-challenge/*" { + root "/acme" + request strip 2 + } + } + + +The final step is to modify the crontab to restart the services +when it runs successfully! Since this is running as the `acmesh` +user, I needed to give it permission to run the `rcctl` command +passwordless by adding the following to doas.conf: + + permit nopass acmesh as root cmd /usr/sbin/rcctl args restart httpd + +Adding the following to the crontab will cause it to run on success: + + -reloadcmd '/usr/sbin/rcctl restart httpd' + +Hopefully I won't need to think about this for a while!