OpenConnect VPN服务器(ocserv)证书认证客户端配置¶
我在 OpenConnect VPN 初步完成了一个OpenConnect VPN服务器(ocserv)部署,VPN客户端是通过密码认证方式连接VPN的。不过,每次输入密码确实有些麻烦,没有 WireGuard VPN 这种完全靠不对称密钥认证(无需密码)方便(ocserv配置也过于复杂了)
通过使用自己的CA(Certificate Authroity, 证书颁发机构)来签署客户端证书,ocserv可以通过证书方式来认证客户端(客户端无需密码)。注意,ocserv daemon继续使用Let's Encrypt颁发的TLS服务器证书,所以客户端软件不会显示安全警告。
生成客户端证书¶
执行以下命令生成一个客户端私钥:
sudo certtool --generate-privkey --outfile client-privkey.pem
创建一个客户端证书模版文件
client-cert.cfg
,注意,这里uid
是之前在 OpenConnect VPN 部署时已经添加到/etc/ocserv/ocpasswd
文件中的一个用户名 :
# X.509 Certificate options
# The organization of the subject.
organization = "vpn.example.com"
# The common name of the certificate owner.
cn = "John Doe"
# A user id of the certificate owner.
uid = "username"
# In how many days, counting from today, this certificate will expire. Use -1 if there is no expiration date.
expiration_days = 3650
# Whether this certificate will be used for a TLS server
tls_www_client
# Whether this certificate will be used to sign data
signing_key
# Whether this certificate will be used to encrypt data (needed
# in TLS RSA ciphersuites). Note that it is preferred to use different
# keys for encryption and signing.
encryption_key
执行以下命令创建客户端证书
client-cert.pem
,这个证书已经被CA私钥签名:sudo certtool --generate-certificate --load-privkey client-privkey.pem --load-ca-certificate ca-cert.pem \ --load-ca-privkey ca-privkey.pem --template client-cert.cfg --outfile client-cert.pem
将客户端私钥和证书合并到受PIN保护的PKCS #12文件中:
sudo certtool --to-p12 --load-privkey client-privkey.pem --load-certificate client-cert.pem --pkcs-cipher aes-256 --outfile client.p12 --outder
此时提示为密钥创建一个名字,可以输入这个密钥的拥有者名,并增加保护密码:
Generating a PKCS #12 structure...
Loading private key list...
Loaded 1 private keys.
Enter a name for the key: huatai
Enter password:
Confirm password:
此时有了一个客户端私钥和证书结合的统一文件 client.p12
需要注意Cisco AnyConnect 和 iOS不支持
AES-256
密码,会拒绝倒入客户端证书。所以如果用户使用iOS设备,可以选择3des-pkcs12
密码:sudo certtool --to-p12 --load-privkey client-privkey.pem --load-certificate client-cert.pem --pkcs-cipher 3des-pkcs12 --outfile ios-client.p12 --outder
此时有了一个iOS专用的客户端私钥和证书结合的统一文件 ios-client.p12
多用户证书签名请求¶
备注
本段仅用于多用户的VPN配置,也就是每个用户各自生成私钥,然后发给VPN管理员签名
对于需要各自保存私钥的多用户VPN,每个用户可以使用自己的私钥来生成证书签名请求(certificate signing request, CSR),然后将证书发送给管理员,管理员再像用户颁发客户端证书。
每个用户首先使用上文的方法生成一个客户端私钥和客户端证书模版
sudo certtool --generate-privkey --outfile client-privkey.pem
# X.509 Certificate options
# The organization of the subject.
organization = "vpn.example.com"
# The common name of the certificate owner.
cn = "John Doe"
# A user id of the certificate owner.
uid = "username"
# In how many days, counting from today, this certificate will expire. Use -1 if there is no expiration date.
expiration_days = 3650
# Whether this certificate will be used for a TLS server
tls_www_client
# Whether this certificate will be used to sign data
signing_key
# Whether this certificate will be used to encrypt data (needed
# in TLS RSA ciphersuites). Note that it is preferred to use different
# keys for encryption and signing.
encryption_key
每个用户执行以下命令创建CSR,这里
request.pem
文件由用户的私钥签名:certtool --generate-request --load-privkey client-privkey.pem --template client-cert.cfg --outfile request.pem
然后用户将
request.pem
文件和client-cert.cfg
(模版文件中有该用户名)文件发送给管理员,管理员执行以下命令生成对应用户的客户端证书:sudo certtool --generate-certificate --load-ca-certificate ca-cert.pem --load-ca-privkey ca-privkey.pem \ --load-request request.pem --template client-cert.cfg --outfile client-cert.pem
然后,将 client-cert.pem
证书发送给用户
在 ocserv 服务端激活证书认证¶
修改
ocserv
服务器配置文件/etc/ocserv/ocserv.conf
将密钥认证激活:# 密码认证 auth = "plain[passwd=/etc/ocserv/ocpasswd]" # 密钥认证 auth = "certificate"
如果要允许用户自己选择证书认证或者密码认证,则修改成:
enable-auth = "plain[passwd=/etc/ocserv/ocpasswd]"
auth = "certificate"
备注
这里有一个疑惑,当激活了 certificate
时,会强制客户端必须发送证书,所以之前仅仅通过密码认证就行不通了会被服务器强制断开。我尝试了上述两种配置,发现Cisco Secure Client不发送客户端证书,是无法进行密码认证的。所以我觉得启用了证书认证之后,可以关闭掉密码认证。( 我最后就是采用证书认证方法 ),所以我的 /etc/ocserv/ocserv.conf
配置实际为:
#auth = "plain[passwd=/etc/ocserv/ocpasswd]"
auth = "certificate"
Recipes for Openconnect VPN 提供了详细的认证配置方法,很多可以结合到企业级密码认证系统,例如FreeIPA, Microsoft AD 等
然后找到
ca-cert
参数
对于 Debian/Ubuntu ,则是:
ca-cert = /etc/ssl/certs/ssl-cert-snakeoil.pem
对于 CentOS 8/RHEL 8则是:
ca-cert = /etc/ocserv/ca.pem
需要将 ca-cert
修改成我们自己的CA证书来验证客户端证书,所以修改成:
ca-cert = /etc/ocserv/ssl/ca-cert.pem
然后找到以下行:
cert-user-oid = 0.9.2342.19200300.100.1.1
这一行不需要修改, 0.9.2342.19200300.100.1.1
代表客户端证书中归档的 UID。 上面的行告诉 ocserv 守护进程从客户端证书的 UID 字段中找到用户名。 如果客户端证书成功通过 CA 证书验证并且 ocserv 守护程序可以在 /etc/ocserv/ocpasswd 文件中找到匹配的用户名,则客户端可以登录。
保存配置修改,然后重启
ocserv
sudo systemctl restart ocserv
openconect客户端证书使用方法¶
使用上述客户端证书
client.p12
连接服务器:sudo openconnect -c client.p12 https://vpn.example.com/
iOS设备证书认证设置方法¶
iOS用户可以使用Cisco AnyConnect应用程序(现在已经改名为Cisco Secure Client),对于Android应用商店也提供Cisco Secure Client,所以两者设置方法类似。
设置的主要步骤就是将前面生成的
PKCS #12
文件导入到Cisco Secure Client中:
可以通过邮件附件方式,在iOS的邮件客户端,打开包含 ios-client.p12
客户端文件,然后点一下 共享
按钮(右上角)
将该文件共享给 Cisco Secure Client
此时输入PIN(也就是证书的保护密码)就可以导入证书文件。
导入证书之后,编辑Cisco Secure Client中的VPN连接配置,选择 Advanced -> Certificate
然后选择导入的客户端证书,
参考¶
Set up Certificate Authentication in OpenConnect VPN Server (ocserv) 采用自签名证书来完成服务器证书、客户端证书签名配置,适合企业自己控制证书分发(不实用 Let's Encrypt颁发的证书)