IPsec 配置备忘 Part2 - 证书
作为系列的第二篇文章,讲解基本的证书原理和配置方法。没看过第一部分的快去看~
传送门:IPsec 配置备忘 Part1。
证书认证基础
我们在 Part1 中看到,PSK 认证的基本思路是使用一个只有通信双方才知道的暗号,如果能确认对方确实知道这个暗号,那么认证就成功了。证书认证的思路非常不同:假设 A 需要向 B 证明自己的身份,同时 A 知道 B 信任 C,那么 A 可以向 C 索取一份“介绍信”,当 B 询问 A 的身份时,A 可以向 B 展示这份 C 出具的“介绍信”,如果 B 能够确认这份“介绍信”确实是由 C 出具的,那么认证就成功了。注意这个认证是单向的,假设 A 也信任 C,那么 B 也可以通过向 C 索取“介绍信”来向 A 证明自己的身份。在 PKI 体系中,A 和 B 持有各自的“私钥”,C 作为 Certificate Authority (CA) 向 A/B 颁发证书(即“介绍信”)。同时,CA 也会向自己颁发一份证书并分发给 A/B,A/B 使用 CA 的证书来确认 B/A 出示的证书确实为 C 所颁发。
使用 certtool 创建证书
我使用 certtool 没有什么特别的理由,你也可以用openssl
或者 strongSwan 自带的pki
工具。我在之前的一篇文章里介绍过如何使用 certtool 创建证书:借助IPsec和strongSwan建立隧道并分配IPv6地址。不过我还是决定再写一遍现在的配置。我们的配置场景和 Part1 中的相同,只不过把 PSK 认证换成了证书认证。
首先给 HostA, HostB 和 CA 分别创建私钥,我这里用的是 ed25519,一些设备可能不支持,请自行参考文档换成 RSA:
certtool --generate-privkey --key-type ed25519 --outfile ca-key.pem
certtool --generate-privkey --key-type ed25519 --outfile hosta-key.pem
certtool --generate-privkey --key-type ed25519 --outfile hostb-key.pem
生成证书时,我们需要手动指定一些证书的信息,比如证书的名称,过期时间等等。证书的 Distinguished Name (DN) 会被用来和 IKEv2 的身份标识符进行匹配,以决定具体向对方出示哪份证书(对于发送者)以及是否接受对方的证书(对于接受者)。这些信息需要写成一个 template 文件才能被 certtool 读取,详细的 template 文件格式可以在 certtool 的帮助文档里查到。template 中的键名大小写敏感。
1 | # Common name, 是 DN 的一部分 |
1 | cn = "HOSTA_COMMON_NAME" |
1 | cn = "HOSTB_COMMON_NAME" |
然后创建证书:
1 | # 生成自签名 CA 证书 |
最终会生成的 6 个文件,你可以使用certtool --key-info < hosta-key.pem
来查看私钥信息,用certtool --certificate-info < hosta-cert.pem
来查看证书信息,用certtool --verify --load-ca-certificate ca-cert.pem < hosta-cert.pem
来检查证书是否确实是由 CA 签发的。其中:
hosta-key.pem, hosta-cert.pem, ca-cert.pem
需要拷贝到 HostA 上hostb-key.pem, hostb-cert.pem, ca-cert.pem
需要拷贝到 HostB 上ca-key.pem
留在本地好好保管不要交给任何人。
对于 strongSwan,私钥*-key.pem
需要放置在/etc/swanctl/private
,私钥对应的证书host*-cert.pem
需要放置在/etc/swanctl/x509
,CA 证书ca-cert.pem
需要放置在/etc/swanctl/x509ca
。
配置文件
基本上和 Part1 中的配置一样,有不同之处已经加了注释
1 | connections { |
将remote.id
设置成%any
会有一定的安全问题,比如 HostA 是服务器,HostB 和 HostC 是客户端,如果 HostB 连接 HostA 的时候不检查 id,那么如果 HostC 能劫持 IP 地址,它就能假装成 HostA。毕竟 HostB 不关心它连接的到底是 A 还是 C。解决方法也很简单,指定remote.id
为CN=HOSTB_COMMON_NAME
即可。
HostB 的配置除了local.id
外完全一致
1 | connections { |
链接测试
同 Part1,在任意一侧使用sudo swanctl -i -c child_sa
建立连接即可。连接建立后抓包即可看到加密流量。