记一次 OpenVPN 配置解决 RDS 安全问题
记一次 OpenVPN 配置解决 RDS 安全问题
1. 问题背景
出于某些原因,线上 RDS 数据库的访问凭证(用户名密码)泄露到了公司内部。这导致了几个潜在的安全隐患:
- 公网访问风险:公司网络环境下,由于 RDS 公网地址的 IP 白名单包含了公司出口 IP,无权限的同事获取公网 RDS 地址后可以直接连接线上数据库
- VPN 访问风险:连接公司内网 VPN 后,可以通过 RDS 内网地址连接到数据库
- 跳板机风险:测试服务器可以作为跳板,通过内网 RDS 地址连接线上库
本文记录了如何通过配置来逐一解决这些问题,确保只有授权人员可以访问线上数据库。
2. 解决方案
2.1 剔除 RDS 公网访问白名单
问题:公司网络环境下可以通过公网 RDS 地址访问线上数据库
解决方法:
在阿里云 RDS 控制台的安全设置中,将公司的外网出口 IP 从白名单中移除,这样公司网络环境下就无法通过公网地址连接数据库了。
2.2 阻断 VPN 连接内网 RDS 的通道
问题:连接公司 VPN 后可通过内网地址访问 RDS
当前配置:OpenVPN 服务端配置文件中的路由配置如下:
# 该配置使整个网段的流量都通过 VPN 隧道
push "route 172.18.20.0 255.255.255.0"
这行配置的作用是让整个网段(172.18.20.0/24)的请求都走 VPN 流量。由于 RDS 内网地址为 172.18.20.235
,属于该网段,所以任何连接了 VPN 的用户都可以通过内网地址连接数据库。
解决方案:添加一条更精确的路由规则,优先级更高:
# 强制 RDS IP 流量走本地网关而非 VPN 隧道
push "route 172.18.20.235 255.255.255.255 net_gateway"
该配置会精准匹配 RDS IP 地址的流量,并强制其走 VPN 客户端本地的网关,而不是 VPN 隧道,从而阻断了通过 VPN 访问内网 RDS 的可能性。
2.3 防止测试服务器作为跳板机
问题:由于测试服务器与 RDS 在同一网段且可以内网通信,无权限同事仍可通过测试服务器作为跳板连接线上数据库。
解决方案:修改 DNS 解析,阻断连接
在测试服务器的 /etc/hosts
文件中添加以下配置:
# 将 RDS 内网域名解析至本地回环地址,阻断连接
127.0.0.1 rds内网域名
这样,当有人尝试在测试服务器上连接 RDS 内网域名时,会被解析到本地回环地址 127.0.0.1
,导致连接失败。
3. 进阶解决方案:基于用户的精细化权限控制
以上三个解决方案在解决安全问题的同时,也限制了有权限用户的正常访问。为此,我们可以通过修改 OpenVPN 服务端配置,实现基于用户的精细化权限控制:只允许特定用户通过 VPN 访问内网 RDS。
3.1 修改 OpenVPN 服务器配置
在 /etc/openvpn/server/server.conf
配置文件中添加以下内容:
# 启用脚本执行权限(级别 3 允许调用外部程序)
script-security 3
# 设置客户端连接时执行的脚本
client-connect /etc/openvpn/client-connect.sh
3.2 创建客户端连接脚本
创建并设置脚本权限:
cd /etc/openvpn
touch client-connect.sh
chmod 755 client-connect.sh # 使用更安全的权限设置
脚本内容如下:
#!/bin/bash
# 获取参数和用户名
CONFIG_FILE="$1" # OpenVPN 生成的临时配置文件
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
LOG_FILE="$(dirname "$0")/client-connect.log"
# 从环境变量获取用户名(优先使用 username,其次是 common_name)
USERNAME="${username:-${common_name:-UNKNOWN_USER}}"
# 创建日志文件(如果不存在)
if [ ! -f "$LOG_FILE" ]; then
echo "Timestamp | Username | Config File | Action Taken" > "$LOG_FILE"
echo "------------------------------------------------" >> "$LOG_FILE"
fi
# 记录连接基本信息
LOG_ENTRY="$TIMESTAMP | $USERNAME | $CONFIG_FILE"
# 基于用户名进行权限控制
# 这里可以扩展为从数据库或配置文件读取授权用户列表
if [ "$USERNAME" = "xingcy" ]; then
# 允许特定用户访问 RDS 内网地址
echo "push \"route 172.18.20.235 255.255.255.255 vpn_gateway\"" >> "$CONFIG_FILE"
echo "$LOG_ENTRY | Added VPN route for 172.18.20.235" >> "$LOG_FILE"
else
# 其他用户不添加特殊路由
echo "$LOG_ENTRY | No special routing applied" >> "$LOG_FILE"
fi
# 记录环境变量(调试用)
echo "[$TIMESTAMP] Environment variables:" >> "$LOG_FILE"
env | grep -E 'username|common_name|script_' >> "$LOG_FILE"
# 记录最终配置(调试用)
echo "[$TIMESTAMP] Final config file content:" >> "$LOG_FILE"
cat "$CONFIG_FILE" >> "$LOG_FILE"
echo "----------------------------------------" >> "$LOG_FILE"
exit 0
脚本工作原理:
- 脚本在客户端连接 VPN 时被调用
- 获取连接用户的用户名
- 只有特定用户(本例中为
xingcy
)才会接收到允许访问 RDS 内网地址的路由配置 - 其他用户不会收到此路由配置,因此无法通过 VPN 访问内网 RDS
- 所有连接尝试都被记录到日志文件,方便审计
3.3 验证配置效果
当不同用户连接 VPN 时,client-connect.log
日志文件会记录不同的路由配置:
# 普通用户连接记录
----------------------------------------
2025-04-11 21:42:54 | yujianghua | /tmp/openvpn_cc_fde8421074b05294e17573fd0810e9a.tmp | No special routing applied
[2025-04-11 21:42:54] Environment variables:
common_name=yujianghua
script_type=client-connect
script_context=init
username=yujianghua
[2025-04-11 21:42:54] Config file content:
----------------------------------------
# 授权用户连接记录
2025-04-11 22:07:02 | xingcy | /tmp/openvpn_cc_6d7bd9d7f217217afbf8ef016b73381.tmp | Added VPN route for 172.18.20.235
[2025-04-11 22:07:02] Environment variables:
common_name=xingcy
script_type=client-connect
script_context=init
username=xingcy
[2025-04-11 22:07:02] Config file content:
push "route 172.18.20.235 255.255.255.255 vpn_gateway"
----------------------------------------
3.4 路由表验证
使用 netstat
命令检查客户端路由表,可以看到授权用户和非授权用户的区别:
授权用户的路由表:
(base) ➜ Downloads netstat -rn|grep 172.18
172.18.20/24 10.0.10.1 UGSc utun3 # 网段流量走 VPN
172.18.20.235/32 10.0.10.1 UGSc utun3 # RDS IP 流量也走 VPN
非授权用户的路由表:
(base) ➜ Downloads netstat -rn|grep 172.18
172.18.20/24 10.0.10.1 UGSc utun3 # 网段流量走 VPN
172.18.20.235/32 192.168.110.1 UGSc en0 # RDS IP 流量走本地网络接口
在非授权用户的路由表中,RDS IP 的流量会被导向本地网络接口(en0),而不是 VPN 接口(utun3),因此无法访问内网 RDS。
4. 总结
通过以上配置,我们成功实现了多层次的安全防护:
- 关闭了公网访问入口:移除 IP 白名单
- 阻断了通用 VPN 访问:通过路由规则控制
- 防止了跳板攻击:修改 DNS 解析
- 实现了精细权限控制:基于用户身份的动态路由配置
这种多层次的安全防护策略,可以有效应对凭证泄露的安全风险,确保即使数据库凭证泄露,也只有授权人员能够实际访问数据库。同时,通过完善的日志记录,也为安全审计提供了有力支持。
在网络安全领域,这种”纵深防御”的思想非常重要 —— 不依赖单点安全措施,而是构建多层次、多角度的安全防护体系。
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: