加密GRE隧道, GRE over IPSec以及IPSec over GRE

上一篇Linux的gre隧道 讲到GRE隧道, 但是GRE是明文传输的, 有一定的安全隐患, 于是需要进行加密处理, 加密一般有两个, GRE over IPSec和IPSec over GRE

两者的区别是, GRE over IPSec是先将数据封装成GRE协议, 再通过IPSec隧道加密传输, 对于外界来说, 看到的都是ESP加密数据包, 并不知道内部是什么, 当然也不知道你内部是GRE.
而IPSec over GRE是先将数据用IPSec加密, 再通过GRE隧道出去, 对于外界来说, 知道你是用GRE传输的, 但是传输的是什么就不知道了, 看到的都是ESP

这里用的是Centos+libreswan来做IPSec, 当然也可以用strongswan/openswan什么的. 原理都是一样的

Server A:
IP: 1.0.0.4
GRE IP: 10.0.0.1

Server B:
IP: 1.0.0.5
GRE IP: 10.0.0.2

首先在两台服务器上都安装libreswan

yum install -y libreswan

装好之后都要执行一下

ipsec initnss

接下来生成rsa密钥对. 在两台server上都执行

ipsec newhostkey

这需要一些时间

GRE over IPsec

在Server A上运行

ipsec showhostkey --left

可以看到类似这样的输出:

ipsec showhostkey loading secrets from "/etc/ipsec.secrets"
    # rsakey AQOcq+xzO 
    leftrsasigkey=0sAQOcq+xzOPYivlZ8kXvALHTJhWwH2IluTzlOOuKiSvP0RDFPHzKBYgse9tT........

然后我们复制leftrsasigkey以及后面的一大串到剪切板备用

之后编辑

/etc/ipsec.d/ipsec.conf

这个文件默认是不存在的, 直接创建就可以了, 然后加入以下内容

config setup
    protostack=netkey

conn gre1
    left=1.0.0.4
    right=1.0.0.5
    authby=rsasig
    auto=start
    leftprotoport=gre
    rightprotoport=gre
    type=transport
    leftrsasigkey=0sAQOcq+xzOPYivlZ8kXvALHTJhWwH2IluTzlOOuKiSvP0RDFPHzKBYgse9tT........

然后不要关闭编辑这个文件, 同时你应该知道为什么要把刚刚的一大串复制备用了吧. 接着在Server B上执行

ipsec showhostkey --right

注意是–right, 同时也把rightrsasigkey和后面的一串复制给Server A上的ipsec.conf后, 跟着leftrsasigkey另起一行, 最后的文件内容类似与

conn gre1
    left=1.0.0.4
    right=1.0.0.5
    authby=rsasig
    auto=start
    leftprotoport=gre
    rightprotoport=gre
    type=transport
    leftrsasigkey=0sAQOcq+xzOPYivlZ8kXvALHTJhWwH2IluTzlO........
    rightrsasigkey=0sAQPiT6xbnBMuPLbXxfT3iQ9yDhlD4U7FdqOR......

然后在Server B上也创建同样的ipsec.conf文件, 并且内容和Server A上是ipsec.conf差不多, 只不过是把left和right对调一下, 也就是:

conn gre1
    left=1.0.0.5
    right=1.0.0.4
    authby=rsasig
    auto=start
    leftprotoport=gre
    rightprotoport=gre
    type=transport
    leftrsasigkey=0sAQPiT6xbnBMuPLbXxfT3iQ9yDhlD4U7FdqOR......
    rightrsasigkey=0sAQOcq+xzOPYivlZ8kXvALHTJhWwH2IluTzlO........

特别需要注意leftrsasigkey和rightrsasigkey的内容也要调换!

然后启动ipsec服务, 在两台Server 上都执行

systemct start ipsec

启动成功后在Server A上ping Server B的GRE IP

ping 10.0.0.2

如果能成功ping 通, 那基本就成功了, 此时在Server B上用tcpdump看下包

先看enp0s3上的包

tcpdump -nn -i enp0s3

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s3, link-type EN10MB (Ethernet), capture size 65535 bytes
22:44:37.448828 IP 1.0.0.5 > 1.0.0.4: ESP(spi=0x2cf3f2c6,seq=0x9), length 132
22:44:37.449159 IP 1.0.0.4 > 1.0.0.5: ESP(spi=0x3c9c7eb2,seq=0x9), length 132
22:44:38.450729 IP 1.0.0.5 > 1.0.0.4: ESP(spi=0x2cf3f2c6,seq=0xa), length 132

可以看到数据是ESP加密的, 然后再看看gre1上的包

