Vai al contenuto
GLGiuseppe Lanza Scrivimi

Accesso remoto IKEv2: client Windows verso Ubuntu con strongSwan

Collegare i portatili Windows alla sede con il client VPN integrato: strongSwan su Ubuntu, certificato del server, utenti EAP-MSCHAPv2, algoritmi robusti con PowerShell, firewall, split tunneling e risoluzione degli errori.

Sistemi: Ubuntu 24.04 LTS · Windows 10/11Livello: AvanzatoTempo: 60 minutiAggiornata: novembre 2026

Che cosa costruiamo

Finora la serie ha collegato sedi intere. Qui colleghi le singole persone: il portatile di chi lavora da casa o in trasferta si connette alla sede B e ottiene un indirizzo della VPN. È lo scenario che in gergo si chiama road warrior.

Usi il client VPN già presente in Windows 10 e 11, senza installare niente sui portatili. Il protocollo è IKEv2, che regge bene i cambi di rete (Wi-Fi → 4G) e attraversa il NAT incapsulando tutto in UDP 4500. L’autenticazione è a due livelli:

  • il server si presenta con un certificato emesso da una tua CA, che i portatili verificano;
  • l’utente si autentica con nome e password tramite EAP-MSCHAPv2.

È la combinazione più diffusa perché non richiede di distribuire un certificato a ogni utente. L’alternativa con certificati macchina, più robusta ma più laboriosa, è descritta in fondo.

Prerequisito

Questa guida dà per scontata la base di strongSwan e swanctl vista in VPN IPsec tra Cisco e Ubuntu con strongSwan. Lo stesso server può servire sia il collegamento tra sedi sia gli utenti remoti: basta una connessione in più in swanctl.conf.

Lo scenario

Il server Ubuntu della sede B ha un indirizzo pubblico statico e un nome DNS, vpn.example.com, che punta a quell’indirizzo. I portatili si collegano da reti qualsiasi, quasi sempre dietro NAT.

Portatile Windows IP VPN 10.10.10.x Internet Ubuntu strongSwan ens18 203.0.113.10 LAN sede B 192.168.20.0/24 IKEv2 / IPsec (UDP 4500) · EAP-MSCHAPv2 dietro NAT (casa, 4G) vpn.example.com ens19 .1 (gateway) pool indirizzi virtuali 10.10.10.0/24
Il portatile apre un tunnel IKEv2 verso Ubuntu, riceve un indirizzo del pool e raggiunge la LAN della sede B.
ElementoValore
Server VPNUbuntu 24.04, ens18 203.0.113.10, nome vpn.example.com
LAN sede B192.168.20.0/24, gateway .1 su ens19
Pool indirizzi virtuali10.10.10.0/24 (non deve sovrapporsi a nessuna rete delle sedi)
DNS per i client192.168.20.1 (un resolver interno della sede B)
ClientWindows 10/11, client VPN integrato

Usa un nome DNS e non l’indirizzo IP: Windows confronta il nome che scrivi nella connessione con quello nel certificato del server. Se proprio devi usare l’IP, vedi la nota sugli errori in fondo.

Pacchetti, CA e certificato del server

1. Installare i pacchetti

Ubuntu – installazione
sudo apt update
sudo apt install charon-systemd strongswan-swanctl strongswan-pki \
     libcharon-extra-plugins libstrongswan-extra-plugins
  • charon-systemd è il demone IKE gestito da systemd, servizio strongswan;
  • strongswan-pki contiene il comando pki per creare CA e certificati;
  • libcharon-extra-plugins porta i plugin eap-mschapv2 ed eap-identity;
  • libstrongswan-extra-plugins aggiunge altri fornitori di algoritmi, utile per MD4 (vedi più sotto).
MSCHAPv2 e OpenSSL 3

EAP-MSCHAPv2 usa ancora MD4 e DES, che OpenSSL 3 ha spostato nel provider “legacy”. Il plugin openssl di strongSwan lo carica da solo (opzione load_legacy, attiva per impostazione predefinita). Se nel log compare un errore su MD4 non disponibile, controlla che i plugin aggiuntivi siano installati e che load_legacy non sia stato disattivato.

2. Creare la CA e il certificato del server

Crei una piccola CA privata e un certificato per il server. Windows è esigente su alcuni dettagli:

  • chiave RSA oppure ECDSA P-256/P-384: Windows rifiuta Ed25519 e P-521;
  • il nome del server in un subjectAltName di tipo DNS, oltre che nel CN;
  • uso esteso della chiave serverAuth; aggiungi anche ikeIntermediate, che male non fa e serve ai client macOS meno recenti.

