ocserv-radius-认证搭建-freeradius-mysql

项目背景

TM3.0项目,VPN方案采用刚开源的openconnect。在客户端认证方式测试过pam、certificate以及2FA(password file 结合OTP)。不过都不满足TM3.0的认证需求。最终采用Radius的方式进行客户端认证。

ocserv搭建

ocserv安装

首先我们来搭建openconnect服务端,openconnect服务端简称ocserv(open connect server)。其在ubuntu上的依赖问题比较麻烦,因此我们这里选择centos7.2。
ocserv已经在epel源提供,我们直接安装对应软件包。

yum install -y epel-release
yum install - y ocserv

安装完毕后使用命令

ocserv -v

检查安装。

设置开机自动启动

chkconfig ocserv on

生成证书:

anyconnect使用ssl证书来进行加密,ocserv也使用此方法。除了ca证书之外,还有服务端证书和客户端登陆用的证书,这比较麻烦,我们先使用密码验证来完成客户端登陆。而ca证书和服务端证书使用自签方式(由于ca证书自签,客户端登陆时将提示不受信任的服务器,待会我们会讲到。如果需要合法的ca证书,请自行寻找信誉良好的ca证书颁发机构进行签发)。

这里你需要先仔细阅读官方文档,简单的来说,如下几步
1. 创建文件夹

[root@ocserv ~]# mkdir anyconnect
[root@ocserv ~]# cd anyconnect

  1. 生成 CA 证书
[root@ocserv anyconnect]# certtool --generate-privkey --outfile ca-key.pem
Generating a 2048 bit RSA private key...
[root@ocserv anyconnect]# cat >ca.tmpl  cn ="VPN CA"
> organization = "opscaff"
> serial = 1
> expiration_days = 3650
> ca
> signing_key
> cert_signing_key
> crl_signing_key
> EOF
[root@ocserv anyconnect]# certtool --generate-self-signed --load-privkey ca-key.pem \
> --template ca.tmpl --outfile ca-cert.pem

把生成的 ca-cert.pem 放到 /etc/ocserv/ 中

  1. 生成本地服务器证书
[root@ocserv anyconnect]# certtool --generate-privkey --outfile server-key.pem
Generating a 2048 bit RSA private key...
[root@ocserv anyconnect]# cat >server.tmpl  cn = "xxx.xxx.xxx.xxx"  //cn为ocserv服务器
> organization = "opscaff"
> serial = 2
> expiration_days = 3650
> encryption_key
> signing_key
> tls_www_server
> EOF
[root@ocserv anyconnect]#  certtool --generate-certificate --load-privkey server-key.pem \
> --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem \
> --template server.tmpl --outfile server-cert.pem

把生成的 server-cert.pem 和 server-key.pem 放到 /etc/ocserv/ 中

  1. 生成客户端证书
    创建 gen-client-cert.sh

[root@ocserv anyconnect]# vi gen-client-cert.sh #!/bin/bash USER=$1 CA_DIR=$2 SERIAL=`date +%s` certtool --generate-privkey --outfile $USER-key.pem cat user.tmpl cn = "$USER" unit = "admins" serial = "$SERIAL" expiration_days = 365 signing_key tls_www_client _EOF_ certtool --generate-certificate --load-privkey $USER-key.pem --load-ca-certificate $CA_DIR/ca-cert.pem --load-ca-privkey $CA_DIR/ca-k ey.pem --template user.tmpl --outfile $USER-cert.pemopenssl pkcs12 -export -inkey $USER-key.pem -in $USER-cert.pem -name "$USER VPN Client Cert" -certfile $CA_DIR/ca-cert.pem -out $USER .p12 [root@ocserv anyconnect]# chmod +x gen-client-cert.sh
  1. 创建用户文件夹并调用 gen-client-cert.sh 生成证书
[root@ocserv anyconnect]# mkdir user
[root@ocserv anyconnect]# cd user
[root@ocserv user]# ../gen-client-cert.sh opscaff001 ..

