Due to a customer request I’ve made my first experiences with using machine certificates for authentication to establish an SSL-VPN connection and was a bit frustrated that there is no good how-to on how to do all that with Active Directory. The information was either not easily findable or scattered everywhere. Now that I have a working configuration I thought I’d write up a how-to so other people have it easier than me.
Versions used:
- FortiGate: 6.4.6
- FortiClient/EMS: 6.4.5/6.4.4 (EMS is optional)
- Windows Server 2019 (although this should work on every supported version)
I assume the following for this:
- A working SSL-VPN configuration using local authentication
- A working Active Directory
- A working Microsoft CA
- Knowledge on how to configure the various components
- Connectivity between all components
1. FortiGate configuration
1.1 Create an LDAP server and add it to your SSL-VPN group
1.2 Enable client certificates
1.2.1 This can either be done globally in VPN → SSL-VPN Settings or for each authentication rule using the CLI
config vpn ssl settings
config authentication-rule
edit 1
set groups <YOUR_GROUP>
set portal <YOUR_PORTAL>
set client-cert enable
next
end
end
1.3. Import your Windows CA certificate (has to be enabled in Feature Visibility and is called “Certificates”)
1.3.1 System → Certificates → Import → CA Certificate → File (probably)
1.3.2 It should appear under “Remote CA Certificate” as “CA_Cert_1” if this is your first one
1.4 Create a peer user (apparently optional)
Note: This is stated in the documentation, but the connection worked in my lab without it, so I don’t really know what’s up with that, but I have it here for the sake of completness. It might be necessary if you only use certificates for authentication, but I am using them as an additional factor.
1.4.1
config user peer
edit "<NAME>"
set ca "CA_Cert_1" (or whatever it ended up being)
set ldap-server <LDAP_Server> (the one that was configured in step 1)
set ldap-mode principal-name
next
end
1.4.2 Maybe add it to your SSL-VPN group? Again, this wasn’t necessary, but the documentation says so
1.4.3 You can probably create a second one for a backup LDAP server, but considering it wasn’t necessary for this to work I haven’t tested anything in this regard
2. Certificate Authority configuration
2.1 Create the certificate template
2.1.1 Duplicate a template that has “Client Authentication” as a usage (I used the default “Computer” one)
2.1.2 Give it a decent name on the “General” tab
2.1.3 !!! On the “Subject Name” tab set the “Subject name format” to a value - This part is important, because a Subject is needed for the certificate
Note I haven’t tested them all, but I assume everything but “None” works. I used “DNS name”
2.1.4 Set the settings in the “Security” tab according to your needs (if you want to autoenroll the certificates via GPOs for example give “Domain Computers” the “Autoenroll” right)
2.2 Add the template to the issued ones
2.3 (Optional) Create a GPO for autoenrollment (plenty of how-tos out there for that)
2.4 Once everything is in order you should have a certificate, but if not you can request it yourself via MMC
2.4.1 Add the Local Computer certificate store and in the Personal certificates request a new one using the template that was created in step 2.1
3. FortiClient configuration
3.1 Allow FortiClient to use computer certificates
3.1.1 By default a connection/FortiClient isn’t allowed to access the private keys of computer certificates, but you can allow this via an XML setting or a registry key
3.1.2 KB on the XML way
For the sake of archiving this information here is the relevant section:
<vpn>
<sslvpn>
<connections>
<connection>
<name>VPN_connection</name>
<certificate> [...]
</certificate>
<allow_standard_user_use_system_cert>1</allow_standard_user_use_system_cert>
[...]
</connection>
</connections>
</sslvpn>
</vpn>
3.1.2.1 Either do this via EMS or import it by hand
3.1.3 The registry key for easy deployment without EMS
[HKEY_LOCAL_MACHINE\SOFTWARE\Fortinet\FortiClient\Sslvpn\Tunnels\<TUNNEL_NAME>]
"allow_standard_user_use_system_cert"=dword:00000001
3.1.4 Optionally immediately show the certificates in the prompt
<vpn>
<sslvpn>
<connections>
<connection>
<name>SSLVPN_Name</name>
<prompt_certificate>1</prompt_certificate>
</connection>
</connections>
</sslvpn>
</vpn>
[HKEY_LOCAL_MACHINE\SOFTWARE\Fortinet\FortiClient\Sslvpn\Tunnels\<TUNNEL_NAME>]
"promptcertificate"=dword:00000001
3.1.5 Even more optionally only display specific certificates according to simple, wildcard or regex matches
https://docs.fortinet.com/document/forticlient/6.4.6/xml-reference-guide/930338/certificate-settings
Note that the documentation here is wrong. It’s not under system in the XML, but the actual connection. The KB is here to see the options.
<vpn>
<sslvpn>
<connections>
<connection>
<name>SSLVPN_Name</name>
<certificate>
<common_name>
<match_type>wildcard</match_type>
<pattern>
<![CDATA[*]]>
</pattern>
</common_name>
<issuer>
<match_type>simple</match_type>
<pattern>
<![CDATA[YOUR_CA_SIMPLE]]>
</pattern>
</issuer>
</certificate>
</connection>
</connections>
</sslvpn>
</vpn>
[HKEY_LOCAL_MACHINE\SOFTWARE\Fortinet\FortiClient\Sslvpn\Tunnels\<TUNNEL_NAME>]
"CertFilter"="{\"version\":1,\"CN\":{\"type\":1,\"pattern\":\"*\"},\"CA\":{\"type\":0,\"pattern\":\"YOUR_CA_SIMPLE\"},\"OIDS\":[{\"type\":1,\"pattern\":\"*\"}]}"
The registry entry is a bit unreadable, so I recommend doing it via the XML and exporting it
3.2 Create a VPN connection and select your certificate
4. Test
4.1 Start FortiClient and the “Client Certificate” field should now show your certificate
Note If the certificate doesn’t have anything before the / that means it has no subject and cannot be used for authentication. This was configured in step 2.1.3
Here is a picture of a working certificate (Host01.testdomain.com) and one without a subject: https://i.imgur.com/AfVHwDK.png
4.2 If you enter
diagnose debug application fnbamd -1
diagnose debug application sslvpn -1
diagnose debug enable
on the FortiGate you will see that a certificate check is being done and that it is all looking good
https://i.imgur.com/tKlwzqp.png
You also see the CA certificate that was being matched; CA_Cert_1 in my case
That should be it. I hope I didn’t forget anything and that this will be of use to someone.