StrongSwan配置笔记

为啥是StrongSwan

本来我的IPSec一直是用Racoon,最近需要换一台机器,新的机器是Debian 10的系统,居然没有Racoon了……放狗搜了一圈也没找到怎么才能装回去,最后是在Debian的发行说明里提到说Racoon性能不行,推荐用LibreSwan。但是之前我也没听说过这个,只是当年搞FreeBSD的时候见过OpenSwan。于是又去搜了一下这两位,原来OpenSwan已经死了,LibreSwan就是它的继承者,顺便还发现了另一位另起炉灶的StrongSwan,据说更好。于是就来试这个了。

因为搜了半天,顺便也知道为什么这些东西都叫Swan,然而跟天鹅并没有什么关系,原来是缩写:S/WAN……安全广域网。本质上是一个IPSec的实现工具,而IPSec是一个用于实现“虚拟专用网”的技术。

虚拟专用网

由于“虚拟专用网”这个词的敏感性,并且在外行人中存在普遍误解,所以这里就不再提它的英文缩写了。

实现虚拟专用网的方法有很多,早年有“点对点隧道协议”,后来有“开放虚拟专用网”等,然而前者技术已经落后,并且安全性也不太行了,后者则因为某些非技术原因基本没法用,所以早年的技术里只剩下IPSec还用得比较多,而且还在不断发展中。当然现在还有更新的WireGuard,我还没研究过,不提。

坦白说,虽然用了好几年,但是对于IPSec的很多技术细节还是不懂的,当年配置Racoon也是查了很多资料,反复尝试调整了很久的参数才总算配通的,现在真是不想重来,但是技术在发展,过时的东西迟早还是不能用的。

网络结构

说到SWAN的结构,其实最初的需求是用于将两个互不连通的LAN通过安全的隧道经WAN连接起来。

简单地说:

  • LAN1里有一个网关G1连到WAN
  • LAN2里有一个网关G2连到WAN
  • G1和G2之间建立一个加密的通信隧道
  • LAN1可以通过G1-G2连到LAN2里
  • 这时,LAN1里的每一台电脑都相当于在LAN2中

然而我们常用的需求不是这样的,而是这样的:

  • 有多个客户端Cn比如手机、电脑、平板之类
  • 有一个虚拟专用网网关Gv
  • 需要在每个客户端Cn到Gv之间建立隧道,组成一个虚拟局域网LANv(注意:不是三层交换概念中的VLAN)
  • Cn通过Gv接入WAN,即Gv同时也是这个LANv的网关

举个栗子:

  • 有一个客户端C1有一个外网IP:10.1.1.1
  • Gv有一个外网IP:20.2.2.2
  • C1通过虚拟专用网隧道连到Gv
  • Gv给C1分配了一个LANv的IP:192.168.100.10,Gv在这个LANv里的IP是192.168.100.1
  • C1现在就可以通过LANv上网,网关是Gv的IP:192.168.100.1,出口是Gv的外网IP:20.2.2.2

因为结构不同,所以Gv的配置跟G1,G2有很大的不同。这里只讨论Gv的情况。

配置

包括两部分:隧道和NAT。隧道部分就是StrongSwan,NAT部分是iptables。

安装和配置StrongSwan

apt install strongswan

如参考文献1所说,不同的客户端系统对IPSec的实现差异很大,所以配置起来也是很麻烦。还好我只需要考虑iOS和Android,而且新版本的iOS已经支持IKEv2了,所以相对没那么复杂。

不过因为我这里的StrongSwan还是5.7,不支持参考文献2所说的swanctl,只能按旧的方式来配。

加上准备只用Let’s encrypt的证书(单服务端认证),所以按参考文献3和参考文献4的配置来改,不过这两个的配置看上去都是主要考虑windows客户端,所以还需要另外配iOS和Android的。

先配置/etc/ipsec.conf,按相对简单的ikev1-psk-xauth来,这个iOS和Android都支持:

config setup
    uniqueids=never  # 客户端可复用相同ID

conn ikev1_psk_xauth
    keyexchange=ikev1
    fragmentation=yes  # iOS需要
    ike=aes256-sha256-modp1024  # 指定IKE算法,不然一个个协商过去速度太慢
    left=%defaultroute
    leftauth=psk
    leftsubnet=0.0.0.0/0
    right=%any
    rightauth=psk
    rightauth2=xauth
    rightsourceip=10.0.0.0/24
    auto=add

# 用于Windows,改自参考文献3和参考文献4,我没有windows,所以没试,仅供参考,以后有用到再来更新
conn ikev2_pubkey_mschap
    keyexchange=ikev2
    ike=aes256-sha1-modp1024!  # windows7仅支持这个
    esp=aes256-sha1
    fragmentation=yes
    forceencaps=yes
    dpdaction=clear
    dpddelay=300s
    rekey=no  # windows7必须禁用rekey
    left=%defaultroute
    leftauth=pubkey  # 服务端为证书认证
    leftsubnet=0.0.0.0/0
    leftcert=fullchain.pem  # Let's encrypt证书
    right=%any
    rightauth=eap-mschapv2  # 客户端为windows eap认证
    rightsourceip=10.0.0.0/24
    rightsendcert=never  # 服务端和客户端认证方式不同,必须指定此项
    eap_identity=%identity
    # eap_identity=%any  # windows7需要eap标识
    compress=no
    type=tunnel
    auto=add

