05
2024
01
00:44:38

[Router] 一个略显"奇怪"的IPSec VPN配法

提示

本文所述为企业互连分支,云,内部服务所使用的合法VPN技术,并非所谓的加速/科学上网类教程,也请不要在评论区传播违反法律规定的加速器和VPN

引言

网工在运维工作中经常碰到的一项任务就是——配IPSec VPN。对于很多图形化设备来说,这并不是难事,但这些设备的功能繁杂,配置方式各异,而且不成系统,很难进行标准化——标准化也就是我在这个地方这样设计了,在另一个地方我可以直接复制,复制,再复制,甚至可以自动化。

当我想要把IPSec VPN作为一种线路接入或者线路备份的方式引入网络,尽可能减少网络中提供接入的设备类型和数量,并且还要提供自动化的可能性的时候,在有着相对完善的CLI和API的企业级路由器和防火墙上配置IPSec VPN就成了绕不开的场景了。

我所运维的网络中目前辛勤工作着的防火墙,Cisco ASA更精于NAT和四层策略,IPSec VPN的配置并不算非常灵活,至少有一点很难忍,就是它没有虚拟隧道接口(VTI)的概念,选路能力也比路由器略差一些,而在连接其它机房/公有云甚至第三方的时候,选路恰好是我们非常在意的一件事。在纯专线或者MPLS接入的场景中,Router可以很好的完成选路,而在IPSec VPN场景中,Cisco Router的表现也不错——如果不考虑shit一样的Configuration Guide这种人为灾难的话。

P.S. 纵然你的Feature足够多,配置足够灵活,没有一个好的"说明书",又有什么用呢?下文所讲到的Cisco Router的IPSec VPN配置方式,如果不是之前测试IWAN捣鼓了很久,光看那残疾的CFG,是真的摸不到门路。

需求

我所维护的网络,配置IPSec VPN,除了基本的连接性之外,还会考虑以下几点——

  • 不考虑增加新设备/新区域,这会带来额外的路由调优工作

  • 尽量不要在承担了网络访问策略的节点上做这件事

  • 隔离底层承载网络,即Internet或者专线应该被关在一个封闭的路由表中

要同时实现上述需求,网络中已有的Cisco Router反而成了最好的选择,因为它——

  • 本就是DC边界承担互连,选路的设备

  • 纯路由,无策略

  • FVRF可以实现底层承载网络和业务网络的隔离


问题

在选定用路由器来配置IPSec VPN后,第一个难题就出现了——我要把承载网络隔离出去,就要有个虚拟的隧道接口放在业务网络中,但如果对端没有虚拟隧道接口怎么办?我过去所接触的VPN方案都比较封闭,DMVPN/FlexVPN在解决方案的构建上从来就没考虑过让你和其它厂商的设备去对接,mGRE/NHRP这些东西好是好,但是局限性太大。

就眼下来说,我要在Cisco Router和阿里云之间配置IPSec VPN——这其实也是被逼无奈,阿里云不支持虚拟路由,不然我一定会选择CSR1000v去起一个GRE over IPSec的。

P.S. 这里提一下Fortinet,Fortinet为了让自己的防火墙在阿里云上工作真的是煞费苦心,先是开发了单播HA的Feature以利用阿里云的HAVIP来实现HA,谁曾想阿里云居然把HAVIP这个功能下线了(研发心里苦,这上哪说理去),然后Fortinet的工程师告诉我,他们有新的操作,他们利用ENI(弹性网卡)又开发了一版HA Feature,让人忍俊不禁的是,这个Feature的名字就叫alicloud-ha……C记真应该好好跟人家学学,不要做什么事都问能卖多少数,这个时代是你先有了东西,客户才会选择你,而不是因为客户都在买,你才考虑去做。

而阿里云自身的VPN网关以及IPSec连接,呵,虽然号称是“route-based”但是并没有考虑弄一个“route interface”出来,更准确地说,猫厂理解的“route-based”好像是指从VPN网关到内部VPC是“routing”的……