按提示设置证书使用密码,或直接回车不设密码

配置ocserv

vim /etc/ocserv/ocserv.conf

以下是需要修改的部分

这里的auth即指使用何种方式进行用户登陆验证,其中plain为ocserv自带的密码验证,需要通过ocserv的相关命令来添加用户(其实是按一定格式保存到文件里,是一种纯文本的用户记录方式)。radius方式即我们实际需要使用的方式,但是我们先使用plain方式,通过分步测试来确保每一步都可以检查是否正确。

auth = "plain[passwd=/etc/ocserv/ocpasswd]"

证书颁发机构,将被用来验证客户端证书(公钥)如果证书身份验证设置

ca-cert = /etc/ocserv/ca-cert.pem

服务端证书路径,这两个路径推荐如下所示,这样便于集中管理ocserv有关文件。如果你之前生成证书后拷贝到了其他位置,请使用证书的实际位置作为设置。

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

该选项指定本服务端最大可以同时接入的连接数量,设置为0表示无限制(依然会受到linux最大用户可打开文件数限制)。推荐值1024。

max-clients = 1024

相同的账户可同时连接上限。这个选项可以限制同一个用户可同时使用的设备数量。设置为0表示无限制。

max-same-clients = 5

以下是虚拟网卡设置。包括虚拟网卡名和ip池以及子网掩码,我们需要记住他们,接下来将会在其他设置中用到。

device = vpns
ipv4-network = 192.168.100.0
ipv4-netmask = 255.255.255.0

打开 PMTUD(自动优化VPN的网络性能)

try-mtu-discovery = true

注释掉所有的 route,让服务器成为 gateway

#route = 192.168.1.0/255.255.255.0

保存设置文件,接下来执行bash命令添加ocserv用户。

ocpasswd -c /etc/ocserv/ocpasswd opscaff001

系统配置

内核配置

其中 -c 参数后面是密码文件的路径,是我们之前在ocserv.conf中设置的路径,需要保持一致。后面的opscaff001是用户名。回车后输入两次密码以完成添加。添加完成后将在指定的目录出现ocpasswd文件,这就是保存密码用的文件。

关于涉及到nat的数据包转发,在linux上使用内核转发效率是最高的,因此ocserv也采用此方案。为此我们需要确认当前操作系统已开启内核转发功能。

vim /etc/sysctl.conf

打开该文件后检查是否存在行

net.ipv4.ip_forward = 1

若没有,添加到文件末尾。保存。然后重载配置文件。

sysctl -p

为确认ipv4内核转发已开启,我们可以查看以下虚文件

cat /proc/sys/net/ipv4/ip_forward

若值为1,表示内核转发已开启。接下来不使用service来执行ocserv,而直接运行ocserv以查看实时输出

firewalld安装及配置

安装firewalld
yum install -y firewalld
配置firewalld

创建一个ocserv服务

vim /etc/firewalld/services/ocserv.xml

内容如下:

ocservCisco AnyConnect

启动firewalld

systemctl start firewalld
firewall-cmd --permanent --add-service=ocserv
firewall-cmd --permanent --add-masquerade
firewall-cmd --reload

配置内网转发

firewall-cmd --permanent --zone=public --add-rich-rule='rule family=ipv4 source address=192.168.100.0/24 masquerade'
firewall-cmd --reload

查看所有打开端口

# firewall-cmd --list-port
# firewall-cmd --zone=public --list-ports
# firewall-cmd --list-all

调试ocserv

ocserv -f -d 1

其中 -f 参数表示前台运行,-d 参数表示debug等级。通过这种方式,如果我们的设置有错误,我们将立即看到错误输出,这样我们就可以知道需要修改哪些设置。之所以放到screen里,是因为接下来还需要做其他事情,而为了不中断ocserv,因此在screen中运行。

