Skip to main content
WelingtonMatias
Staff
Staff
May 21, 2026

Technical Tip: StrongSwan IKEv2 VPN on Ubuntu with Certificate Authentication via FortiGate

  • May 21, 2026
  • 0 replies
  • 186 views

Description

This article describes the complete installation and configuration of the StrongSwan IPsec IKEv2 VPN client on Ubuntu 22.04 LTS, authenticated against a FortiGate firewall using mutual public key (pubkey) authentication. Certificates are issued by an Active Directory Certificate Services (AD CS) CA. This guide is based on a real lab deployment and includes all errors encountered and their solutions.

Scope

OS: Ubuntu v22.04 LTS, StrongSwan v5.6.2.

Firewall: FortiGate, FortiOS v7.x.

CA: Windows Server 2022, Active Directory Certificate Services.

Auth: IKEv2, Mutual Certificate (pubkey).

Solution

Architecture.

The authentication flow uses mutual certificate validation:

Ubuntu (StrongSwan) FortiGate AD / CA.

Sends ubuntu-client.pem ──────► Validates against CA_Cert_1
Receives VPN-LOCAL cert ◄────── Signed by AD CA
Validates with CA_Cert_1 ──────► OK
══ IKEv2 Tunnel ESTABLISHED ══



Step 1. Install StrongSwan on Ubuntu.



sudo apt update && sudo apt upgrade -y

sudo apt install -y strongswan strongswan-pki libstrongswan-extra-plugins libstrongswan-standard-plugins libcharon-extra-plugins libcharon-extauth-plugins strongswan-swanctl openssl ldap-utils



Step 2. Export and Import the AD CA Certificate.

Export from FortiGate GUI.

Navigate to System -> Certificates -> CA Certificates.

Download the AD CA certificate, it will download as .cer.

Check the format on Ubuntu:


file CA_Cert_1.cer


Expected output: CA_Cert_1.cer: PEM certificate.

If already PEM, no conversion needed.


Step 3. Install on Ubuntu.


Copy directly (already PEM format).



sudo cp CA_Cert_1.cer /etc/ipsec.d/cacerts/CA_Cert_1.pem
sudo chmod 644 /etc/ipsec.d/cacerts/CA_Cert_1.pem



To verify:



openssl x509 -in /etc/ipsec.d/cacerts/CA_Cert_1.pem -text -noout | grep -E "Subject:|Issuer:|Not After"



Note: If the file is DER format instead of PEM, convert with: openssl x509 -inform DER -in CA_Cert_1.cer -out CA_Cert_1.pem.


Generate FortiGate VPN Certificate (Signed by AD CA).

The FortiGate must present a certificate signed by the AD CA — do NOT use Fortinet_Factory, as Ubuntu cannot validate its chain.



Generate CSR on FortiGate:

  • Navigate to System -> Certificates -> Local Certificates -> Generate.


Parameter                                                Value

Certificate Name                                         VPN-LOCAL
ID Type                                                  IP
IP                                                       172.16.20.111 ( Fortigate WAN IP)
Key Type                                                 RSA - 2048 bits


  • Download the generated CSR.


Sign with AD CA (via certsrv).

On the AD server, open a browser and access: http://127.0.0.1/certsrv. Select Request a certificate -> Advanced certificate request. Paste the CSR content. Select the template: Web Server. Download the signed certificate in Base 64 format.


Import the signed certificate into FortiGate.

Navigate to System -> Certificates -> Local Certificates -> Import.

Upload the signed .cer file.

Configure Phase 1 to use VPN-LOCAL as the certificate.


Note: Do not use Fortinet_Factory for the VPN certificate. Its chain (fortinet-ca2 > fortinet-subca2001) is not publicly resolvable, and Ubuntu will reject it with 'no trusted RSA public key found'.


Step 4. Generate Ubuntu Client Certificate.

Generate key and CSR on Ubuntu.

Create and access the directory vpn-cert:


mkdir ~/vpn-cert && cd ~/vpn-cert


Generate private key:


openssl genrsa -out ubuntu-client.key 2048


Generate CSR:


openssl req -new -key ubuntu-client.key -out ubuntu-client.csr -subj "/CN=ubuntu/O=wellscompany/C=US"


View CSR to copy:


cat ubuntu-client.csr


Note: The warning 'Can't load .rnd into RNG' is harmless — the CSR is generated successfully. Confirm with: ls -la ~/vpn-cert/.


Create a custom CA template on AD (required).

The default Web Server and User templates do not preserve the CSR Subject. A custom template is required:

Open certtmpl.msc on the AD server

'Right-click' Web Server template -> Duplicate template.

General tab: Name = VPN-Client.

Subject Name tab: select Supply in the request.

Extensions tab -> Application Policies: add Client Authentication.

Security tab: add user with Enroll permission

Select OK and publish the template:


On AD PowerShell (as Administrator):


Add-CATemplate -Name "VPN-Client"


Type Y to confirm.


Note: Using the Web Server or User template will result in the certificate Subject being overwritten with the logged-in AD user's data instead of the CSR Subject (CN=ubuntu).


Sign CSR with VPN-Client template.

Transfer ubuntu-client.csr to the AD server.

Access http://127.0.0.1/certsrv on the AD server.

Select Request a certificate -> Advanced certificate request.

Paste the CSR content.

Select template: VPN-Client.

Download in Base 64 format, save as ubuntu-client.cer.

Transfer back to Ubuntu and verify:


Expected Subject: C=US, O=wellscompany, CN=ubuntu.


openssl x509 -in ubuntu-client.cer -text -noout | grep -E "Subject:|Issuer:|Not After"