tcpdump -nn -i gre1

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on gre1, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
22:45:40.492113 IP 10.0.0.2 > 10.0.0.1: ICMP echo request, id 3800, seq 64, length 64
22:45:40.492174 IP 10.0.0.1 > 10.0.0.2: ICMP echo reply, id 3800, seq 64, length 64
22:45:41.492888 IP 10.0.0.2 > 10.0.0.1: ICMP echo request, id 3800, seq 65, length 64
22:45:41.492910 IP 10.0.0.1 > 10.0.0.2: ICMP echo reply, id 3800, seq 65, length 64

gre1上的包已经是明文了.

但是当我们在Server A上直接ping Server B是1.0.0.5 ip, 在enp0s3上看到是明文的ICMP echo包, 这说明了IPSec仅作用于gre协议上, 这实际是leftprotoport和rightprotoport起的作用.
如果没有指定这两个参数, 那你ping 1.0.0.5的ip的时候也会被IPSec加密.

IPSec over GRE

这里和上面是配置文件区别在于

去掉了leftprotoport, rightprotoport, type. 同时left和right都改成gre ip, 而不是公网ip

也就是配置文件类似于

conn gre1
    left=10.0.0.1
    right=10.0.0.2
    authby=rsasig
    auto=start
    leftrsasigkey=0sAQPiT6xbnBMuPLbXxfT3iQ9yDhlD4U7FdqOR......
    rightrsasigkey=0sAQOcq+xzOPYivlZ8kXvALHTJhWwH2IluTzlO........

注意, 此处的left和right分别是Server A和Server B在GRE 隧道上的IP, 同时需要注意Server A和Server B是left和right的值需要相对应.

其他的部分都是一样的. 包括key什么的.

当配置好之后, 启动IPSec或者重启IPSec服务

然后我们继续在Server A上不间断的ping Server B的GRE IP

ping 10.0.0.2

在Server B上tcpdump查看enp0s3上的数据包

 tcpdump -nn -i enp0s3

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s3, link-type EN10MB (Ethernet), capture size 65535 bytes
22:56:57.936479 IP 1.0.0.5 > 1.0.0.4: GREv0, length 156: IP 10.0.0.2 > 10.0.0.1: ESP(spi=0x538dedb6,seq=0x5), length 132
22:56:57.936578 IP 1.0.0.4 > 1.0.0.5: GREv0, length 156: IP 10.0.0.1 > 10.0.0.2: ESP(spi=0x0d038130,seq=0x5), length 132
22:56:58.936917 IP 1.0.0.5 > 1.0.0.4: GREv0, length 156: IP 10.0.0.2 > 10.0.0.1: ESP(spi=0x538dedb6,seq=0x6), length 132
22:56:58.937212 IP 1.0.0.4 > 1.0.0.5: GREv0, length 156: IP 10.0.0.1 > 10.0.0.2: ESP(spi=0x0d038130,seq=0x6), length 132

我们可以看到Server A和Server B之间公网IP的数据是通过GRE协议传输的, 同时GRE的两端是GRE IP, 但是具体这两个GRE IP在传输什么是无法被外界获取的, 都是ESP加密过的了.

特殊NAT情况

有时候会遇到Server处在NAT后方, 但是Server在NAT上有一对一的对应IP, 比如腾讯云的情况

腾讯云的Server的公网IP并不是直接绑在Server的网卡上的, 而是在一个NAT上的.

举个例子来说, 我腾讯云公网IP是1.2.3.4, 但是我在Server上用ip addr看到的eth0的IP却是这样的:

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
 link/ether 52:54:00:d4:6f:3a brd ff:ff:ff:ff:ff:ff
 inet 10.104.224.4/18 brd 10.104.255.255 scope global eth0
 valid_lft forever preferred_lft forever

可以看到网卡上的IP是内网的10.104.224.4, 这种情况下IPSec over GRE是不受影响的, 但是按照上面的思路缺无法建立GRE over IPSec

假设有这么一个上述的Server C,
公网IP是1.2.3.4
网卡上绑定是: 10.1.0.0.1

要和Server A建立GRE over IPSec, 当你Server C上这么配置的时候

conn gre1
 left=1.2.3.4
 right=1.0.0.4
 authby=rsasig
 auto=start
 leftprotoport=gre
 rightprotoport=gre
 type=transport
 leftrsasigkey=0sAQPiT6xbnBMuPLbXxfT3iQ9yDhlD4U7FdqOR......
 rightrsasigkey=0sAQOcq+xzOPYivlZ8kXvALHTJhWwH2IluTzlO........

启动IPSec服务的时候, 在Server C上会看到类似这样的错误

022 "gretx": We cannot identify ourselves with either end of this connection. 1.2.3.4 or 1.0.0.4 are not usable

因为Server C上并没有绑定1.2.3.4这个IP, IPSec服务就无法在1.2.3.4这个IP上监听了.

