在 CentOS 平台构建 AnyConnect 并使用 Radius 验证权限

测试在 Vultr 提供的 CentOS 7 X64 平台,需要你已经构建好 Radius 服务器。

较早期的 AnyConnect 只能运行在思科设备上,现在 AnyConnect 可以通过兼容 AnyConnect SSL VPN 的 ocserv (OpenConnect VPN Server) 实现。在 Fedora 维护的 EPEL 仓库中已经提供了 ocserv,所以只要安装 EPEL 源即可。

wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -ivh epel-release-latest-7.noarch.rpm

然后安装 ocserv 软件,radcli 是对 Radius 的支持组件。

yum install -y radcli
yum install -y ocserv

AnyConnect 在连接成功后交换内容数据采用 UDP 的 DTLS,在断线重连时采用 TCP 的 TLS 来保证安全,所以需要提供 TLS 证书。自建 CA 会导致客户端在连接服务器时提示证书不信任,可以申请 SSL 证书来避免这个问题并跳过自己生成证书的步骤,对于多台 AnyConnect 服务器可以申请泛域名证书来避免每台服务器生成一张证书。我们在这里使用自建 CA,AnyConnect 所用证书可以用 GunTLS 提供的 certtool 生成,下面的命令构造了一个 RSA 算法的 2048 位私钥,请注意不要生成 AnyConnect 不支持的 ECC 证书。

certtool --generate-privkey --outfile ca.pem

这样就生成了 CA 所需的私钥 ca.pem 文件,生成 CA 的证书需要填写一些模版信息,保存到 ca.tmpl。

cn="my root ca"
organization="ca"
expiration_days=3650
serial=1
ca
signing_key
cert_signing_key
crl_signing_key

这样我们就可以生成 CA 的证书了。

certtool --generate-self-signed --load-privkey ca.pem --template ca.tmpl --outfile ca.crt

自建完成 CA 后需要生成一张供 AnyConnect 使用的终端证书。

certtool --generate-privkey --outfile anyconnect.pem

生成公钥需要填写一些模版信息,保存到 anyconnect.tmpl。

cn="你的域名 / 服务器 IP"
unit="anyconnect"
expiration_days=365
signing_key
tls_www_client

随后我们创建公钥。

certtool --generate-certificate --load-privkey anyconnect.pem --load-ca-certificate ca.crt --load-ca-privkey ca.pem --template anyconnect.tmpl --outfile anyconnect.crt

在客户端需要使用 p12 格式的证书,会提示输入密码与验证密码,如果输入了密码在使用时也会要求输入密码,可以留空。

openssl pkcs12 -export -inkey anyconnect.pem -in anyconnect.crt -certfile ca.crt -out user.p12

我们成功生成了两张证书,一张是我们自建的 CA 证书 ca.crt,一张是我们生成的 AnyConnect 使用的证书 anyconnect.crt。AnyConnect 服务器在此作为的是 Radius 的客户端,编辑 /etc/radcli/servers 中输入你的 radius 服务器地址与通信密钥,例如如下格式。

radius.example.com testing123

然后编辑 Radius Client 的配置文件 /etc/radcli/radiusclient.conf。

authserver radius.example.com
acctserver radius.example.com

编辑 /etc/ocserv/ocserv.conf 文件,找到 auth = "pam" 更改为 auth = "auth = "radius[config=/etc/radcli/radiusclient.conf,groupconfig=true]"

然后主要修改以下部分。

# 启用认证
acct = "radius[config=/etc/radcli/radiusclient.conf]"

# 超时时间
stats-report-time = 360

server-cert = /etc/ocserv/anyconnect.crt
server-key = /etc/ocserv/anyconnect.pem

#最大用户数量
max-clients = 16

#同一个用户最多同时登陆数
max-same-clients = 4

#tcp和udp端口
tcp-port = 443
udp-port = 443

#运行用户和组
run-as-user = ocserv
run-as-group = ocserv

#分配给VPN客户端的IP段
ipv4-network = 10.12.0.0
ipv4-netmask = 255.255.255.0

#DNS
dns = 8.8.8.8
dns = 8.8.4.4

注释掉所有的 no-route 和 route 表示所有流量均通过 AnyConnect 发送,配置防火墙。

iptables -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu # 自动调整 MTU
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # NAT 转发
iptables -I INPUT -p tcp --dport 443 -j ACCEPT # 开启 443 端口的 TCP
iptables -I INPUT -p udp --dport 443 -j ACCEPT # 开启 443 端口的 UDP

随后编辑 /etc/sysctl.conf 文件存入以下内容并保存。

net.ipv4.ip_forward = 1

执行。

sysctl -p

在某些情况下可能 iptables 会无法使用,可以尝试 iptables -F 清除所有的条目后再执行以上条目,最后开启 ocserv 服务端。

systemctl start ocserv.service

或者你也可以选择弃用 firewalld 而改用 iptables。

systemctl stop firewalld
systemctl mask firewalld
yum install iptables-services -y
systemctl enable iptables