Site to Site VPN between Cisco FTD and Strongswan
NOTICE : THIS ARTICLE IS NOT FULLY TRANSLATED TO ENGLISH YET
Introduction
Dans cet article, je vais détailler comment configurer un VPN entre un firewall Cisco FTD (Firepower Thread Defense) et un serveur linux faisant tourner Strongswan. Afin de profiter de BGP pour propager mes sous-réseaux, nous configurerons un VPN “route-based” qui utilise des interfaces virtuelle “tunnel”. Ces interfaces virtuelles seront nommées VTI dans la suite de cet article (et du suivant).
Voici le schéma du VPN que nous allons réaliser.
Note: Les subnets 192.168.1.0/24 et 10.15.0.0/16 sont en réalité divisés en plusieurs sous-réseaux (qui ne sont pas affichés pour ne pas surcharger ce schéma).
Pour un rapide rappel entre “route-based” et “policy-based” :
Policy-based
Seul les paquets répondant aux conditions d’une ACL seront authorisés à entrer / sortir du VPN. Une route implicite est crée pour permettre au système d’exploitation d’envoyer les paquets dans le tunnel VPN, cette route est basée sur l’ACL.
Exemple sur un FTD
> show access-list | include 192.168.157.0
access-list CSM_IPSEC_ACL_5 line 1 extended permit ip host xxx.xxx.146.94 192.168.157.0 255.255.255.0
>
> show route static
[...]
V 192.168.157.0 255.255.255.0
connected by VPN (advertised), VPN_INTERNET
[...]
La destination de l’ACL est 192.168.157.0/24 et c’est également le même sous-réseaux/masque pour la route implicite.
J’aurai bien montré la route implicite sur un linux faisant tourné strongswan, mais je n’ai pas trouvé comment faire.
Route-based
Une interface virtuelle (ou VTI) nommée tunnel va être définie de chaque coté du VPN. Pour envoyer un paquets dans le tunnel VPN, le système n’a juste qu’à définir des routes vers cette interface virtuelle. Peut-importe la nature de la route, static ou dynamique.
Exemple sur FTD
> show route | include 192.168.51.156
B 192.168.51.156 255.255.255.254 [20/0] via 169.254.51.1, 00:05:40
>
Note: 169.254.51.1 est l’IP de la VTI
Exemple sur linux
[centos@labfabear ~]$ ip route | grep 10.15.111.1
10.15.111.12/30 via 169.254.51.2 dev tunnel1 proto 186 metric 20
10.15.111.16/30 via 169.254.51.2 dev tunnel1 proto 186 metric 20
Note: 169.254.51.2 est l’IP de la VTI
Configuration de Firepower
Pour créer le VPN, il faut naviguer dans le menu Devices > Site to Site > Add VPN > Firepower Thread Defense Device
La première page de configuration du VPN s’affiche, il va s’agir ici :
- De choisir entre Policy-based et Route-based
- De choisir la version de IKE
- De renseigner les IPs “peer” sur le firewall FTD lui-même et sur le endpoint
Pour chaque node/peer :
-
Choisir le “device” : – Extranet pour le peer distant (ici notre serveur linux) – Le nom du firewall FTD qui servira de node pour le VPN (dans mon cas FTD Firewall)
-
Choisir l’IP du node : – Pour le firewall extranet (Serveur Linux) il faudra donner l’IP joinable via internet (IP publique, dans mon cas 10.10.10.10) – Pour le firewal local (FTD), il faut simplement séléctionner la VTI qu’on utilisera et l’IP peer sera associée automatiquement (dans mon cas 20.20.20.20 sera donc séléctionné)
On passe ensuite à l’onglet IKE.
Dans cette partie, on va configurer la phase 1 du VPN :
- La suite crypto et la durée de vie avant renegotiation (Policy)
- La clé pré-partagée (pre-shared key)
Il est important que les paramètres crypto (Integrity, Encryption, PRF et DH) ainsi que la clé pré-partagée soient les mêmes sur le FTD et dans la configuration Strongswan, sinon le tunnel ne pourra pas être monté.
L’onglet suivant concerne IPSec (Phase 2)
Même chose, on va choisir une suite crypto qui doit être la même des deux cotés du VPN (je choisi en général AES256 et SHA256), ainsi que :
- le temps (en seconde) avant renegotiation du tunnel IPSec ou
- le nombre de kilo-octet pouvant traverser le tunnel avant de déclencher une renegotiation (j’ai laissé ce champs vide, je ne veux pas de limite de taille)
Tunnel configuration
interface Tunnel2
nameif Tunnel2
ip address 169.254.51.2 255.255.255.252
tunnel source interface VPN_INTERNET
tunnel destination 10.10.10.10
tunnel mode ipsec ipv4
tunnel protection ipsec profile FMC_IPSEC_PROFILE_3
!
Configuration IKEv2
crypto ikev2 policy 1
encryption aes-256
integrity sha256
group 14
prf sha256
lifetime seconds 86400
crypto ikev2 enable VPN_INTERNET
Configuration IPSec
crypto ipsec ikev2 ipsec-proposal CSM_IP_2
protocol esp encryption aes-256 aes-192 aes
protocol esp integrity sha-512 sha-384 sha-256 sha-1
crypto ipsec profile FMC_IPSEC_PROFILE_3
set ikev2 ipsec-proposal CSM_IP_2
set security-association lifetime kilobytes unlimited
Note : Si vous êtes confus par rapport au fait que j’ai choisi plusieurs algorithmes pour “encryption et integrity” rendez-vous dans la FAQ en fin d’article
Divers (IP endpoint/peer/node & IKEv2 Pre-Shared key)
tunnel-group 10.10.10.10 type ipsec-l2l
tunnel-group 10.10.10.10 general-attributes
default-group-policy .DefaultS2SGroupPolicy
tunnel-group 10.10.10.10 ipsec-attributes
ikev2 remote-authentication pre-shared-key *****
ikev2 local-authentication pre-shared-key *****
Configuration sur linux
Strongswan
/etc/strongswan/ipsec.conf
config setup
uniqueids=yes
charondebug="all"
conn centos-to-ftd
type=tunnel
auto=start
keyexchange=ikev2
authby=secret
left=10.10.10.10
leftsubnet=0.0.0.0/0
right=20.20.20.20
rightsubnet=0.0.0.0/0
ike=aes256-sha256-modp2048!
esp=aes256-sha256!
aggressive=no
keyingtries=%forever
ikelifetime=28800s
lifetime=3600s
dpddelay=30s
dpdtimeout=120s
dpdaction=restart
mark=51 #tagging de taffic avec vti
Les champs importants
- left : l’IP publique de votre machine linux
- right : l’IP publique de votre FTD
- ike : La suite crypto de la phase 1 (voir FAQ)
- esp : La quite crypto de la phase 2
- ikelifetime : le temps avant renegotiation de la phase 1
- lifetime : le temps avant renegotiation de la phase 2 (IpSec)
- mark : ID pour associer la connexion VPN à la VTI
- leftsubnet et rightsubnet : traffic selector, normalement utilisé pour un policy-based VPN. Attention : Ces valeurs doivent être identiques avec le traffic selector de l’autre endpoint (FTD). voir FAQ
/etc/strongswan/ipsec.secrets
10.10.10.10 20.20.20.20 : PSK "*******************************"
La clé pré-partagée qui sera utilisée pour un duo de endpoint.
/etc/strongswan/strongswan.d/charon.conf
[...]
install_routes = no
[...]
install_routes installera implicitement une route redirigeant les paquets matchant le “traffic selector” dans le VPN. C’est indispensable pour un “policy-based” VPN, mais pour notre cas (route-based VPN) c’est déconseillé. (à voir ce qu’il se passe ???)
Il faut décommenter cette ligne et spécifier “no” dans le cas d’un route-based VPN.
Création tunnel VTI
[root@labfabear ~]# ip tunnel add tunnel1 local 10.10.10.10 remote 20.20.20.20 mode vti key 51
[root@labfabear ~]# ip addr add 169.254.51.1 remote 169.254.51.2 dev tunnel1
[root@labfabear ~]# ip link set tunnel1 up
On crée la VTI qui va être utilisée comme passerelle pour envoyer/recevoir des paquets vers/depuis le VPN. La valeur après “key” doit matcher celle qui a été mise après “mark” dans le fichier /etc/strongswan/ipsec.conf On spécifie ensuite l’IP de la VTI locale (169.254.51.1), ainsi que l’IP de la VTI du FTD (169.254.51.2). Pour finir on active l’interface de la VTI.
Tests
Linux
Assurez-vous que le VPN est établi correctement :
[root@labfabear ~]$ strongswan status centos-to-ftd
Security Associations (1 up, 0 connecting):
centos-to-ftd[419]: ESTABLISHED 58 minutes ago, 10.10.10.10[10.10.10.10]...20.20.20.20[20.20.20.20]
centos-to-ftd{1989}: INSTALLED, TUNNEL, reqid 310, ESP SPIs: cc96ad4b_i 2be16903_o
centos-to-ftd{1989}: 0.0.0.0/0 === 0.0.0.0/0
Note: Ne faites pas confiance à cette commande à 100%, j’en repalerai plus bas dans la FAQ, mais il se peut que la commande indique que le tunnel est “ESTABLISHED” alors que ça n’est pas le cas.
Un simple ping de la VTI du FTD depuis notre machine linux devrait pouvoir confirmer le bon fonctionnement du VPN
[root@labfabear ~]$ ping 169.254.51.2
PING 169.254.51.2 (169.254.51.2) 56(84) bytes of data.
64 bytes from 169.254.51.2: icmp_seq=1 ttl=255 time=6.44 ms
64 bytes from 169.254.51.2: icmp_seq=2 ttl=255 time=6.58 ms
64 bytes from 169.254.51.2: icmp_seq=3 ttl=255 time=6.44 ms
64 bytes from 169.254.51.2: icmp_seq=4 ttl=255 time=6.48 ms
On peut également afficher les statistiques de la VTI pour confirmer qu’il y a bien des données échangées
[root@labfabear ~]$ ip -s tunnel show tunnel1
tunnel1: ip/ip remote 20.20.20.20 local 10.10.10.10 ttl inherit key 51
RX: Packets Bytes Errors CsumErrs OutOfSeq Mcasts
839372 574373326 296 0 0 0
TX: Packets Bytes Errors DeadLoop NoRoute NoBufs
601756 50634978 4178 0 4178 0
FTD
Coté FTD, un simple ping peut également confirmer le bon fonctionnement du VPN.
> ping 169.254.51.1
Please use 'CTRL+C' to cancel/abort...
Sending 5, 100-byte ICMP Echos to 169.254.51.1, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/6/10 ms
>
Pour des statistiques, la commande ‘show vpn-sessiondb l2l’ est utile. Attention : Le profile VPN ne sera affiché que lorsque des données auront commencé à transiter dans le tunnel VPN. C’est pour cette raison que faire un ping en amont peut-être utile pour “amorcer” la construction du tunnel VPN (dans une configuration de base le tunnel VPN ne sera pas en ligne tant qu’aucune donnée n’a tenté de l’emprunter).
> show vpn-sessiondb l2l
Session Type: LAN-to-LAN
Connection : 10.10.10.10
Index : 4804 IP Addr : 10.10.10.10
Protocol : IKEv2 IPsec
Encryption : IKEv2: (1)AES256 IPsec: (1)AES256
Hashing : IKEv2: (1)SHA256 IPsec: (1)SHA1
Bytes Tx : 29310 Bytes Rx : 15163
Login Time : 11:51:42 CEST Wed Aug 17 2022
Duration : 1h:06m:16s
Tunnel Zone : 0
Conclusion
Nous avons donc construit un VPN (routed-based) fonctionnel, mais pour l’instant il n’est pas très utile qu’il n’existe aucune route pour envoyer des données à travers. A ce stade du déploiement on pourrait simplement rajouter des routes statiques sur le FTD et la machine linux avec pour gateway leurs VTI respectives, mais je vous propose de propager les routes en utilisant BGP à la place.
Voir Partie 2 : Mise en place de BPG à travert un tunnel VPN FTD<->Linux
FAQ
Q : Est-il possible de mélanger route-based et policy based ?
Je me suis la question de mettre un traffic selector plus restrictif que 0.0.0.0/0 au niveau de strongswan. Pas dans l’idée que ça change la table de routage (puisque j’ai désactivé la fonctionnalité de Strongswan de rajouter des routes [install_routes = no], mais plutôt pour filtrer le traffic. Pour faire un test, j’ai changé l’encryption domain coté Strongswan :
/etc/strongswan/ipsec.conf
[...]
conn centos-to-ftd
[...]
left=10.10.10.10
leftsubnet=192.168.51.157/32,169.254.52.1/32 #encryption domain
right=20.20.20.20
rightsubnet=0.0.0.0/0
[...]
Après relancement du service strongswan, le resultat de la commande strongswan status centos-to-ftd laisse penser que tout va bien.
[root@labfabear strongswan]# strongswan status centos-to-ftd
Security Associations (1 up, 0 connecting):
centos-to-ftd[2]: ESTABLISHED 31 seconds ago, 10.10.10.10[10.10.10.10]...20.20.20.20[20.20.20.20]
centos-to-ftd{2}: INSTALLED, TUNNEL, reqid 1, ESP SPIs: cf989189_i fb6aa0e7_o
centos-to-ftd{2}: 169.254.52.1/32 192.168.51.157/32 === 0.0.0.0/0
Mais en réalité, le tunnel ne se monte pas et on peut voir dans /var/log/messages le message suivant :
Aug 20 12:22:31 labfabear charon: 09[CFG] selected proposal: IKE:AES_CBC_256/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/MODP_2048 [0/1927]
Aug 20 12:22:31 labfabear charon: 09[IKE] authentication of '10.10.10.10' (myself) with pre-shared key
Aug 20 12:22:31 labfabear charon: 09[IKE] establishing CHILD_SA centos-to-ftd{1}
Aug 20 12:22:31 labfabear charon: 09[ENC] generating IKE_AUTH request 1 [ IDi N(INIT_CONTACT) IDr AUTH SA TSi TSr N(MOBIKE_SUP) N(ADD_4_ADDR) N(ADD_4_ADDR) N
(ADD_4_ADDR) N(EAP_ONLY) N(MSG_ID_SYN_SUP) ]
Aug 20 12:22:31 labfabear charon: 09[NET] sending packet: from 10.10.10.10[4500] to 20.20.20.20[4500] (320 bytes)
Aug 20 12:22:31 labfabear charon: 10[NET] received packet: from 20.20.20.20[4500] to 10.10.10.10[4500] (160 bytes)
Aug 20 12:22:31 labfabear charon: 10[ENC] parsed IKE_AUTH response 1 [ V IDr AUTH N(TS_UNACCEPT) ]
Aug 20 12:22:31 labfabear charon: 10[IKE] authentication of '20.20.20.20' with pre-shared key successful
Aug 20 12:22:31 labfabear charon: 10[IKE] IKE_SA centos-to-ftd[1] established between 10.10.10.10[10.10.10.10]...20.20.20.20[20.20.20.20]
Aug 20 12:22:31 labfabear charon: 10[IKE] scheduling reauthentication in 28087s
Aug 20 12:22:31 labfabear charon: 10[IKE] maximum IKE_SA lifetime 28627s
Aug 20 12:22:31 labfabear charon: 10[IKE] received TS_UNACCEPTABLE notify, no CHILD_SA built
Aug 20 12:22:31 labfabear charon: 10[IKE] failed to establish CHILD_SA, keeping IKE_SA
La problème (TS_UNACCEPTABLE) vient du fait que pour que la phase1 du vpn fonctionne, il faut que l’encryption domain soit le même des deux cotés. Mais sur le FTD, l’encryption domain ressemble à ça :
IKEv2 SAs:
Session-id:11917, Status:UP-ACTIVE, IKE count:1, CHILD count:1
Tunnel-id Local Remote Status Role
1311346589 20.20.20.20/4500 10.10.10.10/4500 READY RESPONDER
Encr: AES-CBC, keysize: 256, Hash: SHA256, DH Grp:14, Auth sign: PSK, Auth verify: PSK
Life/Active Time: 86400/2312 sec
Child sa: local selector 0.0.0.0/0 - 255.255.255.255/65535
remote selector 0.0.0.0/0 - 255.255.255.255/65535
ESP spi in/out: 0xc26e770e/0xcd7cb8a9
0.0.0.0/0 en left et right. Je n’ai pas trouvé comment changer le traffic selector sur le FTD lorsque le VPN est reglé en “Route-Based”.
Q : Pourquoi y a-t-il plusieurs algorithmes encryption/integrity dans la partie IPSec du VPN FTD
C’est une partie de la configuration que je n’ai jamais modifié, quand j’ai commencé à configurer le VPN FTD je ne savais pas encore ce que pouvais gérer Strongswan comme algorithmes, j’en ai donc mis plusieurs. Mais au final, pas d’inquiètude, les deux endpoint vont séléctionner l’algorithmes le plus sécurisé qu’ils ont en commun.
Pour FTD : Encryption (aes-256 aes-192 aes) / Integrity (sha-512 sha-384 sha-256 sha-1) Pour Strongswan : Encryption (aes256) Integrity (sha256)
Encryption | Integrity | |
---|---|---|
FTD | aes-256aes-192aes | sha-512sha-384sha-256sha-1 |
Strongswan | aes256 | sha256 |
Et c’est effectivement ce que va choisir strongswan :
[root@labfabear strongswan]# grep -i "selected proposal" /var/log/messages | tail -n 1
Aug 20 17:53:27 labfabear charon: 09[CFG] selected proposal: ESP:AES_CBC_256/HMAC_SHA2_256_128/NO_EXT_SEQ
[root@labfabear strongswan]#