Handling TLS certs on Fedora IoT with acme.sh
If you're running Fedora IoT (or Fedora CoreOS outside of Kubenetes) then you'll need to run your ACME client within a container if you want free auto-updating TLS certificates.
One option for doing this is acme.sh. It wasn't obvious to me how this was expected to work, hence these notes. My primary resources were:
- acme.sh wiki page on using it within Docker
- Podman docs
Note that I perform all of the following as the root user (see Shortcomings of Rootless Podman), because one of my uses for the certs is nginx bound to port 443.
Firstly we'll need to create a volume that acme.sh can write to and any certificate-consuming applications can read from:
podman volume create acme-certs
…then we can run acme.sh and point it at our volume (the
:z option when specifying the volume applies an SELinux label denoting shared content):
# Only needed for the first run: podman run --rm -it -v acme-certs:/acme.sh:z \ docker.io/neilpang/acme.sh --register-account -m firstname.lastname@example.org
Once the initial registration is done you should be able to issue certs:
podman run --rm -it -v acme-certs:/acme.sh:z \ -e GANDI_LIVEDNS_KEY=api-key-gibberish \ docker.io/neilpang/acme.sh \ --issue --dns dns_gandi_livedns -d host.example.com
In this example I'm using Gandi LiveDNS for verification, the acme.sh DNS API supports many providers so probably yours is in there.
Assuming the certificate issue operation succeeds you will see output like this:
Your cert is in: /acme.sh/host.example.com/host.example.com.cer Your cert key is in: /acme.sh/host.example.com/host.example.com.key The intermediate CA cert is in: /acme.sh/host.example.com/ca.cer And the full chain certs is there: /acme.sh/host.example.com/fullchain.cer
Take note of the names/paths as you'll need them when configuring whichever consuming applications you'll use.
Now all that's left is to automate certificate renewal. I've done this with a systemd timer because everything in Fedora IoT is unit files already, but it works just as well via cron.
cat <<EOF > /etc/systemd/system/acme-certs.service [Unit] Description=Renew TLS certificates via acme.sh After=network.target [Service] Type=simple ExecStart=podman run --rm -it -v acme-certs:/acme.sh:z \ -e GANDI_LIVEDNS_KEY=api-key-gibberish \ docker.io/neilpang/acme.sh --cron EOF cat <<EOF > /etc/systemd/system/acme-certs.timer [Unit] Description=Check and renew TLS certificates daily [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=timers.target EOF systemctl daemon-reload # test manually systemctl start acme-certs.service journalctl --unit acme-certs.service # enable the timer systemctl enable acme-certs.timer systemctl start acme-certs.timer systemctl status acme-certs.timer acme-certs.service