同样是"把链路加密",TLS 在 socket 之上,只保护某个应用的流量;IPsec 在网络层之下,保护的是整个 IP 包。这个位置差异带来两个直接后果:对上层协议完全透明(TCP、UDP、ICMP 一起走),以及必须自己面对封装后变小的 MTU。配置 IPsec 出的问题,八成不在加密算法上,而在协商参数对不上或 MTU 被吃掉。
1. 位置决定能力:TLS 与 IPsec 的差别
| 维度 | TLS | IPsec |
|---|---|---|
| 工作层次 | 传输层之上(应用可感知) | 网络层(IP 之上) |
| 保护对象 | 单条连接的数据流 | IP 包,含所有上层协议 |
| 身份 | 证书 + 域名(SNI) | 预共享密钥 / 证书 / EAP,绑定 IP 或 ID |
| 对应用的要求 | 需支持 TLS | 应用无感 |
| 典型实现 | Nginx / OpenSSL | 内核 XFRM + IKE 守护进程 |
| 失效表现 | 握手失败、证书告警 | 包被丢、隧道不通、路由黑洞 |
第二条最关键:IPsec 由内核的数据面 + 用户态的协商面两部分组成。内核负责加密解密与封装(XFRM 子系统),守护进程只负责谈参数、下发 SA。所以"配置改了没生效"通常要看两边:swanctl --list-sas 和 ip xfrm state。
2. AH 与 ESP:两个协议保护的范围不同
| 项 | AH(IP 协议号 51) | ESP(IP 协议号 50) |
|---|---|---|
| 完整性覆盖 | 整个 IP 包,含外层 IP 头 | 仅 ESP 载荷(不含外层 IP 头) |
| 加密 | 不提供 | 提供 |
| NAT 穿越 | 不可行(IP 头被改即校验失败) | 可行(NAT-T 用 UDP 4500 封装) |
| 典型用途 | 极少,仅完整性验证场景 | 绝大多数 VPN |
| 与隧道模式组合 | 支持但无实际意义 | 标准组合 |
实践中"IPsec = ESP"。AH 在 NAT 环境下直接失效,因为 NAT 会改写源 IP,而 AH 的 ICV 覆盖了该字段——这也是 NAT-T 存在的原因。
传输模式(Transport):
[IP 头][ESP 头][加密的 TCP/UDP 载荷][ESP 尾][ICV]
隧道模式(Tunnel):
[新 IP 头][ESP 头][加密的 原始IP头+载荷 ][ESP 尾][ICV]
| 模式 | 是否新增 IP 头 | 适用 | 代价 |
|---|---|---|---|
| Transport | 否 | 主机到主机、端到端加密 | 原 IP 头暴露,路由需可达 |
| Tunnel | 是(20/40 字节) | 网关到网关、站点互联 | 多一层头,MTU 更紧 |
3. IKEv2 的三段协商
IKE 负责"谈参数",本身跑在 UDP 500 上;一旦检测到 NAT,后续 ESP 改走 UDP 4500。
| 阶段 | 交换 | 产出 | 常见失败点 |
|---|---|---|---|
| IKE_SA_INIT | 两条消息 | 协商加密套件、交换 DH、建立 IKE SA | 算法集无交集、DH 组不匹配 |
| IKE_AUTH | 两条消息 | 身份认证、建立首个 CHILD_SA | PSK 不一致、ID 不匹配、证书链不全 |
| CREATE_CHILD_SA | 可选、随时 | 新 SA、重协商密钥 | 流量选择器不匹配 |
| 概念 | 含义 | 排查命令 |
|---|---|---|
| IKE SA | 控制通道,双向一对 | swanctl --list-sas |
| CHILD_SA | 数据通道,每个方向一对 SPI | ip xfrm state |
| Proposal | 算法组合(加密 + 完整性 + PRF + DH) | 对比两端 proposals = 行 |
| Traffic Selector | 哪些源/目的网段进隧道 | local_ts / remote_ts |
| SPI | 安全参数索引,标识一个 SA | ip xfrm state 的 spi 字段 |
协商铁律:两端 proposal 必须有交集,且顺序不影响结果。只要有一端把 aes256gcm16-prfsha256-ecp256 写成 aes128-sha1-modp1024 这类旧组合,IKE_AUTH 就会停在 NO_PROPOSAL_CHOSEN。
4. 一份可用的 strongSwan 配置
下面按 strongSwan 5.9 的 swanctl 语法写,站点到站点、两端都是固定公网 IP 的场景。
# /etc/swanctl/conf.d/site.conf
connections {
site-b {
version = 2
local_addrs = 203.0.113.10
remote_addrs = 198.51.100.20
local {
auth = psk
id = 203.0.113.10
}
remote {
auth = psk
id = 198.51.100.20
}
proposals = aes256gcm16-prfsha256-ecp256, aes128-sha256-modp2048
children {
net {
local_ts = 10.10.0.0/24
remote_ts = 10.20.0.0/24
esp_proposals = aes256gcm16-ecp256
dpd_delay = 30s
start_action = trap
}
}
}
}
secrets {
ike-site-b { secret = "REPLACE_WITH_PSK" }
}
# 生效与观察
swanctl --load-all
swanctl --initiate --child net
swanctl --list-conns
swanctl --list-sas
# 内核侧确认 SA 与策略
ip xfrm state list
ip xfrm policy list
内核数据面也可以手工下发,用来验证"配置问题还是内核问题":
ip xfrm state add src 203.0.113.10 dst 198.51.100.20 proto esp spi 0x1000 \
reqid 1 mode tunnel aead "rfc4106(gcm(aes))" 0x000102030405060708090a0b0c0d0e0f10111213 128
ip xfrm policy add dir out src 10.10.0.0/24 dst 10.20.0.0/24 \
tmpl src 203.0.113.10 dst 198.51.100.20 proto esp mode tunnel
如果手工 SA 能通、swanctl 建的不通,问题就在协商侧(proposal、ID、selector);两者都不通则是路由、防火墙或 MTU。
5. 放行与 MTU:两处最容易漏的配置
| 规则 | 协议/端口 | 说明 |
|---|---|---|
| IKE | UDP 500 | 初始协商,必须双向可达 |
| NAT-T | UDP 4500 | 检测到 NAT 后 ESP 被封进 UDP |
| ESP | IP 协议 50 | 非 NAT 场景的数据面 |
| AH | IP 协议 51 | 仅使用 AH 时需要 |
| ICMP | echo/reply | 建议放行,用来验 MTU |
# nftables 写法(firewalld 也可用 rich rule 表达)
nft add rule inet filter input udp dport {500, 4500} accept
nft add rule inet filter input ip protocol esp accept
封装开销是 MTU 问题的根源。按典型量级估算:
| 封装组合 | 额外字节(约) |
|---|---|
| IPv4 + ESP(AES-GCM,含 IV 与 ICV) | 50–60 |
| IPv4 隧道模式(再加外层 20 字节 IP 头) | 70–80 |
| IPv6 隧道模式(外层 40 字节) | 90–100 |
| 再叠一层 UDP 封装(NAT-T) | 再加 8 |
若链路 MTU 是 1500,隧道内可用 MTU 只剩 1400 出头,对应 TCP MSS 约 1360。不处理就会出现"能 ping 通小包、大包全丢"的经典现象:ssh 卡在登录、curl 卡在响应体。
# 网关侧钳制 MSS,让两端自行收敛
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
-j TCPMSS --clamp-mss-to-pmtu
内核 XFRM 也支持在策略上做 PMTU 处理,但对端不配合时仍然要靠 MSS clamp。
6. 排错:六种典型故障
| 现象 | 常见原因 | 定位 |
|---|---|---|
协商停在 NO_PROPOSAL_CHOSEN |
两端 proposal 无交集 | swanctl --list-conns 对比算法串 |
AUTHENTICATION_FAILED |
PSK 不一致、ID 写错 | 核对 secrets 与 local.id/remote.id |
| SA 建起来但 ping 不通 | traffic selector 不覆盖实际网段 | ip xfrm policy list 看 src/dst |
| 小包通、大包丢 | MTU/MSS 未收敛 | ping -M do -s 1400 逐步逼近 |
| 一段时间后断,重建又通 | DPD 未开或重协商失败 | 开 dpd_delay,看日志重协商记录 |
| 只有单向通 | 一侧策略缺 dir in/dir fwd |
两侧都 ip xfrm policy list 对照 |
| NAT 后 ESP 不通 | 未启用 NAT-T | 确认 4500 放行、encapsulation 设置 |
日志入口固定在这几处:journalctl -u strongswan、swanctl --log(实时)、内核侧 dmesg | grep -i xfrm。把三层分开看——协商日志、SA 表、包计数(ip -s xfrm state 有字节计数)——能快速判断断在哪一层。
7. 边界:什么时候 IPsec 不是好选择
| 场景 | 更适合的方案 | 理由 |
|---|---|---|
| 少量客户端接入办公网 | WireGuard / OpenVPN | 配置量级小得多,NAT 友好 |
| 只需要保护 HTTP 流量 | TLS + mTLS | 无需动网络层,审计更细 |
| 跨云多租户互联 | 云厂商 VPN 网关 / 专线 | 托管方处理协商与 MTU 收敛 |
| 需要按应用做策略 | 服务网格 mTLS | IPsec 只能按 IP/端口粒度 |
| 客户端在频繁变动的移动网络 | WireGuard(UDP 单端口) | IPsec 的多端口与 NAT 检测更易断 |
一条容易被忽略的边界:IPsec 保护的是"包在链路上不被看/被改",它不解决"谁有权限访问哪个服务"。访问控制仍要靠安全组、防火墙规则和应用鉴权,把这两件事混在一起谈,往往导致隧道建好了但权限模型一片空白。
8. 自测
- 为什么 AH 在 NAT 环境下不可用,而 ESP 可以?
- 隧道模式与传输模式在报文结构上的差别是什么,各自多出多少字节?
- IKE_SA_INIT 与 IKE_AUTH 各解决什么问题?
NO_PROPOSAL_CHOSEN出现在哪一步? swanctl --list-sas有输出但业务不通,下一步该查什么表?- 链路 MTU 1500,IPv4 隧道模式下隧道内可用 MTU 大致是多少?
- 手工
ip xfrm state能通、守护进程建的不通,说明问题在哪一层?