可能反而是各路国产防火墙和猫厂的思路更接近一些……

从实际的情况来看,猫厂所支持的IPSec VPN就是最普通的IPSec VPN,tunnel模式那种,所以我在路由器这端也要配置这种VPN。我Google和百度了很多文章,都没找到在路由器上配置“带VTI接口的普通IPSec VPN”的配法,最后还是从以往的经验中得到启发,从原理入手,小小魔改了一下原先IWAN中的VPN配置,实现了“既有可路由的VTI接口,同时又是个普通的IPSec,还能用上FVRF”这件事……

P.S. VTI,Virtual Tunnel Interface,虚拟隧道接口,其实就是你敲的 interface Tunnel啦……

再P.S. 传统的IPSec VPN的配法网上有很多,这里就不赘述了


测试拓扑

测试拓扑很简单,三台路由器连在一起

R1---R2---R3

其中R2和R3之间的链路模拟了现网中的运营商网络,我们假设R1和R2,与R2和R3在路由上是不通的,我还把R2和R3互连的接口扔进了VRF,也就是Cisco所说的FVRF,Front-door VRF,接下来你还会经常看到这个词。


配置——IKEv2

这里所写出的配法从IWAN的IPSec配法魔改而来,其实是Cisco本来就支持的配置方式,只是没有什么正儿八经的文档讲清楚过。CFG写的真的是惨不忍睹。

因为我打算把IPSec VPN工作的接口扔在VRF里,所以我们也就必须要先建立一个VRF——

vrf definition WAN
 !
 address-family ipv4
 exit-address-family

然后配置一阶段,IKEv2的proposal和policy

crypto ikev2 proposal TEST 
 encryption aes-gcm-256
 prf sha512
 group 19
crypto ikev2 policy TEST 
 match fvrf any
 proposal TEST

encryption aes-cbc-256 配置加密方式,integrity sha512 配置认证方式,group 14 配置DH,这三个属性要和对端完全一致,否则第一阶段协商无法完成。

你可以看到 ikev2 policy 子配置中是有 fvrf 的,不过这里我们并不配置它,因为我并不想每次换不同的物理接口和 fvrf 的时候都去配置一遍 policy,我尽可能想要复用这部分配置。

然后配置 ikev2 keyring 和 ikev2 profile,这里的配置就会去关联fvrf 了,限制第一阶段协商发生的区域。

crypto ikev2 keyring TEST
 peer ANY
  address 0.0.0.0 0.0.0.0
  pre-shared-key CISCO
crypto ikev2 profile TEST
 match fvrf WAN
 match identity remote address 0.0.0.0 
 identity local address 10.90.2.1
 authentication remote pre-share
 authentication local pre-share
 keyring local TEST

需要说明的是,除非你是面对多个远端站点,否则你不应该配置 match identity remote address 0.0.0.0,该限制还是要限制的,这里仅供参考!

P.S. 在生产环境中,我也限制了阿里云的VPN网关的IP地址,来和我的路由器建立VPN

再P.S. match identity remote address 应该是可以写多行的,不过我还没有试过

ikev2 profile里关联了VRF,因为我们把物理接口放在了一个VRF当中,这里其实是可以写ANY的,当你有多个不同的运行商线路接在路由器上的时候, 为了解决多运营商选路的问题,一个比较好的做法就是每个接口一个VRF,名字可以取成CTCU这样的名字,然后如果你通过多个接口去和远端建立隧道,这里就可以考虑写成match fvrf any,毕竟能少配点就少配点……

ikev2 keyring 没有限制ip的原因,主要是考虑到同一个远端可能有多个隧道,这些隧道共享keyring是可以接受的,对不同的远端,可以配置不同的keyring 和 profile 来区分

到这里为止,IKEv2的部分就配完了。


配置——IPSec

crypto ipsec security-association replay window-size 1024
crypto ipsec transform-set TEST esp-aes 256 esp-sha512-hmac 
 mode tunnel