一般情况下我们的ocserv应该已经成功运行并有输出了,接下来我们来测试以下是否可以用。在windows上使用编译好的客户端进行测试。
因为在内网测试,连接时间不到2s。

windows客户端配置证书(先欠着)

freeradius搭建

安装freeradius服务端

在另外一台centos服务器上搭建radius服务,这里采用开源的freeradius
freeradius用来提供用户验证功能,我们现在来搭建freeradius然后调整ocserv设置以使其使用radius作为用户身份验证模块。freeradius分为两部分,客户端和服务端。验证请求由客户端发出,服务端收到后根据设置中的密码保存形式(文件、mysql等)完成验证,数据回传给客户端。freeradius并不是某一种附属程序或插件,而是单独运行的程序。ocserv通过调用freeradius客户端对连接者进行身份验证。因此我们分别需要安装并设置freeradius客户端和服务端。

freeradius服务端与ocserv不需要在同一台服务器上。freeradius客户端必须在ocserv服务器上(一个服务端可以对应多个客户端)。同样的,mysql数据库也不需要和freeradius在同一台服务器上。下面的示例中,采取的网络架构是三台服务器 ocserv服务器(安装有ocserv,freeradius client)、freeradius服务器(安装有freeradius server)、mysql服务器(安装有mysql)。
首先我们在freeradius服务器安装freeradius服务端

yum install freeradius

安装完毕后使用

radiusd -v

若看到版本号信息说明安装成功。
由于我们之后需要使用mysql来存储用户信息,我们还需要安装freeradius的mysql扩展

yum install freeradius-mysql

配置freeradius并测试

我们首先使用freeradius的默认设置,即文本形式记录用户的用户名和密码。测试freeradius的工作是否正常,再测试ocserv调用freeradius是否正常,最后再设置freeradius使用mysql来读取用户记录。

freeradius的保存用户的文本在 /etc/raddb/user 其他设置也在这个目录,我们等会会改动这个目录下的设置。user文件是一个link,我们直接编辑其实际路径(vim似乎不能编辑link)

vim /etc/raddb/mods-config/files/authorize

在第一行插入如下内容后保存

opscaff001 Cleartext-Password := "123456"

这里,我们新建了一个用户,用户名为 opscaff001 ,密码为 123456 。之后我们新建一个screen并以调试模式运行radiusd

radiusd -X

好,现在我们可以看到我们的freeradius服务端已经处于运行状态了
我们退出screen,然后使用freeradius的调试工具进行测试,首先安装它

yum install freeradius-utils

执行以下命令

radtest opscaff001 123456 localhost 0 testing123

ps:如果修改了主机名,一定要当心出错。

如果看到 Received Access-Accept 字样说明验证成功。如果看到 Received Access-Reject 说明验证失败,你需要检查使用的命令。

当我们确认freeradius工作正常之后我们用freeradius客户端来访问freeradius服务端。不过在那之前我们需要先设置freeradius服务端设置。

首先打开设置文件(服务端上的客户端配置)

vim /etc/raddb/clients.conf

我们在这份文件可以对每个客户端进行设置(以ip区分),以及所有客户端的一些全局设置。内容很多,我们不一一详谈了。
我们直接找到第30行的 client localhost,我们刚才测试工具之所以能正确访问freeradius服务端,是因为默认设置下,localhost已被加入这份设置,即localhost可以访问freeradius服务端。

而我们之前在测试命令中使用的 testing123在这份文件的第100行,这个设置用来指定客户端发送请求时带的密钥,若密钥错误将导致服务端返回验证失败的信息。这个设置很重要,我们这里不去修改他,但是真正的生产环境需要修改这个设置。

为了方便起见,我们不另外再开一个客户端设置了,我们直接修改现有的客户端设置即 client localhost 的设置中的客户端ip设置。

找到第42行,修改为
#ipaddr = 127.0.0.1

