TrueNAS can secure connections to its WebUI using ACME-provisioned TLS certificates. Because I don't want to expose TrueNAS to the internet, the best possible way to get a certificate is to use ACME DNS-01. Unfortunately, TrueNAS only supports Cloudflare and AWS Route 53 out of the box. For other DNS providers, a shell script can be used. I am using deSEC.io and so I needed to write a shell script. I struggled quite a bit with this because there's not really any documentation out there about how to do it.
Assuming TrueNAS tries to get a certificate for my.dns.domain
it will call the shell script with
the following parameters. To set the challenge, it calls
myscript.sh set my.dns.domain _acme-challenge.my.dns.domain <challenge>
Once the challenge is either solved or failed it removes the challenge from DNS by calling
myscript.sh unset my.dns.domain _acme-challenge.my.dns.domain <challenge>
It doesn't attempt to find the zone for you instead it gives you the full domain name (e.g. let's
say the zone in this example is dns.domain
, then TrueNAS will provide my.dns.domain
instead of
dns.domain
). That's annoying because for deSEC I need the zone. I decided to hard code the zone
into the script to avoid anything more complicated than calling curl
.
1 | #!/bin/bash
|
2 |
|
3 | set -euo pipefail
|
4 |
|
5 | TOKEN="<deSEC.io token>"
|
6 | ZONE="dns.domain"
|
7 | URL="https://desec.io/api/v1/domains/${ZONE}/rrsets"
|
8 |
|
9 | # https://desec.readthedocs.io/en/latest/dns/rrsets.html#creating-an-rrset
|
10 | add_record() {
|
11 | name=${1%%".${ZONE}"} # bash for "trim suffix"
|
12 | txtvalue=$2
|
13 | curl -s -X POST "${URL}/" \
|
14 | --header "Authorization: Token ${TOKEN}" \
|
15 | --header "Content-Type: application/json" --data @- <<EOB
|
16 | {
|
17 | "subname": "${name}",
|
18 | "type": "TXT",
|
19 | "ttl": 3600,
|
20 | "records": ["\"${txtvalue}\""]
|
21 | }
|
22 | EOB
|
23 | }
|
24 |
|
25 | # https://desec.readthedocs.io/en/latest/dns/rrsets.html#creating-an-rrset
|
26 | del_record() {
|
27 | name=${1%%".${ZONE}"}
|
28 | curl -s -X DELETE "${URL}/${name}/TXT/" \
|
29 | --header "Authorization: Token ${TOKEN}"
|
30 | }
|
31 |
|
32 | if [ "$#" -ne 4 ]; then
|
33 | echo "invalid number of parameters"
|
34 | exit 1
|
35 | fi
|
36 |
|
37 | case "${1}" in
|
38 | "set")
|
39 | add_record "${3}" "${4}"
|
40 | ;;
|
41 | "unset")
|
42 | del_record "${3}"
|
43 | ;;
|
44 | *)
|
45 | echo "unexpected commandline: ${@}"
|
46 | exit 1
|
47 | ;;
|
48 | esac |
It's not the most robust piece of software, but it does its job.