crypto ipsec profile TEST
 set transform-set TEST 
 set ikev2-profile TEST

这部分其实就是第二阶段协商的配置以及最终关联在隧道接口下的profile,注意transform-set,配置了加密和认证方法但是没有配置DH Group , 所以可能的话,你可以考虑禁用掉远端的DH Group 的配置

注意模式,mode tunnel,因为我们直接使用IPSec自带的封装,而不借助其它的封装协议,所以这里一定要是tunnel模式

crypto ipsec profile 没啥好说的,关联对了就行。

重点,VTI接口

请注意,这里的配置很重要,你可能习惯于配一个GRE隧道,但这里的配置有所不同——

interface Tunnel0
 ip unnumbered GigabitEthernet1.902
 ip mtu 1400
 ip tcp adjust-mss 1360
 tunnel source GigabitEthernet1.902
 tunnel mode ipsec ipv4
 tunnel destination 10.90.2.2
 tunnel vrf WAN
 tunnel protection ipsec profile TEST

我们要解决的大部分问题都在这些配置里——

ip unnumbered 由于对端没有虚拟隧道接口,所以本地的隧道接口我也没有配置ip地址,而是用了这条命令去借用物理口的ip,这可以正常工作,但是带来了一点点转控不一致的现象,详见后文拾遗部分的介绍

mtutcp adjust-mss其实并不需要填成这个样子,只是因为是做个实验,我就懒得去算了,就先这么填好了反正可以通……

tunnel mode ipsec ipv4——tunnel mode要改掉,默认是GRE,如果你忘记改了,你会发现你的隧道一直在反复的一阶段或者二阶段协商不成功,而且你还debug不出任何有效的信息……

tunnel vrf WAN 因为物理接口,也就是GigabitEthernet1.902被我放在了VRF当中,所以这里一定要有这么一条配置

最后,tunnel protection ipsec profile TEST 关联好之前创建的接口,配置就完成了。

需要注意,这个IPSec VPN本质上就是普通的IPSec VPN,跑不了组播也就跑不了大部分IGP,当然BGP是单播的,理论上可以通过环回口建立起来。


测试

R2和R3上对着对方照着上面这么配就行了,地址不要填错就好。

show一下测试用的环回口ip和承载IPSec VPN的物理口配置

R2#sh run int lo0
Building configuration...

Current configuration : 63 bytes
!
interface Loopback0
 ip address 2.2.2.2 255.255.255.255
end

R2#sh run int gi1.902
Building configuration...

Current configuration : 142 bytes
!
interface GigabitEthernet1.902
 description outside
 encapsulation dot1Q 902
 vrf forwarding WAN
 ip address 10.90.2.1 255.255.255.252
end

你可以很明显的看到,GigabitEthernet1.902Loopback0不在一个路由表里——前者在名为WAN的VRF里,后者在默认路由表,也就是Global或者说default路由表中

P.S. Globaldefault代表同一个东西,即路由器的默认路由表,又叫全局路由表,我也不知道为什么就变成了两个不同的名字……

因此如果没有隧道打通,或者路由泄露,从2.2.2.2为源访问GigabitEthernet1.902对端的一个ip是永远也不会通的,当然,访问10.90.2.0/30这个网段本身也不会通(因为通过VRF隔离了)

P.S. 路由泄露是不现实的,虽然这里的拓扑R2和R3是直连的,但实际网络中,R2和R3之间可能隔了天涯万里……而且现实中的私网地址本来也不可能在公网上被路由

R2的Global路由为(省略了部分输出)

R2#sh ip route
……
      2.0.0.0/32 is subnetted, 1 subnets
C        2.2.2.2 is directly connected, Loopback0

R2的WAN路由表路由为

R2#sh ip route vrf WAN

Routing Table: WAN
……
      10.0.0.0/8 is variably subnetted, 2 subnets, 2 masks