找到第46行,修改为ipv4addr = * # any. 127.0.0.1 == localhost
保存这个文件。现在我们允许任何ipv4地址访问freeradius服务端(这在实际生产环境中是不安全的,生产环境中请仔细配置每一个客户端设置)。

安装freeradius客户端

我们现在在ocserv服务器上安装freeradius客户端
下载freeradius-client源码包
这里我们使用的包为:freeradius-client-1.1.7.tar.gz

tar -zxvf freeradius-client-1.1.7.tar.gz
cd freeradius-client-1.1.7

安装依赖包:

yum install –y  gcc gcc-c++
./configure
make -j2 && make install 

我们现在在ocserv服务器上安装freeradius客户端

yum install freeradius-client

为了测试freeradius服务端在这台服务器上也可以访问,我们可以在这台服务器上也安装测试工具并进行测试(假设freeradius服务器地址为1.1.1.1)

yum install freeradius-utils
radtest opscaff001 123456 1.1.1.1 0 testing123

确认无误后我们进行接下来的设置。首先我们打开freeradius客户端设置文件

vim /usr/local/etc/radiusclient/radiusclient.conf

第37行改为

authserver 1.1.1.1

第42行改为

acctserver 1.1.1.1

保存这份文件
打开freeradius客户端的服务器设置

vim /usr/local/etc/radiusclient/servers

添加以下内容至最后一行

1.1.1.1 testing123

保存这份文件。自此,我们已经设置好了freeradius客户端需要做的设置。我们接下来让ocserv使用freeradius作为验证模块

我们再次打开ocserv配置文件

vim /etc/ocserv/ocserv.conf

我们修改第39行的验证方式设置,改为

auth = "radius[config=/usr/local/etc/radiusclient/radiusclient.conf,groupconfig=true]"

这样,我们就使得ocserv使用freeradius来进行用户验证。

但是使用文本保存密码不是我们最终需要的,我们到此仅仅是确认了ocserv调用freeradius正常,接下去我们完成freeradius服务端的mysql设置。

配置mysql

由于我们需要使用mysql来存储用户信息,我们还需要安装freeradius的mysql扩展

yum install freeradius-mysql

我们首先需要启用freeradius的sql模块,方法很简单,做一个link即可

cd /etc/raddb/mods-enabled
ln -s /etc/raddb/mods-available/sql ./sql

这样,freeradius就可以加载sql模块了。
接下去我们设定sql模块设置,编辑以下文件

vim /etc/raddb/mods-available/sql

第31行

driver = "rlm_sql_mysql"

第73行

dialect = "mysql"

第77到80行(假设mysql服务器地址为2.2.2.2,用户名为radius,密码为123456789)

server = "2.2.2.2"
port = 3306
login = "radius"
password = "123456789"

第83行(假设库名为radius,其实这个一般不改)

radius_db = "radius"

第114行

read_groups = yes

第211行

read_clients = yes

保存这份文件,接下去我们修改freeradius服务端设置让它使用sql模块来进行用户验证。

vim /etc/raddb/sites-available/default

这份文件的主要结构是设置各种过程的操作步骤,例如验证,回话,验证失败等过程中的详细步骤。

第365行#files

第372行sql

第564行#files

第602行sql

第650行sql

第676行sql

第779行sql

保存这份文件。接下去我们重启radiusd。

数据库备份文件在freeradius服务器的 /etc/raddb/mods-config/sql/main/mysql/schema.sql 我们拷贝这个文件到数据库服务器的 /tmp/schema.sql

之后我们在mysql服务器上运行以下命令创建数据库并添加一条记录(用户名 opscaff001 密码 123456 )
mysql -u root -p
输入密码

create database radius;
use radius;
source /tmp/schema.sql;
insert into `radcheck` (`id`,`username`,`attribute`,`op`,`value`) values(1,'opscaff001','Cleartext-Password',':=','123456');
quit;

好,我们再此使用客户端进行尝试。如果你全部按照以上步骤进行的话,此时应该可以验证成功了。