Add opt-in built-in Feishu OIDC issuer for OpenVPN
This commit is contained in:
1 parent
6ca609fde4
commit
63cdda4ae1
23 files changed
+1244
-17
No files matched your search
+4
-4
@@ -51,9 +51,9 @@ sudo ss -tlnp | grep ':18080'
|
||||
|
||||
## 飞书 / OIDC 登录入口
|
||||
|
||||
`http://121.4.111.208:18080` 是当前管理界面示例,**既不是 OIDC issuer,也不是 OAuth 回调地址**。当前项目在 [OpenVPN OIDC 配置](../backend/internal/service/openvpn/openvpn.go)中要求 `oidc_issuer` 和 `oidc_base_url` 均为 HTTPS。issuer 指向提供标准 OIDC discovery 和 ID Token 的身份提供方(飞书若不支持,需使用 Keycloak / Authentik 等身份代理)。OpsX VPN 当前不签发 OIDC 令牌;经代理接入时,飞书 App ID/Secret 配在代理的飞书上游,向导的 Client ID/Secret 则来自代理中为 VPN 创建的 OIDC 客户端。
|
||||
`http://121.4.111.208:18080` 是旧管理入口,**不是 OIDC issuer 或安全的凭据配置入口**。当前内置飞书身份服务启用后以现有可信 HTTPS 域名的 `/id` 为 issuer,提供发现文档、JWKS、授权、令牌和用户信息接口;飞书应用上游回调是 `https://<域名>/id/feishu/callback`,OpenVPN 认证组件的回调是 `https://<域名>/oauth2/callback`。管理端通过 HTTPS 保存飞书 App ID/Secret 与允许的 tenant_key,VPN Client Secret 系统生成、服务器内部传递,不通过管理 API 回显。发行者禁用时不能将管理域名充当 issuer。
|
||||
|
||||
认证入口另设可供 VPN 客户端在连接前访问的 HTTPS 地址,例如 `https://vpn-login.example.com`。它**可以与 opsx-vpn 管理后台部署在同一台服务器上**:反向代理依据域名把管理站点送往 `:18080`,把认证站点的**所有路径**送往同机 `127.0.0.1:19090`(按专线配置调整)。两者是同一台服务器上的不同 Web 服务,并非管理后台不允许提供其他页面;当前实现由平台启动和管理认证组件,回调实际由 `openvpn-auth-oauth2` 处理。最终在 OIDC 身份提供方登记 `https://vpn-login.example.com/oauth2/callback`。不要把本地认证端口或 OpenVPN 管理 socket 暴露到公网。详见 [接入说明](../README.md#openvpn-飞书--oidc-浏览器认证)。
|
||||
内置方案复用管理域名与证书;先在「设置 → 飞书身份」启用身份服务并同步公网路由,Nginx 仅允许固定 `/id/` 身份路径。创建并启动唯一一条使用当前域名的 OpenVPN OIDC 测试专线后再次同步,才会把 `/oauth2/` 转发到其本机认证组件 `127.0.0.1:19090+`。未启动专线时不会开放 `/oauth2/` 路由。不要把认证端口或 OpenVPN 管理 socket 暴露到公网。详见 [接入说明](../README.md#openvpn-飞书--oidc-浏览器认证)。
|
||||
|
||||
该域名须由你控制并解析到公网入口。管理员可在“设置 → 域名与证书”保存 `test-link.appx365.com`,并选择 Go 或 Nginx 入口模式;`VPN_TLS_DOMAIN` 和 `VPN_TLS_MODE` 环境变量优先于页面配置。两种模式只能选一种来占用 TCP 80/443,保存配置并不会安装 Nginx、开放安全组或签发证书。
|
||||
|
||||
@@ -72,8 +72,8 @@ Go 模式(默认)使用 `golang.org/x/crypto/acme/autocert` 监听 80/443,
|
||||
2026-10-22 生产实例已启用 `test-link.appx365.com`,证书有效至 2027-01-19,`certbot renew --dry-run --run-deploy-hooks --non-interactive` 模拟续签成功。当前管理服务仍在公网 `:18080` 监听,沿用 HTTP 地址的客户端可绕过 Nginx 的路径白名单;完成客户端地址迁移后,需限制 18080 仅回环访问。模拟续签执行钩子时 `nginx -t` 的正常 stderr 被 Certbot 记录为警告,但退出成功。
|
||||
4. 页面保存入口模式为 Nginx,启动或重启 opsx-vpn 并设置 `VPN_LISTEN_ADDR=127.0.0.1:18080`;确认 `https://<域名>/api/health`、登录及各业务页面可用,未知路径断开,80 的挑战仍可读,然后收紧 18080 公网安全组。若现有业务必须从公网直连 18080,先迁移这些客户端。
|
||||
|
||||
不要只开放 `/oauth2/callback`:独立的 OIDC 认证域名还要转发认证组件的完整登录流程,且应另为该域名申请证书。管理站点的路由预览不覆盖认证域名;真实认证域名和组件端口确认后单独配置。若代理和 VPN 主机分离,预览里的 `127.0.0.1` 指代理主机自身,应改成受限私网地址并保护传输链路。回退时先恢复原 Nginx 配置及 opsx-vpn 入口模式,运行 `nginx -t` 后重载,不删除 `data/` 或已有证书。
|
||||
不要只开放 `/oauth2/callback`:认证组件还需要 `/oauth2/` 下的登录入口。内置身份服务方案通过设置页同步已托管的 Nginx 站点;外部发行者或独立认证域名仍须单独配置,不能直接复用管理站点路径。若代理和 VPN 主机分离,预览里的 `127.0.0.1` 指代理主机自身,应改成受限私网地址并保护传输链路。回退时恢复原 Nginx 配置,运行 `nginx -t` 后重载,不删除 `data/`、签名密钥或已有证书。
|
||||
|
||||
`/.well-known/openid-configuration` 属于发行者域名,不是认证入口上的 VPN 回调。不要只放行 `/oauth2/callback`:认证组件还需要发起登录等路由。认证入口使用独立域名,只反代给认证组件;如需按路径白名单返回 Nginx `444`,须先核对实际安装版本的完整路由,并保障 HTTP-01 验证路径。认证端口默认 19090,仅监听回环;新增 OIDC 专线自动递增并跳过已配置或已监听的端口,仍以启动时冲突检测为准。
|
||||
内置 issuer 的发现文档位于 `https://<域名>/id/.well-known/openid-configuration`,不属于 ACME 路径;Nginx 仅放行固定 `/id/` 身份端点、HTTP-01 验证路径及已配置专线的 `/oauth2/` 前缀,其余保持 444。认证端口默认 19090,仅监听回环;新增 OIDC 专线自动递增并跳过已配置或已监听的端口,仍以启动时冲突检测为准。
|
||||
|
||||
启用飞书认证前,需安装并验证 `openvpn-auth-oauth2`、准备身份提供方凭据、配置 HTTPS 反代,并用支持 WebAuth 的客户端联调。现有 LDAP 拨号用户不会自动绑定飞书用户。
|
||||
@@ -0,0 +1,42 @@
|
||||
# SDD-007:内置飞书 OIDC 发行者
|
||||
|
||||
| 字段 | 内容 |
|
||||
|---|---|
|
||||
| 级别 | S3(公网身份入口、签名密钥、生产网关变更) |
|
||||
| 状态 | 实施中,尚未验证真实飞书登录 |
|
||||
| 日期 | 2026-10-22 |
|
||||
|
||||
## 1. 现状与目标
|
||||
|
||||
当前 OpenVPN OIDC 模式调用 `openvpn-auth-oauth2`,要求外部标准 issuer;`/api/tunnels/openvpn/oidc-readiness` 仅检测已安装插件与 HTTPS 管理入口。Nginx 只允许管理页面/API,其他路径返回 444;现有 LDAP 与密码专线均应保留。
|
||||
|
||||
增加单租户、单机部署的 Go `/id` 身份模块:飞书网页 OAuth 授权后,向插件提供受限的 OIDC authorization code 流程。仅已启用的管理员配置可提供发现文档、JWKS 与发码;不把登录成功视为自动获得 VPN 权限。沿用现有 HTTPS 域名及数据库,不引入外部身份服务器。
|
||||
|
||||
## 2. 功能与约束
|
||||
|
||||
- FR-01:管理员配置飞书 App ID/Secret(密钥不回显)、允许的 tenant key;系统生成并仅在服务端使用 VPN OIDC Client Secret,管理页面只显示 Client ID;复用现有 TLS 域名。
|
||||
- FR-02:提供 discovery、JWKS、authorize、飞书回调、token、userinfo;只接收登记的一个 HTTPS 回调地址,发放一次性短时 code;签发 RS256 ID Token。飞书返回的 open_id 与 tenant_key 组合成稳定 subject。
|
||||
- FR-03:OpenVPN 插件通过机密客户端交换授权码;客户端凭据、回调、nonce、state 绑定,存在 code_challenge 时校验 S256;不接受外部指定的上游 URL。
|
||||
- FR-04:前端展示 issuer、飞书回调及 VPN 回调、准备状态,允许选择内置 issuer 填写专线配置,但不覆盖既有配置。
|
||||
- FR-05:Nginx 仅允许同域 `/id/` 的固定身份端点转发到管理进程;`/oauth2/` 转发到单条已启动的认证组件(仅就绪后启用);其他未知路径保持 444。
|
||||
- NFR-01:签名密钥 0600、密钥材料不可回显,令牌与随机状态只保存哈希或受限数据;严格 TLS、过期时间、状态原子消费、请求限流及日志脱敏。
|
||||
- NFR-02:未启用或配置不完整时不发布可用 issuer,不破坏现有 OpenVPN/LDAP/管理入口。
|
||||
|
||||
## 3. 方案与契约
|
||||
|
||||
发行者建议 `https://<现有域名>/id`;只按 issuer 文档发布实际 URL,不假设根目录 discovery。飞书上游回调 `https://<现有域名>/id/feishu/callback`;插件回调 `https://<现有域名>/oauth2/callback`。飞书 App ID/Secret 只用于上游;插件使用系统生成的独立 VPN 凭据。数据加密利用现有 `secret.key`;RSA 签名私钥独立文件,备份必须同时包含数据库和密钥。
|
||||
|
||||
独立 `internal/identityprovider` 包承载协议逻辑和存储;`api` 管理路由只对管理员开放;Nginx 模板明确路由优先级。JWT 仅签发 `openid` 授权范围,不在令牌里包含飞书访问令牌。用户授权初期先采用飞书应用可用范围 + 明确租户约束;后续如需逐用户允许名单再增加独立配置。
|
||||
|
||||
接口参考 `/Users/logan/devops/demo/id/Feishu-OIDC-Workers` 的飞书官方端点定义与 JSON 换码格式;授权状态和客户端凭据隔离参考 `/Users/logan/devops/demo/id/dex` 的协议边界。没有复制其实现;Workers 示例把原始飞书 code 转交客户端的做法不用于本项目。
|
||||
|
||||
## 4. 风险与验收
|
||||
|
||||
| 风险 | 防护 / 恢复 |
|
||||
|---|---|
|
||||
| 伪造授权回调 / 重放 code | 随机 state 与 code、短有效期、数据库原子消费、精确 redirect URI 和客户端绑定 |
|
||||
| 泄露私钥或飞书密钥 | 0600 与 AES-GCM、API 不回显、部署时不传入对话中曾公开的旧密钥 |
|
||||
| 多专线共用 `/oauth2/` | 网关只选择唯一运行中的同域 OIDC 专线,冲突时不启用转发 |
|
||||
| 网关修改影响管理入口 | 先预览、备份现有站点、`nginx -t` 后 reload;失败恢复旧站点 |
|
||||
|
||||
验收:禁用与错误配置拒绝授权;模拟飞书服务测试完整码流、重放、错误租户、错误回调/nonce/PKCE、JWT 验签;真实飞书应用授权和 OpenVPN WebAuth 需单独联调。发布顺序:完成本地测试 → 部署但默认禁用 → 管理员轮换并保存飞书凭据 → 预览并启用网关 → 测试专线正/负向登录 → 再决定生产切换。恢复:禁用 issuer、恢复 Nginx 旧站点和旧二进制;不删除现有专线或密钥。
|
||||
Reference in new issue
Block a user