C        10.90.2.0/30 is directly connected, GigabitEthernet1.902
L        10.90.2.1/32 is directly connected, GigabitEthernet1.902
R3#

R3的Global路由为

R3#sh ip route
……
      3.0.0.0/32 is subnetted, 1 subnets
C        3.3.3.3 is directly connected, Loopback0

R3的WAN路由

R3#sh ip route vrf WAN

Routing Table: WAN
……
      10.0.0.0/8 is variably subnetted, 2 subnets, 2 masks
C        10.90.2.0/30 is directly connected, GigabitEthernet1.902
L        10.90.2.2/32 is directly connected, GigabitEthernet1.902


如果IPSec以及Tunnel的配置没有错误,通过show ip interface brief是可以看到Tunnel0接口正常up起来的,而通过show crypto session可以看到IPSec的协商也将会是正常的

R2#sh ip int br
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       unassigned      YES unset  up                    up      
GigabitEthernet1.901   unassigned      YES unset  up                    up      
GigabitEthernet1.902   10.90.2.1       YES manual up                    up         
Loopback0              2.2.2.2         YES manual up                    up      
Tunnel0                10.90.2.1       YES TFTP   up                    up

P.S. Tunnel0借用了GigabitEthernet1.902的地址,却不会在路由表里加载直连路由。

R2#show crypto session 
Crypto session current status

Interface: Tunnel0
Profile: TEST
Session status: UP-ACTIVE     
Peer: 10.90.2.2 port 500 
  Session ID: 2  
  IKEv2 SA: local 10.90.2.1/500 remote 10.90.2.2/500 Active 
  IPSEC FLOW: permit ip 0.0.0.0/0.0.0.0 0.0.0.0/0.0.0.0 
        Active SAs: 2, origin: crypto map


然后,我们在R2和R3上分别配置对方的测试接口路由,指向Tunnel接口

R2

R2(config)#ip route 3.3.3.3 255.255.255.255 Tunnel0

R3

R3(config)#ip route 2.2.2.2 255.255.255.255 Tunnel0


再来show两侧的路由,只看我们新加的路由——

R2

R2#sh ip route | in 3.3.3.3
S        3.3.3.3 is directly connected, Tunnel0

R3

R3#sh ip route | in 2.2.2.2
S        2.2.2.2 is directly connected, Tunnel0


开启R3上的Telnet,然后分别测试pingtelnet

ping

R2#ping 3.3.3.3 source loopback 0
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 3.3.3.3, timeout is 2 seconds:
Packet sent with a source address of 2.2.2.2 
.!!!!
Success rate is 80 percent (4/5), round-trip min/avg/max = 1/1/2 ms

telnet

R2#telnet 3.3.3.3 /source-interface loopback 0
Trying 3.3.3.3 ... Open

User Access Verification

Username: admin
Password: 
R3>
R3>

实验成功。


拾遗一:ip unnumbered 带来的轻微转控不一致现象

我们来看一些更细节的问题。

由于R2的Global路由表里并没有一个真正的物理接口(物理接口被关在了WAN里),所以通过show ip arp我们看不到任何arp条目,只有show ip arp vrf WAN才能看到熟悉的ARP表

R2#sh ip arp
R2#
R2#sh ip arp vrf WAN
Protocol  Address          Age (min)  Hardware Addr   Type   Interface
Internet  10.90.2.1               -   0050.568a.adad  ARPA   GigabitEthernet1.902
Internet  10.90.2.2               9   0050.568a.278c  ARPA   GigabitEthernet1.902
R2#

这个特征意味着,我们在写路由的时候是不能写下一跳的地址的,如果要写下一跳地址,那么一定要把下一跳绑定到正确的接口上去

先看看写了下一跳会是个什么样子——

R2(config)#ip route 3.3.3.3 255.255.255.255 Tunnel0 10.90.2.2

P.S. 既然Tunnel0是借用的地址,下一跳自然也要指向对端的借用的物理ip上去,逻辑没问题,但是这个操作是要出事情的

此时,路由会发生一些变化——

