• Matt Sherif

Follow up: Let's Encrypt with FortiGate - Now with VDOMs!!!

It's been well over a year since I wrote the original "Let's Encrypt with FortiGate", and while my mediocre python code proved popular, many others have gone on to implement it in their environment. I'll say it again, I am not a coder, I am just a guy who thought it would be neat to automate this, and I would be very interested to see your implementations.

This article is a result of Hendrik reaching out to me. Hendrik essentially outlined the problem for me:

"Let's Encrypt with FortiGate works well on my non-VDOM FGTs, however on multi-VDOM setups, then I get a 403 error when setting the admin-server-cert parameter.".

Well Hendrik, thanks to you I decided to lab this up.


  • You have access to FNDN - If not get in touch with your account team to get access. This is not required to do what we're doing in this article, but it provides access to the FortiOS API, which can be very handy

  • FortiGate is running 6.2.x or above - this will probably work on 6.0.x (as the endpoint is the same) but has not been tested

  • You've already created an admin profile for your REST user

  • For this Scenario I used Postman to test the JSON/API calls, it's just cleaner when I need to understand what the JSON/URL need to look like

Ok, with the boring stuff out of the way, let's get to it!

To replicate Hendrik's issue we will be using this API endpoint:


So your request URL should look something like this:


The JSON we're using is very simple:

    "admin-server-cert": "cert_name"

Don't forget to set your method to 'PUT' which essentially means "Update this resource with the following - JSON - Values". I am sure there's a better explanation, but you're getting front row seats to my mind.

The request receives the following response:

"http_method": "PUT",
"status": "error",
"http_status": 403,
"vdom": "uv-office",
"path": "system",
"name": "global",
"serial": "FGXXXXXXXXXXX",
"version": "v6.4.3",
"build": 1778

Well shoot. I should be getting something with a "success" status and a code 200.

Time to take a deeper look, after doing some digging and discussing with a peer, I decided to get a debug going on the httpsd process with the following commands:

diag debug application httpsd -1
diag debug enable

And we got the following output:

BOOM! There it is, the user we created for REST doesn't have access to the system.global endpoint, causing the 403 error.

I could go into a long article on how permissions change a bit when you go to multi-vdom setups, but that's a whole other series of articles. Let's just settle for the fact that, this user doesn't have access to Global settings (settings that will be the same no matter what, like what SSL cert to use for the web UI). And it's not readily available in the GUI when you create the new admin profile, because it really is bad practice to apply "super_admin" access to every user.

So, what do we do?

We make the rest API's admin profile global!

How do we do that you say?

The CLI!

Ok, ok, I am way too excited over this. But simply put we just need to go to the admin profile in the CLI and set the scope of the admin profile to global:

config global
    config system accprofile
        edit "rest_super"
            set scope global
            set sysgrp custom
            config sysgrp-permission
                set admin read-write
                set upd read-write
                set cfg read-write
                set mnt read-write

And that's it!!!

After trying that, I was able to get the following result:

 "http_method": "PUT",
 "revision": "ommitted",
 "revision_changed": false,
 "status": "success",
 "http_status": 200,
 "vdom": "uv-office",
 "path": "system",
 "name": "global",
 "serial": "FGxxxxxxxxxxx",
 "version": "v6.4.3",
 "build": 1778

Big thanks to Hendrik, James, and Tri. Thank you all for reading, I hope this helps.

1,153 views0 comments

Recent Posts

See All