Let's Encrypt with Fortigate
Updated: a day ago
Update Feb 7, 2020: I had missed something in the original script and have updated it to update the certificate gracefully. I initially over complicated the fix, then I realized the fix was simple. I updated the config file to append the date to the cert name.
Update May 27, 2020: Updated the links for the script and files.
SSL certs, the bane of many SysAdmin, Network Admin, and anyone else who works in IT’s existence. SSL certs cost money and expire regularly. In my experience with multiple IT departments, it has always taken more effort than I felt was needed to keep these updated and deployed correctly. Forget to renew a cert, and you’ll get untrusted errors until the cows come home, and some applications stop working altogether. Deploy a cert incorrectly, whether you’re missing an intermediate, or need to put the intermediate in the same file as the cert, it’s always a guessing game.
Let’s Encrypt (LE) came along and solved one of the problems associated with SSL/TLS certs, the cost. Now you can get encryption certificates for free but there is a catch, they expire every 90 days. For most platforms LE is used on, this isn’t an issue, you just create a cron job (scheduled task) and run a renewal script every 89 days or so to avoid expiration. As Certbot – the most common ACME client used with LE – has integrations with Apache, Nginx, and many other web server platforms this isn’t an issue. With network devices this is a totally different story, while many routers/switches/firewalls are built on some flavor of *nix, they’re generally locked down, and don’t really support customizing much of the base OS – sure there are exceptions to this, but those are out of scope for this write-up.
Fortigate/FortiOS, like many security products is too based on some flavor of *nix – I have no idea which, but suffice it to say it is – but is locked down pretty tight, and much of the CLI that runs is FortiOS and there really isn’t any direct Linux Shell access from the CLI. FortiOS however, does have a pretty well developed API and it shows, because the Fortigate web interface leverages that API. Since remembering to renew/upload certs once a year can be cumbersome, remembering to do so every 80-90 days is probably out of the question for most folks, hence why organizations spend on 3-5 year certs.
In this article, we’ll go through installing LE certs via the CLI, and automating the renewal.
You have deployed Linux VM with Python 3 support – with root/sudo access
Certbot is installed on the Linux VM – and certs have been requested already
A REST API Admin has already been created on the Fortigate
Preparing the Linux VM
One of the first things you’ll need to do with the Linux VM is installing the intermediate cert that is provided as part of the cert you requested. In this post, I am running CentOS 7 and this is what I needed to do:
bash# cp /etc/letsencrypt/live/<domain_name>/chain.pem
This will prevent the LE cert from being seen as untrusted. When running the python script, you’ll still see that an unverified HTTP request was made, that’s due to the nature of the configuration set to bypass cert verification for the first run since the factory cert is untrusted.
The Updater Script:
The ssl updater script was written in python 3.6 so if you’re running Python 2 and 3 side by side, you’ll need to call out Python 3. It has two components, the config file, and the executable script.
The config file has a number of changeable parameters so that you can implement this in your environment – I know my Python skills are basic, but I did my best to make it readable and easy to follow, I am open to suggestions.
The main script should not be edited unless you know what you’re doing, if there are improvements to be made, I’d appreciate if you shared them with me as well. I am a network engineer by trade and not a programmer, so I’m sure there will be plenty of room for improvement.
The Renewal script
The renewal script is a bash script that does two things, runs the certbot renewal, and if it detects that the cert has been updated, it will launch the python script to install the new certs on your fortigate(s). This is what we will be adding to cron for scheduling.
Running the Updater and installer script
This is to demonstrate how the updater works. You typically won’t need to run this yourself, as the renewal shell script will do that for you.
Running the renewal script
This will demonstrate how the renewal script works, again you shouldn’t need to run this manually since we’ll be scheduling this in cron.
Scheduling in Cron
Since Cron works on a time hierarchy, we’ll schedule the checker to run once a month, once a cert is within 30 days of expiry, it will be renewed by certbot. On Centos 7 this is as easy as placing our renewal script in the /etc/cron.monthly/ directory.
Let's Encrypt is pretty awesome, but just like everything in the Open Source world, requires a bit more elbow grease and some shell scripting to make work with non-native platforms. That being said, where's there's an API there's a way!
Thank you for reading, I hope this was helpful.