R2#sh ip route | in 3.3.3.3
S        3.3.3.3 [1/0] via 10.90.2.2, Tunnel0

更直接的变化要通过CEF才能看出—

R2#sh ip cef 3.3.3.3
3.3.3.3/32
  nexthop 10.90.2.2 Tunnel0
R2#sh ip cef 10.90.2.2
0.0.0.0/0
  no route

可以看到,10.90.2.2在转发上被绑定到了0.0.0.0/0上去,如果存在一条默认路由,比如说我写了这样一条路由指向另一个路由器——

R2# do show run | s ip route
ip route 0.0.0.0 0.0.0.0 10.90.1.1

这时候cef表里就会出现比较有趣的现象——

R2(config)#do show ip cef 3.3.3.3
3.3.3.3/32
  nexthop 10.90.2.2 Tunnel0
R2(config)#do show ip cef 10.90.2.2
0.0.0.0/0
  nexthop 10.90.1.1 GigabitEthernet1.901

更有趣的是,实际转发的时候,由于IPSec VPN的存在,数据包会"先一步"被封装到IPSec隧道中,而并不会受到诡异转发表的影响

R2(config)#do show ip cef 3.3.3.3
3.3.3.3/32
  nexthop 10.90.2.2 Tunnel0
R2(config)#do show ip cef 10.90.2.2
0.0.0.0/0
  nexthop 10.90.1.1 GigabitEthernet1.901
R2(config)#
R2(config)#do ping 3.3.3.3 so lo 0
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 3.3.3.3, timeout is 2 seconds:
Packet sent with a source address of 2.2.2.2 
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/1 ms
R2(config)#

我并不知道这个诡异的转发表什么时候会抽一下,但有一点可以肯定,转发平面和控制平面存在不一致,一定是一件不好的事,所以,如果你一定要闲的蛋疼在这种情况下的路由里加一条没什么用的nexthop,就一定不要忘记把下一跳绑定到正确的出接口,以免在某个时间被Gank一波

ip route 10.90.2.0 255.255.255.252 GigabitEthernet1.902

R2#show ip cef 10.90.2.2
10.90.2.2/32
  attached to GigabitEthernet1.902

另外,这个诡异的现象的根源还是在于,在这个场景中,我既为了安全而隔离了隧道接口和物理接口,同时隧道接口又没有配置IP地址,如果隧道接口有一个虚的IP地址,这个现象就不会出现了,因为虚的IP地址存在于Global路由表,路由器可以正常的进行路由递归。

最好的办法,当然是不写下一跳,因为这种情况下,下一跳已经没有意义,能通的前提是IPSec隧道正常建立,而隧道如果不正常,我们也不会希望流量往隧道上跑。


拾遗二:感兴趣流?

在生产的配置中,我意外的发现,这个配置下,感兴趣流 似乎 仍然是有效的。为了确保流量都能经过隧道进行转发,在对端的阿里云的配置中,我把感兴趣流的配置,配成了0.0.0.0/0 -- 0.0.0.0/0,我并不非常确定是否是感兴趣流造成了 不通,但确实在我这么配置之前,流量的转发是有问题的。

仔细考虑过后,发现这么配置对于 route-based 模式的IPSec VPN来说是可以接受的,因为流量在进入隧道前首先受到的是路由选择 的影响——这在阿里云和本地路由器上都是这样子。

只有被路由到隧道接口的流量,才会经由隧道转发。看起来,感兴趣流仍然起作用,所以如果我配置成全0,也就意味着我不依赖感兴趣流去检查流量是否被封装了。

阿里云上的感兴趣流配置




推荐本站淘宝优惠价购买喜欢的宝贝:

image.png

本文链接:https://hqyman.cn/post/4774.html 非本站原创文章欢迎转载,原创文章需保留本站地址!

分享到:
打赏





休息一下~~


« 上一篇 下一篇 »

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

请先 登录 再评论,若不是会员请先 注册

您的IP地址是: