If you've read my previous post on FortiClient, you'll already be aware that I'm a great fan of their top-tier methods for deploying this particular application …
Well, it was only a matter of time before we had to delve deeper in to this topic. Yes, that's right, EMS. Here's to another can of rotting worms.
In this episode of how to rapidly lose more hair, we'll go through packaging and deploying FortiClient EMS 7.x with Jamf Pro.
Create the Installation Package
First up, you're going to need a generated package from your EMS service, which will come as a .dmg.
After finding hidden config files in another application I was packaging, I've learned the hard way to double-check this mounted volume. What do we have?
10244 3 Jun 17:48 .DS_Store 2048 3 Jun 17:48 .fseventsd 266257984 3 Jun 17:48 Install.mpkg 258 3 Jun 17:48 Technical Documentation.webloc 2048 3 Jun 17:48 Uninstall.app 16485 3 Jun 17:48 background.jpg 2048 3 Jun 17:48 fctdata
Looks like we've got a hidden folder in here with a load of executables, so we'll need to include that in the re-package, otherwise I'm sure something will break.
Under fctdata, it looks like we've got our configuration files, so we'll certainly need to include them, too.
All in all, I think it's best we re-package this whole thing to ensure we don't miss anything at all. There are a few ways we can do this, but I'll stick with Composer, as we'll be pushing with Jamf.
As we need to grab some hidden files, we can't just drag and drop, so create a folder within the /tmp/ folder.
sudo mkdir /tmp/forticlient-ems
Now, copy the contents of the mounted DMG over to our tmp directory.
sudo cp -r /Volumes/FortiClient /tmp/forticlient-ems sudo cp -r /Volumes/FortiClient/.fseventsd /tmp/forticlient-ems
/tmp/forticlient-ems .fseventsd Install.mpkg Technical Documentation.webloc Uninstall.app background.jpg fctdata
Fantastic, that's the contents of the file in the temporary directory. Open this location in finder, and fire up Composer. We can then drag that in to the window in readiness to create a pkg.
We'll also create a postinstall script to run the .mpkg installer.
sudo installer -pkg /tmp/forticlient-ems/Install.mpkg -target /
With that done, we can Build as PKG. Then we need to test it and make sure it installs the application as expected as if we were installing it as the end user.
Testing the Custom Package
For this first bit, we'll keep it simple, sign in to our VM as a standard user, and enter some admin credentials when prompted to install the PKG.
Yep, that worked!
As you can see, it comes with an absolute barrage of pop-ups that a non-admin user is never going to be able to resolve, and the FortiClient tray icon is present.
If we check our FortiClient Console, we can see that it's connected and managed by FortiClient Cloud, and also has our remote access details pre-filled, and is just waiting for our login. Fantastic, that means all the custom settings have worked, too.
That's the easy part, complete. Time to revert the snapshot to our clean working base, and work through the next part. Hiding those pop-ups and pre-approving the bits we need to.
With the application installing, let's work on hiding all these pop-ups and allowing permissions to things.
The first helpful link in this section:
So, first up is removing that "Permission required for VPN" pop up. This requires a VPN configuration profile. Let's create a new Configuration Profile, and set a VPN payload.
Scope it, test it. This removes the VPN pop-up. One down, three more to go. Let's tackle the System Extension warning next.
We need to get information about that system extension. The easiest way to do this is to check what extensions are active before, and after manually approving the extension. Don't forget to roll your snapshot back again once you've checked ;)!
systemextensionsctl list 1 extension(s) --- com.apple.system_extension.network_extension enabled active teamID bundleID (version) name [state] * * AH4XFXJ7DK com.fortinet.forticlient.macos.vpn.nwextension (1.5.0/B20220228) vpnprovider [activated enabled]
Great, now we know what system extension we're approving. Let's add a new payload to our configuration profile.
With that tested, we no longer get the "FortiTray would like permission to create VPN profiles". What's next? Well, all sorts.
Security & Privacy Permissions
Trawling through the Fortinet documentation, I finally found a "Special Notices" section, which provides a list of services that need permissions allowing.
Right then, let's get started.
We need to sign our life away for the following components:
Time to add a new PPPC payload to our configuration profile:
Phew, that was a long one! Here's all of that in a way you can copy.
/Library/Application\ Support/Fortinet/FortiClient/bin/fcaptmon identifier fcaptmon and anchor apple generic and certificate 1[field.1.2.840.1136126.96.36.199.6] /* exists */ and certificate leaf[field.1.2.840.1136188.8.131.52.13] /* exists */ and certificate leaf[subject.OU] = AH4XFXJ7DK // /Library/Application Support/Fortinet/FortiClient/bin/fctservctl2 identifier fctservctl2 and anchor apple generic and certificate 1[field.1.2.840.1136184.108.40.206.6] /* exists */ and certificate leaf[field.1.2.840.1136220.127.116.11.13] /* exists */ and certificate leaf[subject.OU] = AH4XFXJ7DK // /Library/Application\ Support/Fortinet/FortiClient/bin/fmon identifier fmon and anchor apple generic and certificate 1[field.1.2.840.113618.104.22.168.6] /* exists */ and certificate leaf[field.1.2.840.113622.214.171.124.13] /* exists */ and certificate leaf[subject.OU] = AH4XFXJ7DK // com.fortinet.forticlient.macos.antivirus anchor apple generic and identifier "com.fortinet.forticlient.macos.antivirus" and (certificate leaf[field.1.2.840.1136126.96.36.199.9] /* exists */ or certificate 1[field.1.2.840.1136188.8.131.52.6] /* exists */ and certificate leaf[field.1.2.840.1136184.108.40.206.13] /* exists */ and certificate leaf[subject.OU] = AH4XFXJ7DK) // com.fortinet.FortiClient identifier "com.fortinet.FortiClient" and anchor apple generic and certificate 1[field.1.2.840.1136220.127.116.11.6] /* exists */ and certificate leaf[field.1.2.840.113618.104.22.168.13] /* exists */ and certificate leaf[subject.OU] = AH4XFXJ7DK
You'll notice that fmon2 is missing from this list. Well, it's not. No matter how many times I tried to get fmon2 approved, I received warnings about needing to allow access. Turns out that I actually needed to approve com.fortinet.forticlient.macos.antivirus - not fmon2. Thanks for wasting a week there, Fortinet!
That's our VPN, PPPC, and System Extension pop-ups dealt with. Let's try to tackle that certificate warning.
This had me boggled for a few days, until a moment of clarity in the shower (it's where my best thinking happens). Honestly, not sure why it took me this long.
I approved the certificate prompt on the test VM, then exported them from the Keychain.
I found we needed two certificates from here. support.cer, and fortinet-ca2.cer.
As this contains certificates which could be revoked, or need to be changed at different intervals to the other settings, I created a new profile with a Certificate payload.
After testing this, I found I had to restart the machine for the certificate trust to be in place. I added a restart option to the installation policy, and no more pop-ups!
That's two configuration profiles, with a total of 4 payloads between them.
After endless testing with the VM, I deployed it to a few different machines, across a couple of different macOS versions, to ensure that it behaved as expected.
I HATE anything to do with FortiClient. It's always such a pain.
Let's see what we have for this.
- A custom package with the contents from the pre-packaged DMG
2. A computer policy to install the package - scoped to staff machines, and made available in Self Service (don't want to be pushing this out with an enforced restart).
3. Two Configuration Profiles, scoped to our staff machines.
We can finally move this out of test, and close the job off!
I hope this helped some of you out there.