基于 OpenWrt, OpenLDAP 和 FreeRADIUS 构建用帐号密码认证的 Wi-Fi 网络并按帐号实现 VLAN 分流

Posted by

on

前言

继上次初步使用 N305 设备构筑完家用网络后,想要让家里的网络看起来更高级一些。记得 2017 年在某处看到 Wi-Fi 连接的时候除了需要提供密码,还需要提供帐号。这引起了我的兴趣。本次将来构建这样一个网络,并再整一些好玩的活(按帐号分流到不同的 VLAN,并走不同出口访问公网)。

本文内容仅为重要内容之记录,不包含全部配置文件和信息。

架构图 TLDR

在本次的实现中:

  • 使用不同的帐号密码组合连接同一个 Wi-Fi,会根据帐号属性进入不同的 VLAN 内网
  • 不同的 VLAN 内网将走不同的 ISP 出口出站
  • AP 设备为 MT7621 + MT7605 芯片的 OpenWrt
  • 交换机为一台轻管理的 VLAN 交换机,端口和 VLAN 划分如图所示
  • 内网由 IGP LXC 终结,所有非本地子网的内网路由将被送入 IGP LXC,通过各路 WireGuard 隧道出站
  • 主路由 LXC 负责总路由导向,并连接各个 ISP
  • VLAN 1 主要为自己和授权用户访问;VLAN 10 为不受信任的设备和客人访问

主交换机的配置

主交换机的配置较为简单,重点在于配置与主路由的上联口及与 AP 设备的下联口。这两个端口上需要传输本次的 VLAN 1 和 10 的数据,所以我们为他们打标记(Tagged)。

对于其他口(2, 3, 4, 6),在本次被视为授权端口,默认需要走 VLAN 1,我们将这些口配置为 VLAN 1 上的 Untagged。可以参照下表进配置:

Tagged 数据帧 InTagged 数据帧 OutUntagged 数据帧 InUntagged 数据帧 Out
Tagged 端口原样接收原样发送按端口 PVID 打 Tag 标记按照 PVID 打 Tag 标记
Untagged 端口丢弃去掉 Tag 标记按端口 PVID 打 Tag 标记原样发送

本 Cheat Sheet 表参照于网络。

无线 AP 的配置

OpenWrt 需要进行配置才能启用企业级 WPA(WPA Enterprise)。我们需要移除固件自带的 wpad-mini 软件包并安装 wpad-openssl 软件包。

opkg update
opkg remove wpad-mini
opkg install wpad-openssl

执行上述命令后,重新启动 OpenWrt 设备即可。

配置 VLAN

本次案例中,AP 通过 WAN 口连接主交换机。我们首先清空 OpenWrt 中的所有接口,重新一一配置。

在 “Network” -> “Interfaces” -> “Devices” 中:

  • 为 WAN 口新增一个 VLAN,VLAN ID 为 1,接口名称 “vlan1”
  • 为 WAN 口新增一个 VLAN,VLAN ID 为 10,接口名称 “vlan10”
  • 新增一个网桥,桥接接口 “vlan1″,接口名称 “br-vlan1″,并选中空接口时也带起网桥
  • 新增一个网桥,桥接接口 “vlan10″,接口名称 “br-vlan10″,并选中空接口时也带起网桥

构建这些接口的原因是为了方便 Wi-Fi 的接口动态附加到对应 VLAN 的网桥上。

配置无线网络

在 “Network” -> “Wireless” 中新建好对应的网络,并在 “Wireless Security” 中选择 WPA2 获 WPA3 的带有 “EAP” 字眼的认证方式,就能在下方看到 RADIUS 服务器的配置。

  • 填好 RADIUS 服务器的地址(后文部署)与端口号,RADIUS 共享密钥
  • 在 “RADIUS Dynamic VLAN Assignment” 一栏,选择 “Required”。这意味着,RADIUS 会给每个认证请求下发一个 VLAN,用户会被绑定到对应 VLAN 的网桥中。如果没有下发 VLAN,则拒绝用户连接
  • 不要勾选 “RADIUS VLAN Naming”,并选择 “RADIUS VLAN Tagged Interface” 为 “wan”(本案例)
  • 在 “RADIUS VLAN Bridge Naming Scheme” 中填写 “br-vlan”(本案例)

