用作实验室内部环境的VPN。
我很喜欢IKEv2的 Traffic Selector Narrowing,这样服务器和客户机可以分别制定策略,
决定到底哪些流量通过IPSec传输。 我不喜欢了……本来路由和 NAT 规则就已经很乱了,
半路杀出来 IPSec,光制定能通的策略就已经非常繁琐……万一出了问题完全不会调试。
看看它能支持多少路由表吧。
在CentOS 7中,原本的ipsec命令似乎改名为strongswan。
zh_CN en_US: Installationsudo yum install -y epel-release
sudo yum install -y strongswan
之所以在自己电脑上装,主要是为了管理PKI。
sudo pacman -S strongswan
见一个非常简单的strongswan pki脚本。
名字里*不要*带点!(’.’)会和swanctl本身的配置解析冲突!
strongswan真的是……选项超多。
- 可以选传统ipsec.conf风格的配置,也可以选最新的stronswan.conf风格,这里选择后者
- 可以选择IKEv1,或者v2,这里选择v2
- 各种认证方式,这里选择和OpenVPN最类似的公钥体系
- 还有很多看不懂的选项……
traffic selector: 用于匹配包的 目标 地址。
Initiator(客户端)和Responder(服务器端)各自可以有 local_ts/remote_ts (Traffic Selector,流选择),而IKEv2规定,最终的IPSec策略是在两者的ts之间取交集 (narrowing),因此可以相对灵活地由客户或者服务器端 配合决定 哪些流量通过IPSec传输。
官方文档说得挺清楚。就是万一ND等本地组播的地址也被Tunnel了,本地端口的 link local 协商会被影响,估计拿不到 fe80**的地址了。解决办法是在 ND 被影响的端加入一 个本地的 connection,盖住 ND 使它不走IPSec
connections {
...
ndp {
children {
ns {
local_ts = ::/0[ipv6-icmp/135]
remote_ts = ::/0[ipv6-icmp/135]
mode = pass
start_action = trap
}
na {
local_ts = ::/0[ipv6-icmp/136]
remote_ts = ::/0[ipv6-icmp/136]
mode = pass
start_action = trap
}
}
}
}
通过IPSec连接访问某些内网,客户访问其它站点不受影响:服务器端不做NAT。但是还是有可能要做端口转发。
connections {
roadwarriors {
version = 2
local_addrs = ip,ip6
pools = v4pool,v6pool
local {
auth = pubkey
certs = server-cert.pem
id = vm0.lab.ivi2.org
}
remote {
auth = pubkey
cacerts = ca-cert.pem
}
children {
net {
local_ts = 172.16.21.0/24
}
}
}
}
pools {
v4pool {
addrs = 172.16.254.0/24
}
v6pool {
addrs = fddc:ffff::0/64
}
}
connections {
lab {
version = 2
vips = 0.0.0.0, ::
remote_addrs = ip,ip6
local {
auth = pubkey
certs = user-cert.pem
id = user
}
remote {
auth = pubkey
cacerts = ca-cert.pem
id = vm0.lab.ivi2.org
}
children {
lab {
remote_ts = 0.0.0.0/0,::/0
start_action = trap
}
}
}
}
首先配置防火墙!
sudo firewall-cmd --zone=public --add-service="ipsec" --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --list-all
注意在 children 配置里没有 start_action,默认为 none 。Responsder 是这样配的。
sudo systemctl enable strongswan-swanctl
sudo systemctl start strongswan-swanctl
# sudo swanctl --load-all
不同的 start_action 行为:
- none: 只加载,等着用 swanctl -i -c children
- trap: 有匹配 children 的流量出现时建立连接(准确说是协商 SA)
- start: 立即建立连接
抓包的方法需要 IPtables 配合。从另一个角度讲,也可以帮助 Debug IPtables 规则。
校园网用的公网IP所以看不出NAT。但是即便使用
connections.<conn>.encap = yes
也没用。忧郁。
默认的 SELinux profile 会导致 strongswan-swanctl 的 systemd service 中,swanctl 执行权限不够。
cat <<EOF >swanctl-local.te
module swanctl-local 1.0;
require {
type ipsec_conf_file_t;
type ipsec_mgmt_t;
class dir { open read search };
}
#============= ipsec_mgmt_t ==============
allow ipsec_mgmt_t ipsec_conf_file_t:dir { open read search };
EOF
checkmodule -M -m -o swanctl-local.mod swanctl-local.te
semodule_package -o swanctl-local.pp -m swanctl-local.mod
semodule -i swanctl-local.pp
# 重启
sudo setenforce 0
sudo systemctl restart strongswan-swanctl
sudo ausearch -m AVC | grep swan
sudo grep ipsec_mgmt_t /var/log/audit/audit.log | sudo audit2allow -m swanctl-local > swanctl-local.te
如果客户通过 IPSec 默认路由到服务器上,本地不可以再做 MASQUERADE 等 SNAT,否则源地址是错的。
iptables -t nat -I POSTROUTING -m policy --pol ipsec --dir out -j ACCEPT
遗憾的是,nftables 暂时还没有这个功能。需要通过标记等方式实现类似的东西。