然后是配置认证密钥和密码等,在ipsec.secrets中:

: RSA privkey.pem  # 服务器证书密钥
: PSK "psk_password"  # PSK密码
user_name : XAUTH "user_password"  # XAUTH用户及密码
user_name : EAP "user_password"  # EAP用户及密码

还要配置一下strongswan.conf,因为它include了strongswan.d/*.conf,所以在这里创建一个charon-myserver.conf:

charon {
    dns1 = 8.8.8.8  # 指定DNS
    dns2 = 208.67.220.220

    # Windows用这个DNS配置
    nbns1 = 8.8.8.8
    nbns2 = 208.67.220.220

    # 现在duplicheck是个插件,所以配置方式跟以前不一样,虽然默认没有加载,还是这样配置一下吧
    plugins {
        duplicheck {
            enable = no
        }
    }
    # 配置日志,但是因为apparmor的存在会导致出错,处理方式见下文
    filelog {
       charonlog {
           path = /var/log/strongswan.charon.log
           time_format = %b %e %T
           default = 1  # 日志这个级别就够了,用2的话会太多
           append = yes
           flush_line = yes
       }
    }
}

由于AppArmor的默认配置问题,上面的配置会导致StrongSwan启动时报日志文件权限错误,所以需要参考文献4处理一下:

运行apparmor_status可以看到/usr/lib/ipsec/charon等程序处于被处理状态,所以需要禁用一下。

ln -s /etc/apparmor.d/usr.lib.ipsec.charon /etc/apparmor.d/disable/
ln -s /etc/apparmor.d/usr.lib.ipsec.stroke /etc/apparmor.d/disable/
apparmor_parser -R /etc/apparmor.d/usr.lib.ipsec.charon
apparmor_parser -R /etc/apparmor.d/usr.lib.ipsec.stroke

现在启动StrongSwan就正常了,检查日志文件看看有没有错误。

证书使用Let’s encrypt,具体获取方法可以参考《HTTPS配置全记录》中HTTPS证书的流程,方法是一样的。

StrongSwan中要使用证书需要链接一下:

cd /etc/ipsec.d/certs
ln -s /etc/letsencrypt/live/your_domain/fullchain.pem
cd /etc/ipsec.d/private
ln -s /etc/letsencrypt/live/your_domain/privkey.pem

另外就是要配置定时更新任务,记得同时重启nginx和strongswan:

certbot renew --quite --deploy-hook "nginx -s reload; systemctl restart strongswan"

配置NAT

如前面所说,StrongSwan只提供了一个连到网关的隧道,还要在网关上配置NAT为客户端提供上网接入。

一般来说按参考文献1中的iptables配置就可以了:

# 改系统参数
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p
# iptables
-A INPUT -p udp --dport 500 -j ACCEPT
-A INPUT -p udp --dport 4500 -j ACCEPT
# 以上在 -A INPUT -j DROP 之前
-A FORWARD -s 10.0.0.0/24 -j ACCEPT
# 以上在 -A FORWARD -j DROP 之前
# 以下在*nat中
-A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE

但是这回不知道为什么不行,后来按参考文献2改了一下才终于可以。

# 系统参数增加:
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
# iptables增加:
# 在INPUT中增加:
-A INPUT -p ah -j ACCEPT
-A INPUT -p esp -j ACCEPT
# 在FORWARD中那句改为下面两句:
-A FORWARD -i eth0 -m policy --dir in --pol ipsec -j ACCEPT
-A FORWARD -d 10.12.0.0/24 -o eth0 -m policy --dir out --pol ipsec -j ACCEPT
# 在nat中加入:
-A POSTROUTING -s 10.12.0.0/24 -o eth0 -m policy --dir out --pol ipsec -j ACCEPT

客户端配置

现在可以试试用手机连接了:

iOS

  • 类型:IPsec
  • 服务器:你的域名
  • 账户:xauth用户名
  • 密码:xauth用户密码
  • 群组名:空
  • 密钥:PSK密码

Android

  • 类型:IPSec Xauth PSK
  • 服务器:你的域名
  • IPSec标识:空
  • IPSec预共享密钥:PSK密码
  • 用户名:xauth用户名
  • 密码:xauth用户密码

推送到[go4pro.org]

参考文献


  1. 使用 Strongswan 架设 Ipsec VPN ↩︎

  2. CentOS 8 使用 Strongswan 搭梯(IPsec IKEv2 VPN) ↩︎

  3. How to Setup IKEv2 VPN Using Strongswan and Let’s encrypt on CentOS 7(中文版↩︎

  4. IKEv2 VPN server with strongSwan and Let’s Encrypt ↩︎