Lavora in una cartella protetta. La chiave della CA, in produzione, va conservata fuori dal server VPN.

Ubuntu – CA privata
mkdir -p ~/pki-vpn && cd ~/pki-vpn
umask 077

# chiave e certificato della CA (10 anni)
pki --gen --type ecdsa --size 384 --outform pem > caKey.pem
pki --self --ca --lifetime 3652 --in caKey.pem \
    --dn "C=IT, O=Esempio Srl, CN=Esempio VPN Root CA" \
    --outform pem > caCert.pem
Ubuntu – certificato del server
# chiave del server
pki --gen --type ecdsa --size 384 --outform pem > serverKey.pem

# certificato del server (5 anni), firmato dalla CA
pki --pub --in serverKey.pem --type ecdsa \
  | pki --issue --lifetime 1826 \
        --cacert caCert.pem --cakey caKey.pem \
        --dn "C=IT, O=Esempio Srl, CN=vpn.example.com" \
        --san vpn.example.com \
        --flag serverAuth --flag ikeIntermediate \
        --outform pem > serverCert.pem

# controllo: SAN e flag devono comparire nell'output
pki --print --in serverCert.pem

Copia i file nelle cartelle che swanctl legge da solo:

sudo cp caCert.pem     /etc/swanctl/x509ca/
sudo cp serverCert.pem /etc/swanctl/x509/
sudo cp serverKey.pem  /etc/swanctl/private/
sudo chmod 600 /etc/swanctl/private/serverKey.pem

Il file caCert.pem è l’unico che distribuirai ai portatili. È pubblico: contiene solo il certificato, non la chiave.

Configurazione di strongSwan

Crea un file dedicato agli utenti remoti. swanctl carica in automatico tutto ciò che trova in /etc/swanctl/conf.d/.

/etc/swanctl/conf.d/road-warrior.conf
connections {
  rw-windows {
    version = 2
    local_addrs = 203.0.113.10
    pools = pool-rw
    send_cert = always
    # IKE: AES-GCM (o AES-CBC) con SHA-256 e curva P-256
    proposals = aes256gcm16-prfsha256-ecp256, aes256-sha256-ecp256
    dpd_delay = 60s

    local {
      auth = pubkey
      certs = serverCert.pem
      id = vpn.example.com
    }
    remote {
      auth = eap-mschapv2
      eap_id = %any
    }
    children {
      rw-lan {
        local_ts = 0.0.0.0/0
        # ESP: AES-GCM 256 con PFS sulla curva P-256
        esp_proposals = aes256gcm16-ecp256
        # lascia che sia Windows a rinnovare le SA figlie
        rekey_time = 0s
        dpd_action = clear
      }
    }
  }
}

pools {
  pool-rw {
    addrs = 10.10.10.0/24
    dns = 192.168.20.1
  }
}

secrets {
  eap-mario {
    id = mario.rossi
    secret = "Cambia-Questa-Password-Lunga"
  }
  eap-anna {
    id = anna.bianchi
    secret = "Anche-Questa-Va-Cambiata"
  }
}

I punti da capire:

  • id = vpn.example.com deve coincidere con il SAN del certificato e con il nome che userai su Windows;
  • eap_id = %any fa sì che strongSwan chieda il nome utente al client: Windows infatti si presenta con il proprio indirizzo IP, non con il nome dell’utente;
  • local_ts = 0.0.0.0/0 permette sia il tunnel completo sia lo split tunneling, che decidi lato Windows (vedi più avanti);
  • rekey_time = 0s sulle SA figlie evita un problema noto: il rinnovo avviato dal server verso un client dietro NAT può essere rifiutato da Windows. Il client rinnova da solo, a tempo o dopo circa 200 MiB di traffico.
Password robuste

MSCHAPv2 è un protocollo vecchio: qui è al sicuro solo perché viaggia dentro il tunnel IKEv2 già cifrato e autenticato dal certificato del server. Usa password lunghe e casuali, generate per esempio con openssl rand -base64 24, e proteggi il file: sudo chmod 600 /etc/swanctl/conf.d/road-warrior.conf. Con molti utenti, invece dei secrets locali passa a un server RADIUS (plugin eap-radius), magari collegato ad Active Directory.

Carica la configurazione e controlla:

sudo systemctl enable --now strongswan
sudo swanctl --load-all
sudo swanctl --list-conns
sudo swanctl --list-certs
sudo swanctl --list-pools