看起来像这样:

配置接口和防火墙

在 “Interfaces” 页面中,新增区域 “guest”(VLAN 10) 和 “lan”(VLAN 1),分别绑定 “br-vlan10” 和 “br-vlan1″。协议为 DHCP 或者手动指定。关闭 “guest” 区域中的使用默认路由。设置 IP 的原因是为了方便管理 AP,否则可能无法再访问 AP。

在 “Network” -> “Firewall” 中,为默认 “Input” 和 “Forward” 设置策略 “Drop”,在下方 “Zone” 中,禁止(Drop) “guest” 区域的 “Input” 和 “Forward”。这么做是为了 VLAN 10 网络上防止不信任的设备访问本设备。

防火墙的配置看起来像这样:

整体配置

网络接口和区域配置看起来像这样:

# From /etc/config/network
# ...
config interface 'guest'
        option proto 'dhcp'
        option device 'br-vlan10'
        option type 'bridge'
        option defaultroute '0'
        option peerdns '0'
        option delegate '0'

config interface 'lan'
        option proto 'dhcp'
        option device 'br-vlan1'
        option delegate '0'

config device
        option type 'bridge'
        option name 'br-vlan1'
        list ports 'vlan1'
        option bridge_empty '1'

config device
        option name 'br-vlan10'
        option type 'bridge'
        list ports 'vlan10'
        option bridge_empty '1'

config device
        option type '8021q'
        option ifname 'wan'
        option vid '10'
        option name 'vlan10'

config device
        option type '8021q'
        option ifname 'wan'
        option vid '1'
        option name 'vlan1'

无线配置看起来像这样:

# From /etc/config/wireless
# ...
config wifi-iface 'default_radio1'
        option device 'radio1'
        option mode 'ap'
        option ssid '___________'
        option encryption 'wpa3-mixed'
        option auth_server 'X.X.X.X'
        option auth_port '1812'
        option auth_secret '____________'
        option dynamic_vlan '2'
        option vlan_tagged_interface 'wan'
        option vlan_bridge 'br-vlan'
        option network 'lan'

认证服务器的配置

OpenLDAP 的配置

OpenLDAP 是 LDAP 的开源实现的一种。另外比较出名的实现和变种便是微软的 Active Directory。LDAP 提供了目录管理功能。我们利用 LDAP 实现用户分组,权限管理,VLAN 数据管理等。

apt update
apt install -y ldap-server

安装过程中会要求输入域管理密码。

新版本的 OpenLDAP 已经使用 ldif 文件来管理配置(/etc/ldap/slapd.d/cn\=config.ldif)。

更新域名后缀

# changeSuffix.ldif
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=contoso,dc=com

ldapmodify -Y EXTERNAL -H ldapi:/// -f changeSuffix.ldif

安装 Radius 描述文件

由于默认的安装没有 Radius 的描述文件,需要添加 这两个文件 到 “/etc/ldap/schema” 中。

# 导入到数据库中
slapd -l /etc/ldap/schema/radius.ldif

配置用户和组

现在可以使用 LDAP Admin 软件来方便管理用户和组。

  • 分别创建 “cn=guest”, “cn=”network”, “cn=power” 三个组,分别代表 “访客用户”,”网络用户” 和 “超级用户”。
  • 创建 “ou=users” 来收纳用户
  • 在 “ou=users” 中创建 “admin” 帐户,并设置明文密码(为了方便 FreeRADIUS MSCHAP 认证),这不安全所以需要严格保管 LDAP 服务器中的数据(尽管数据库文件里的密码字段有有限的加密)
  • 在 “ou=users” 中创建 “guest” 帐户,赋予其 objectClass: radiusprofile 属性。并添加 radiusTunnelMediumType: IEEE-802, radiusTunnelPrivateGroupId: 10, radiusTunnelType: VLAN
  • 设置 “admin” 用户属于 “power” 和 “network” 组
  • 设置 “guest” 属于 “network” 组

FreeRADIUS 的配置

安装 FreeRADIUS。配置文件保存在 “/etc/freeradius/3.0” 中。目录结构类似于很多 Debian 系发行版软件包。

apt update
apt install freeradius freeradius-ldap

配置 EAP

cp /etc/freeradius/3.0/mods-available/eap /etc/freeradius/3.0/mods-enabled

在 eap 文件中:

  • 设置 “default_eap_type = peap”
  • 设置 “tls-config tls-common” 通用 TLS 证书
  • 设置 “tls_min_version = “1.2”, “tls_max_version = “1.2”

eap 文件的 “peap” 小节类似地配置为:

peap {
    tls = tls-common
    default_eap_type = mschapv2
    copy_request_to_tunnel = no
    use_tunneled_reply = yes # 设置此项才能将 RADIUS VLAN 字段成功透传
    virtual_server = "inner-tunnel"
}

配置 LDAP 联动

cp /etc/freeradius/3.0/mods-available/ldap /etc/freeradius/3.0/mods-enabled

在 ldap 文件中:

  • 设置管理员身份查询 “identity=’cn=admin,dc=contoso,dc=com’”
  • 设置密码和 “base_dn = ‘dc=contoso,dc=com’”

“update” 小节类似地配置为:

peap {
    # ...
    control:Cleartext-Password      := 'userPassword'
    # ...
    reply:Tunnel-Type               := 'radiusTunnelType'
    reply:Tunnel-Medium-Type        := 'radiusTunnelMediumType'
    reply:Tunnel-Private-Group-ID   := 'radiusTunnelPrivategroupId'
    # ...
}

“user” 小节类似地配置为:

user {
    # ...
    base_dn = "ou=users,${..base_dn}"
    filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
    # ...
}

“group” 小节类似地配置为:

group {
    # ...
    base_dn = "${..base_dn}"
    filter = '(objectClass=posixGroup)'
    name_attribute = cn
    membership_filter = "(|(member=%{control:${..user_dn}})(memberUid=%{%{Stripped-User-Name}:-%{User-Name}}))"
    # membership_attribute = 'memberOf' # 本案例中 OpenLDAP 尚未被配置支持此属性
    # ...
}

设置默认 VLAN 及允许拨入的用户组

在之前 LDAP 服务器的设定中,我们创建了 “network” 用户组。所有在该用户组中的用户才允许连接(拨入)网络。

同时,我们只对 “guest” 用户设置了 VLAN 10 的目录数据,这意味着,其他用户默认是 VLAN 1。

⚠️ 注意:本段内容在 后续文章 中有更新。

在 “/etc/freeradius/3.0/users” 文件中添加:

DEFAULT LDAP-Group == "network"
    Tunnel-Type = "VLAN",
    Tunnel-Medium-Type = "IEEE-802",
    Tunnel-Private-Group-Id = "1"

DEFAULT Auth-Type := Reject
    Reply-Message = "Sorry, your role is not allowed to connect."

虚拟主机

在 “sites-enabled” 文件夹中,仅保留 “inner-tunnel” 虚拟主机配置文件。并对其进行编辑:

#...
listen {
       ipaddr = *
       port = 0
       type = auth
}
authorize {
    filter_username
    eap {
        ok = return
    }
    ldap
    files
    expiration
    logintime
}
authenticate {
    Auth-Type MS-CHAP {
        mschap
    }
    eap
}
post-auth {
    # 此小节在下一篇文章中有更新。敬请参考。
    ldap
}
#...

测试

常用测试命令

# 调试 FreeRADIUS 时观察认证信息
freeradius -X

# LDAP 查看用户身份
ldapwhoami -x -D uid=username,dc=contoso,dc=com -W

# Radius 客户端模拟
radtest -x user password <Radius Server IP> <Port> <Radius Secret>

客户端验证

参考

  1. https://forum.openwrt.org/t/802-1x-dynamic-vlan-with-dsa-config/126040, 802.1X dynamic VLAN with DSA config
  2. https://github.com/redBorder/freeradius/blob/master/doc/schemas/ldap/openldap.schema, OpenLDAP Radius Schema File, GitHub
  3. https://github.com/redBorder/freeradius/blob/master/doc/schemas/ldap/openldap.ldif, OpenLDAP Radius ldif File, GitHub

Leave a Reply

Your email address will not be published. Required fields are marked *