Tuesday, October 29, 2019

Secure-ish Workaround for Certbot http validation on Ubuntu

LetsEncrypt is a great tool for securing your non-production resources. I personally use it for securing my Unifi controller in AWS along with my NGINX server for my entertainment services. Certbot only has really two methods of validating the certificate renewal at the time of this writing, DNS and HTTP. DNS can be useful if you wish to update your TXT records frequently (API or manually) but clearly the more convenient is HTTP.

The problem I have with HTTP validation is, well it's HTTP and I do not want to keep an unsecured port open on my Ubuntu server perpetually. How can we keep our server secured in between certificate renewals? This posting will show you the required steps to make modifications to the systemd service for Certbot if you are using firewalld on your server.

If you are using Certbot's built-in systemd methods for renewing your certificate you've got a couple things you are in luck because systemd allows for 'ExecStartPre' and 'ExecStartPost' invocations which we can bookend around the 'ExecStart' of /lib/systemd/system/certbot.service . First we will tell systemd to add a new firewall rule to allow http to the appropriate firewall zone before we run the certbot renew command. After the renew command is finished we'll tell systemd to remove the temporary allowance. Simple right?

1) sudo vim /lib/systemd/system/certbot.service
[Service]
Type=oneshot
ExecStartPre=/usr/bin/firewall-cmd --add-service=http --zone=public ## add this line
ExecStart=/usr/bin/certbot -q renew
ExecStartPost=/usr/bin/firewall-cmd --remove-service=http --zone=public ## add this line

2) reload the daemon
sudo systemctl daemon-reload

3) profit

That's it. Those two lines in the systemd service file will open up http and then close it afterwards. You may test it out by commenting the ExecPostStart line to make sure it adds it in there, reloading the daemon, and then running the certbot.service. After you run the service you should see the public zone still has http listed as an available service
ubuntu@ubuntu-server:~$ sudo firewall-cmd --list-all --zone=public
public
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: dhcpv6-client http https ssh
  ports: 6789/tcp 32400/tcp 33400/tcp 5050/tcp 8989/tcp
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
And if you repeat the process by commenting out the ExecPreStart and allowing the ExecPostStart to execute you'll see the service is gone.

I'm looking forward to getting no more notification emails about a certificate expiring in 20 days without leaving my server exposed in the meantime. Cheers!