Install the client certificate on Ubuntu.


cd ~/vpn-cert

sudo cp ubuntu-client.cer /etc/ipsec.d/certs/ubuntu-client.pem
sudo cp ubuntu-client.key /etc/ipsec.d/private/ubuntu-client.key
sudo chmod 644 /etc/ipsec.d/certs/ubuntu-client.pem
sudo chmod 600 /etc/ipsec.d/private/ubuntu-client.key


Confirm files are in place:


ls -la /etc/ipsec.d/certs/ubuntu-client.pem
ls -la /etc/ipsec.d/private/ubuntu-client.key
ls -la /etc/ipsec.d/cacerts/

Step 5. Configure FortiGate IPsec Tunnel.

Phase 1 (IKEv2 + Certificate).

Navigate to VPN -> IPsec Tunnels -> Create New -> Custom, or configure via CLI:


config vpn ipsec phase1-interface

edit "VPN_CERT"
     set type dynamic
     set interface "port1"
     set ike-version 2
     set authmethod signature
     set peertype peergrp
     set net-device disable
     set mode-cfg enable
     set proposal aes256-sha256-modp2048
     set dhgrp 14
     set eap disable
     set dpd on-idle
     set dpd-retryinterval 60
     set certificate "VPN-LOCAL"
     set peergrp "grp-authcert"
     set assign-ip-from name
     set ipv4-name "SSLVPN_TUNNEL_ADDR1"
     set ipv4-netmask 255.255.255.0
     set dpd-retryinterval 60
  next
end


Note: Key settings: authmethod=signature (certificate auth), peertype=any (accept any valid cert), eap=disable (not using EAP/MSCHAPv2).


Configure User Peer and Peer Group (required).

These two configurations tell FortiGate which CA to use when validating the client certificate. Without them, certificate authentication will fail.


Create a user peer referencing the AD CA:


config user peer
   edit "authcert-peer"
   set ca "CA_Cert_1"
  next
end


Create a peer group with that peer as a member:


config user peergrp
   edit "grp-authcert"
   set member "authcert-peer"
  next
end


Reference the peer group in Phase 1:


config vpn ipsec phase1-interface
   edit "VPN_CERT"
   set peertype peergrp
   set peergrp "grp-authcert"
  next
end


Note: This is the most critical FortiGate configuration for certificate auth. The user peer maps the client certificate to the AD CA (CA_Cert_1). Without this, FortiGate cannot validate which CA signed the client certificate.


Verify AD CA is imported on FortiGate.

Navigate to System -> Certificates -> CA Certificates.

Confirm that wellscompany-WELLS-ADSERVER-CA is listed.

If missing, import CA_Cert_1.pem via: System -> Certificates -> CA Certificates -> Import.


Parameter                                                   Value

Encryption                                                  AES256/SHA256
PFS                                                         DH Group 14
Lifetime (s)                                                43200


Firewall Policy:


Parameter                                                   Value

incoming Interface                                          VPN_CERT (VPN tunnel)
Outgoing Interface                                          LAN Interface 
Source                                                      ALL    
Destination                                                 ALL 
Action                                                      ACCEPT
NAT                                                         Disable


Step 6. Configure StrongSwan on Ubuntu: edit /etc/ipsec.conf.


config setup
charondebug="ike 2, knl 2, cfg 2, net 2, esp 2, dmn 2, mgr 2"
strictcrlpolicy=no

conn vpn-fortigate
keyexchange=ikev2
right=172.16.20.111
rightid=%any
rightauth=pubkey
rightsubnet=0.0.0.0/0
left=%config
leftauth=pubkey
leftid="C=US, O=wellscompany, CN=ubuntu"
leftcert=ubuntu-client.pem
leftsourceip=%config
ike=aes256-sha256-modp2048!
esp=aes256-sha256!
auto=add
dpdaction=clear
dpddelay=30s
dpdtimeout=120s


strictcrlpolicy=no prevents connection failures when Ubuntu cannot reach the AD CRL distribution point via LDAP.: edit /etc/ipsec.secrets.

# Reference the client private key
: RSA ubuntu-client.key


The /etc/ipsec.secrets file must have permission 600. Run: sudo chmod 600 /etc/ipsec.secrets


Step 7. Connect and Verify.

Restart StrongSwan:


sudo ipsec restart


Bring up the tunnel:


sudo ipsec up vpn-fortigate


Expected output:


initiating IKE_SA vpn-fortigate[1] to 172.16.20.111.
authentication of 'CN=172.16.20.111' with RSA signature successful
IKE_SA vpn-fortigate[1] established
CHILD_SA vpn-fortigate{1} established
connection 'vpn-fortigate' established successfully


Note: Connection confirmed: ESTABLISHED 172.16.20.115[C=US, O=wellscompany, CN=ubuntu]...172.16.20.111[CN=172.16.20.111] — IP assigned: 10.212.134.200/32.


Step 8. Useful diagnostic commands.

Live logs:


sudo journalctl -u strongswan-starter -f

 

Check loaded connections:


sudo ipsec status
sudo ipsec statusall


Verify certificate:


openssl x509 -in /etc/ipsec.d/certs/ubuntu-client.pem -text -noout | grep -E "Subject:|Issuer:|Not After"


Test AD LDAP auth from FortiGate CLI:


diagnose test authserver ldap Wells-ADSERVER wells Password123


Check FortiGate Phase 1 config:


show vpn ipsec phase1-interface LDAPS


Tear down tunnel:


sudo ipsec down vpn-fortigate


Related article:

Technical Tip: How to export root CA from Certificate Authority Server and import to FortiGate