而当你把Server  C上的left改成10.1.0.0.1之后, Server C虽然可以启动IPSec了, 但是Server A上又会报这样的错误:

003 "gretx" #1: NAT-Traversal: Result using RFC 3947 (NAT-Traversal) sender port 500: peer behind NAT
002 "gretx" #1: transition from state STATE_MAIN_I2 to state STATE_MAIN_I3
108 "gretx" #1: STATE_MAIN_I3: sent MI3, expecting MR3
003 "gretx" #1: received Vendor ID payload [CAN-IKEv2]
002 "gretx" #1: Main mode peer ID is ID_IPV4_ADDR: '10.1.0.0.1'
003 "gretx" #1: we require IKEv1 peer to have ID '1.2.3.4', but peer declares '10.1.0.0.1'
218 "gretx" #1: STATE_MAIN_I3: INVALID_ID_INFORMATION
002 "gretx" #1: sending encrypted notification INVALID_ID_INFORMATION to 1.2.3.4:4500

注意看倒数第三行的错误, Server A要求对端(也就是Server C)返回的ID是1.2.3.4, 但实际上Server C返回的却是10.1.0.0.1, 这是因为Server C在启动IPSec服务的时候, 监听了10.1.0.0.1这个IP, 但是正常情况下应该是要监听1.2.3.4, 然而1.2.3.4也无法监听.

解决办法就是: 在Server C的ipsec.conf里面加上一个leftid字段, 值是1.2.3.4, 也就是Server C的实际公网IP

Server C的正确配置像这样:

conn gre1
    left=%defaultroute
    right=1.0.0.4
    authby=rsasig
    auto=start
    leftprotoport=gre
    rightprotoport=gre
    type=transport
    leftrsasigkey=0sAQPiT6xbnBMuPLbXxfT3iQ9yDhlD4U7FdqOR......
    rightrsasigkey=0sAQOcq+xzOPYivlZ8kXvALHTJhWwH2IluTzlO........
    leftid=1.2.3.4

这样就可以顺利的在Server A和C之间建立起GRE over IPSec了

同理就算两台Server都是这种NAT结构, 只需要都增加leftid和rightid就可以解决问题了.