Instradamento, firewall e NAT

1. Abilitare l’inoltro

/etc/sysctl.d/99-router.conf
net.ipv4.ip_forward = 1
sudo sysctl --system

2. Regole nftables

Con IKEv2 servono le porte UDP 500 e 4500, più il protocollo ESP (numero 50) per i client che non sono dietro NAT. Il traffico decifrato rientra da ens18 e si riconosce con l’espressione meta ipsec exists. Aggiungi alle catene della guida Firewall completo su Linux con nftables:

/etc/nftables.conf – estratto
table inet filtro {
  chain input {
    # ... regole esistenti ...
    udp dport { 500, 4500 } accept
    ip protocol esp accept
  }
  chain forward {
    # ... regole esistenti (established,related in testa) ...
    # MSS ridotto per il traffico da e verso i client VPN
    ip saddr 10.10.10.0/24 tcp flags syn tcp option maxseg size set 1360
    ip daddr 10.10.10.0/24 tcp flags syn tcp option maxseg size set 1360
    # client VPN verso la LAN B (e verso Internet, se tunnel completo)
    meta ipsec exists ip saddr 10.10.10.0/24 accept
  }
}

table ip nat {
  chain postrouting {
    type nat hook postrouting priority srcnat; policy accept;
    # solo per il tunnel completo: i client escono su Internet con l'IP del server
    ip saddr 10.10.10.0/24 oifname "ens18" masquerade
  }
}
sudo nft -c -f /etc/nftables.conf   # controlla la sintassi
sudo systemctl reload nftables

Le risposte dalla LAN B ai client passano grazie alla regola ct state established,related accept che hai già in testa alla catena forward. I PC della LAN B non hanno bisogno di rotte particolari se il loro gateway è il server Ubuntu; altrimenti aggiungi sul loro gateway una rotta verso 10.10.10.0/24 via 192.168.20.1.

Con UFW l’equivalente minimo è:

sudo ufw allow 500,4500/udp
sudo ufw route allow from 10.10.10.0/24
# il masquerade va aggiunto in /etc/ufw/before.rules, sezione *nat

Configurazione dei client Windows

1. Importare la CA nell’archivio del computer

Il certificato della CA va nelle Autorità di certificazione radice attendibili del computer locale, non in quelle dell’utente: il client IKEv2 guarda solo l’archivio della macchina. Copia caCert.pem sul portatile e, da PowerShell come amministratore:

PowerShell (amministratore)
Import-Certificate -FilePath "C:\Temp\caCert.pem" `
    -CertStoreLocation Cert:\LocalMachine\Root

# verifica
Get-ChildItem Cert:\LocalMachine\Root |
    Where-Object Subject -like "*Esempio VPN Root CA*"

In alternativa, da interfaccia: certlm.msc → Autorità di certificazione radice attendibili → Certificati → Importa. Su molti portatili conviene distribuire la CA con un criterio di gruppo o con Intune.

2. Creare la connessione

PowerShell (amministratore)
Add-VpnConnection -Name "Sede B" `
    -ServerAddress "vpn.example.com" `
    -TunnelType Ikev2 `
    -AuthenticationMethod Eap `
    -EncryptionLevel Required `
    -AllUserConnection `
    -RememberCredential `
    -PassThru

Con -AuthenticationMethod Eap e senza un profilo EAP personalizzato, Windows usa EAP-MSCHAPv2 con nome e password. -AllUserConnection rende la connessione disponibile a tutti gli utenti del portatile (per questo serve la shell da amministratore); toglilo se vuoi crearla solo per l’utente corrente.

3. Allineare gli algoritmi

Questo passaggio non è facoltativo. Senza impostazioni personalizzate Windows propone ancora 3DES, SHA-1 e il gruppo Diffie-Hellman 2 (modp1024), e per ESP addirittura DES. strongSwan, configurato come sopra, li rifiuta: ed è giusto così.

PowerShell (amministratore)
Set-VpnConnectionIPsecConfiguration -ConnectionName "Sede B" `
    -EncryptionMethod GCMAES256 `
    -IntegrityCheckMethod SHA256 `
    -DHGroup ECP256 `
    -CipherTransformConstants GCMAES256 `
    -AuthenticationTransformConstants GCMAES256 `
    -PfsGroup ECP256 `
    -AllUserConnection `
    -Force -PassThru

Ecco come si corrispondono i due lati:

FaseWindowsstrongSwan
IKE – cifratura-EncryptionMethod GCMAES256aes256gcm16
IKE – PRF-IntegrityCheckMethod SHA256prfsha256
IKE – Diffie-Hellman-DHGroup ECP256ecp256
ESP – cifratura e integrità-CipherTransformConstants GCMAES256 e -AuthenticationTransformConstants GCMAES256aes256gcm16
ESP – PFS al rinnovo-PfsGroup ECP256ecp256 in esp_proposals

Con AES-GCM in ESP i due parametri -CipherTransformConstants e -AuthenticationTransformConstants devono avere lo stesso valore, perché GCM cifra e autentica insieme. Se un portatile datato non accetta GCM per IKE, usa -EncryptionMethod AES256: la seconda proposta in proposals (aes256-sha256-ecp256) lo copre già.

Connessioni create da interfaccia

Se l’utente crea la VPN da Impostazioni → Rete e Internet → VPN, la connessione è solo sua: in quel caso esegui Set-VpnConnectionIPsecConfiguration senza -AllUserConnection, dalla sessione di quell’utente. Il nome dopo -ConnectionName deve essere identico.

4. Collegarsi

Dall’icona di rete scegli “Sede B” → Connetti e inserisci nome utente e password definiti nei secrets. Per una prova da riga di comando:

rasdial "Sede B" mario.rossi "Cambia-Questa-Password-Lunga"
rasdial "Sede B" /disconnect

Tunnel completo o split tunneling

Hai due modi di instradare il traffico del portatile:

Tunnel completoSplit tunneling
Cosa passa nella VPNTutto, anche la navigazioneSolo le reti della sede
ProIl traffico passa dai controlli della sede; protegge sulle reti Wi-Fi pubblicheMeno carico sul server e sulla linea della sede; navigazione più veloce
ControTutta la banda Internet degli utenti passa dalla sedeIl portatile è contemporaneamente in VPN e su Internet
Lato UbuntuServe il masquerade su ens18Il masquerade non serve

Il tunnel completo è il comportamento predefinito di Add-VpnConnection. Per passare allo split tunneling e indicare quali reti mandare nella VPN:

PowerShell (amministratore)
Set-VpnConnection -Name "Sede B" -SplitTunneling $true -AllUserConnection

Add-VpnConnectionRoute -ConnectionName "Sede B" `
    -DestinationPrefix "192.168.20.0/24" -AllUserConnection

# se usi anche le altre sedi della serie
Add-VpnConnectionRoute -ConnectionName "Sede B" `
    -DestinationPrefix "192.168.10.0/24" -AllUserConnection

Le rotte compaiono quando la VPN si connette e spariscono quando si disconnette. Se instradi verso la VPN anche 192.168.10.0/24, ricorda che anche il collegamento tra sede B e sede A deve conoscere la rete 10.10.10.0/24 (vedi il passo successivo in fondo).

Rete “a classi” in split tunneling

In split tunneling Windows aggiunge da solo anche una rotta per la rete di classe dell’indirizzo ricevuto: con un pool 10.10.10.0/24 è 10.0.0.0/8. Se a casa dell’utente qualcosa usa la rete 10.x, può andare in conflitto. In quel caso scegli per il pool un intervallo meno comune, per esempio in 172.16.0.0/12.

Se usi lo split tunneling e vuoi irrigidire il server, puoi anche ridurre local_ts alle sole reti della sede (local_ts = 192.168.20.0/24): i client non potranno mandare altro nel tunnel.

Verifiche

Su Ubuntu

sudo swanctl --list-sas                # SA IKE e figlie con gli algoritmi negoziati
sudo swanctl --list-pools --leases     # indirizzi assegnati e a chi
sudo journalctl -u strongswan -f       # log in tempo reale durante la connessione
sudo ip xfrm state                     # SA nel kernel
sudo tcpdump -ni ens18 udp port 500 or udp port 4500

Nell’output di --list-sas controlla la riga dell’IKE SA: deve riportare AES_GCM_16-256/PRF_HMAC_SHA2_256/ECP_256 e l’identità EAP dell’utente (mario.rossi).

Su Windows

Get-VpnConnection -Name "Sede B" -AllUserConnection | Format-List *
Get-NetIPConfiguration | Where-Object InterfaceAlias -eq "Sede B"
Get-NetRoute -InterfaceAlias "Sede B"
Test-NetConnection 192.168.20.1
Resolve-DnsName server.sede-b.lan

Quando una connessione fallisce, il dettaglio è nel Visualizzatore eventi → Registri di Windows → Applicazione, origine RasClient: il messaggio riporta il codice di errore che trovi nella tabella dei problemi.

L’alternativa: certificati macchina

Invece di nome e password, ogni portatile può autenticarsi con un proprio certificato. È più sicuro (niente password da indovinare o riutilizzare) e si presta alla connessione automatica, ma devi emettere, distribuire e revocare un certificato per ogni dispositivo.

  • emetti per ogni portatile un certificato con flag clientAuth, firmato dalla stessa CA, ed esportalo in PKCS#12 con openssl pkcs12 -export;
  • importalo nell’archivio Personale del computer (Cert:\LocalMachine\My) con Import-PfxCertificate;
  • crea la connessione con -AuthenticationMethod MachineCertificate invece di Eap;
  • in strongSwan sostituisci il blocco remote con auth = pubkey e cacerts = caCert.pem, e togli eap_id.

In un dominio Active Directory con una CA aziendale, la registrazione automatica dei certificati computer rende questa strada molto più comoda.

Problemi comuni

SintomoCausa probabileCosa fare
Errore 13801 “credenziali di autenticazione IKE non accettabili”Il certificato del server non va bene per Windows: nome diverso da quello della connessione, manca serverAuth, chiave Ed25519 o P-521Controlla con pki --print; il nome in -ServerAddress deve comparire nel SAN. Se ti colleghi per IP, il SAN deve contenere l’IP come nome DNS: --san dns:203.0.113.10
Errore 13806 “IKE non ha trovato un certificato computer valido”La CA non è nell’archivio radice del computer, oppure è nell’archivio dell’utenteImporta la CA in Cert:\LocalMachine\Root
Errore 13868 “errore di corrispondenza dei criteri”Algoritmi non allineatiRipeti Set-VpnConnectionIPsecConfiguration sulla connessione giusta (utente o tutti gli utenti); nel log di strongSwan cerca NO_PROPOSAL_CHOSEN
Errore 809, nessuna risposta dal serverUDP 500/4500 bloccati, oppure frammenti IKE persi lungo il percorsoVerifica con tcpdump che i pacchetti arrivino; controlla il firewall di Ubuntu e quello della rete da cui si collega l’utente
Nome utente e password rifiutatiUtente sbagliato nei secrets, oppure MD4 non disponibileGuarda journalctl -u strongswan: cerca EAP_MSCHAPV2 e messaggi su MD4
Connesso, ma la LAN B non rispondeInoltro disattivato, regola forward mancante, rotta di ritorno assentesysctl net.ipv4.ip_forward; i PC della LAN B devono sapere che 10.10.10.0/24 si raggiunge via 192.168.20.1
La connessione cade dopo un po’ di trafficoRinnovo delle SA figlie avviato dal server verso un client dietro NATLascia rekey_time = 0s nel blocco children
Siti lenti o pagine che non finiscono di caricareMTU/MSSControlla le regole MSS nella catena forward; prova con 1300
Sull’errore 809 e la chiave di registro

Per l’errore 809 si consiglia spesso di creare il valore DWORD AssumeUDPEncapsulationContextOnSendRule = 2 in HKLM\SYSTEM\CurrentControlSet\Services\PolicyAgent, seguito da un riavvio. Microsoft lo documenta per L2TP/IPsec con il server dietro NAT; IKEv2 gestisce il NAT da solo e di solito quella chiave non cambia nulla. Provala solo dopo aver escluso porte bloccate e frammentazione.

Il passo successivo

Ora gli utenti remoti raggiungono la sede B. Se la sede B è già collegata alla sede A con la VPN IPsec tra Cisco e Ubuntu, puoi far arrivare i portatili anche lì: sul Cisco aggiungi una rotta verso 10.10.10.0/24 attraverso il tunnel della sede B e, su Ubuntu, una regola forward che consenta il traffico tra i client VPN e l’interfaccia di quel tunnel. Se quel collegamento usa una crypto map invece della VTI, aggiungi 10.10.10.0/24 ai selettori di traffico. Per collegare una terza sede con Windows Server vedi VPN IPsec site-to-site tra Cisco e Windows Server. Per filtrare con più precisione che cosa possono raggiungere gli utenti remoti, riprendi la catena forward della guida Firewall completo su Linux con nftables.

Prima di andare in produzione

Prova sempre la configurazione in laboratorio, salva quella attuale prima di modificarla e tieni un accesso di emergenza (console o accesso fuori banda) quando lavori su firewall e VPN da remoto.