关于 “加密GRE隧道, GRE over IPSec以及IPSec over GRE” 的 9 个意见

  1. 日志是这样的:
    10月 16 20:19:28 greoveripsec-138-7 addconn[2056]: cannot load config ‘/etc/ipsec.conf’: /etc/ipsec.d/ipsec.conf:9: syntax error, unexpected KEYWORD, expecting $end [leftrsasigkey]
    10月 16 20:19:28 greoveripsec-138-7 systemd[1]: ipsec.service: control process exited, code=exited status=3
    10月 16 20:19:28 greoveripsec-138-7 systemd[1]: Failed to start Internet Key Exchange (IKE) Protocol Daemon for IPsec.
    10月 16 20:19:28 greoveripsec-138-7 systemd[1]: Unit ipsec.service entered failed state.
    10月 16 20:19:28 greoveripsec-138-7 systemd[1]: ipsec.service failed.
    10月 16 20:19:28 greoveripsec-138-7 systemd[1]: ipsec.service holdoff time over, scheduling restart.
    10月 16 20:19:28 greoveripsec-138-7 systemd[1]: Starting Internet Key Exchange (IKE) Protocol Daemon for IPsec…

  2. 你好,按照你得方法,IPsec服务起不来,有报错,还请指点。
    ● ipsec.service – Internet Key Exchange (IKE) Protocol Daemon for IPsec
    Loaded: loaded (/usr/lib/systemd/system/ipsec.service; enabled; vendor preset: disabled)
    Active: failed (Result: start-limit) since 日 2020-10-18 23:43:12 CST; 14s ago
    Docs: man:ipsec(8)
    man:pluto(8)
    man:ipsec.conf(5)
    Process: 5612 ExecStartPre=/usr/libexec/ipsec/addconn –config /etc/ipsec.conf –checkconfig (code=exited, status=3)

    10月 18 23:43:12 greoveripsec-138-7 systemd[1]: ipsec.service: control process exited, code=exited status=3
    10月 18 23:43:12 greoveripsec-138-7 systemd[1]: Failed to start Internet Key Exchange (IKE) Protocol Daemon for IPsec.
    10月 18 23:43:12 greoveripsec-138-7 systemd[1]: Unit ipsec.service entered failed state.
    10月 18 23:43:12 greoveripsec-138-7 systemd[1]: ipsec.service failed.
    10月 18 23:43:12 greoveripsec-138-7 systemd[1]: ipsec.service holdoff time over, scheduling restart.
    10月 18 23:43:12 greoveripsec-138-7 systemd[1]: start request repeated too quickly for ipsec.service
    10月 18 23:43:12 greoveripsec-138-7 systemd[1]: Failed to start Internet Key Exchange (IKE) Protocol Daemon for IPsec.
    10月 18 23:43:12 greoveripsec-138-7 systemd[1]: Unit ipsec.service entered failed state.
    10月 18 23:43:12 greoveripsec-138-7 systemd[1]: ipsec.service failed.

      1. conn gre1
        authby=rsasig
        auto=start
        type=transport
        left=192.168.88.4
        leftprotoport=gre
        leftrsasigkey=0sAwEAAbVtN2BjwRq9hqtQwTazkEF+kZXWfSBlH/m4KhmPU1a20FipUmqmVlhy/MZn27hMl6aaPP1iXonU4mb3PKCOCDoZJgIU3b7b6Q1uaQGlkXArUIdezHBZ9YUp+Rx676lWjPRJJt5EURUWTEpe5LbPdzrArfn/gfcFMQyhvBCggS60sIBFD/M
        6RUgds2wOKDndG8y89UnRhPiibF1erqb069MTTe2w+nQFAJEsN6SyNEaSUndCbsh1nAB2ETwL1+n3j9662DC7k6wEaF6QY53aNzFPySx7huPLpsP/bibfLLgrSRtffXRNM0rmIbXSIk89iWadjQKoPW5JaovwOCA0Px2UNWCYjnsup/0XfcsZqO+gxQzd1NatNSYE82
        4S0pUHoS37gKKQqKdz/rdI3XdEdIQz3nMSENaU8LA1UmUjUNfmebCaJklKDMsm/+UF3PVPNeGVw7zhyM1B2Qx66MmoHFbSifRVVqVf7vlsURtCnOZ/qViZeswnHLNOW176TlhbX0scIc4ROocBmDnppUflPo/Gj4kSO4zoVHk2P2YjuqVaxElCq1/BBGqZAel74VAMP
        SQwu4yxXkWWm4dRdE/Yw3TtbNMdGAlp6PyeWMIKEMcf85kavpjVT8MXNMDM6LBJpftbQ+izPit/48OaQU0ZVE6LpLK1tvxDyCHj
        right=192.168.88.2
        rightprotoport=gre
        rightrsasigkey=0sAwEAAdZkTtxI8voB7dzi12Vm6S/WCQj/Rx0KvGUQSvnsH4fV7LlZpgss/0IVteZ0QUzUcCGu7TrBnLNPfHiHH5e4u+BSUMXRBtkqiFGZv1NnQ8eIVxj5V1UDOfpfoNyEl4Az7X0pwYuDzpS8A6GiAMCwm30VeXrU7bluS9Zbo
        b7A2hycBPiTTVVyzh4xRtm1bzHD8mIm/zCUpiE6WXLyaEkTRT/+R93WwUPHa7FWBaom5i+Dj50gKa+67Bn/2qqC5FOSlI+QSfJKd0DKOb+kSZNgr0bQaZbHE8MP8Vkt56W/bMDjZa7WGznQEVTsJVPGXTuH6PqFl2SqHpR7DtZjyC+8REU3YxHWC1NoZmZMttW6P/FV
        hQgko9PfVVzfmIj1+xwkDEky7dK40qSmgORnNsqn6fs9NFRywTqMImupf8XOK8HWz4jR3UI2coILXsQMgFV27YzXjFMQXfePdckWrLBORkUt82l69dWjAflyKdqDg/kRYQ6GtWQmjsgM+vHuqAiQ+UEx3WZjdPqCKm+92WmKbIpAWpXA3VXXNnZ8EnkQnpZm5LNYzPr
        Cq52f8F63I69iLQQXgdaSOkZcl8U=

        1. 这两个sigkey的部分是不是换行了?leftrsasigkey的这部分我这里看到的是分成了四行了,应该是一行的。不知道是粘贴到评论的时候换行了还是配置文件就是错误的换行了。

          1. 您好,十分感谢您的回复。我检查过,没有分行。我有几个疑惑:
            1.A设备的leftrsasigkey是否就是B设备的rightrsasigkey?反之亦然?
            2.config setup
            protostack=netkey #这两行是否需要在ipsec.conf中写上?
            3.支持psk吗?是否要配置IKE?
            十分感谢您的解答,如果方便我们可以加联系方式沟通下:qq:119713621,微信:13794413554.可有偿解答,再次感谢。

        2. 是的,对于A设备来说left是自己,right的B,对于B来说,B的right也就是A设备的left。
          另外一点是,配置文件里面除了conn,version,config这几个指令之外,其他的诸如rightrsasigkey这些是以tab开头缩进的,不知道用空格缩进会不会是导致这个的原因。

回复 czz 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注