Skip to content

Latest commit

 

History

History
182 lines (136 loc) · 6.67 KB

File metadata and controls

182 lines (136 loc) · 6.67 KB

Keylo 安装向导设计说明

1. 背景

Keylo 当前采用 API-first 的轻量统一认证与授权中心定位,核心能力通过 HTTP API 暴露。用户管理、应用管理、品牌配置、登录体验、密钥轮换、多租户和审计可视化等业务管理能力并非所有系统都需要,且 Keylo 已提供接口供接入方按需开发。

当前主要痛点集中在首次部署:

  • 配置项较多:数据库、Redis、RSA 密钥、管理客户端、运行环境。
  • 启动默认 fail-fast,错误安全但对首次部署用户不够直观。
  • 用户需要从日志和文档中拼接初始化步骤。
  • 第三方服务接入前,需要先确认 discovery、JWKS、token endpoint 和 admin token endpoint 是否可用。

因此,Keylo 需要的是安装向导,而不是完整管理后台。

2. 产品边界

安装向导只解决“第一次跑起来”和“为什么没跑起来”。

包含:

  • 环境与依赖诊断。
  • 数据库连接状态。
  • migration 执行状态与 checksum 校验;首次 setup 尚未执行时该项为待处理提示,不会阻塞初始化。
  • Redis 配置与连通性状态。
  • JWT RSA 密钥状态;非生产环境未配置密钥文件时 Keylo 自动生成随机 RSA 密钥对并写入 JWT_PRIVATE_KEY_PATH / JWT_PUBLIC_KEY_PATH,生产环境必须预先提供固定密钥。
  • 管理客户端初始化状态。
  • 初始化完成后的接入端点摘要。

不包含:

  • 用户管理 UI。
  • 服务客户端管理 UI。
  • OAuth Provider 管理 UI。
  • RBAC 配置 UI。
  • 品牌、登录体验、多租户配置 UI。
  • 审计日志可视化。
  • 密钥轮换控制台。

上述能力继续通过 API 暴露,由使用方根据业务需要自行开发。

3. 安全原则

  • 安装向导默认启用;首次未完成 setup 时访问 / 会进入 /setup
  • 不需要安装向导时,可以显式设置 ENABLE_SETUP_WIZARD=false
  • 首次 setup 未完成时可以通过 /setup 执行初始化;初始化完成后接口返回 403,页面只显示只读状态。
  • 初始化完成后,setup API 返回 403,setup 页面显示已完成状态,不再执行初始化动作。
  • 安装向导不能绕过生产安全基线:生产环境仍要求 Redis 和固定 RSA 密钥。
  • 页面不展示已存在的密钥明文,也不回显管理客户端密钥;只有用户提交或生成时由用户自行保存。
  • 非生产环境自动生成的 RSA 公钥会通过 /.well-known/jwks.json 正常发布;生产环境不会接受本次启动自动生成的密钥,避免未经管理的密钥进入正式流量。
  • 数据库连接失败时,状态接口只返回稳定的修复提示;连接探测使用短超时,底层连接诊断只写入服务日志,避免匿名 setup 接口泄露 DSN 或凭据。
  • 初始化使用 PostgreSQL advisory lock 防止并发 seed;状态检查、seed 或完成标记失败时也必须释放该锁,保证修复配置后可以重试。

4. 配置项

新增配置:

配置 默认值 说明
ENABLE_SETUP_WIZARD true 是否启用安装向导路由
SETUP_KEYS_DIR ./keys 生成 RSA 密钥文件的目录

前端工程:

  • 安装向导 UI 位于 web/
  • 技术栈为 React + TypeScript + Vite。
  • 开发时运行 cd web && npm run dev,通过 Vite proxy 调用 Keylo 后端 setup API。
  • 发布时运行 cd web && npm run build,Keylo 后端从 web/dist 托管 /setup 页面与 /setup/assets/* 静态资源。

已有配置仍作为运行基线:

  • DATABASE_URL
  • Redis 密码密文配置:生产环境使用 REDIS_PASSWORD_ENC_FILE / REDIS_PASSWORD_KEY_FILE,host/port 使用普通环境变量,非生产调试才允许明文 REDIS_URL
  • JWT_ISSUER
  • JWT_KEY_ID
  • JWT_PRIVATE_KEY_PATH / JWT_PUBLIC_KEY_PATH
  • ADMIN_CLIENT_ID
  • ADMIN_CLIENT_SECRET 可在环境配置中提供;未配置时在 setup 页面录入

5. 路由设计

方法 路径 说明
GET /setup 安装向导页面
GET /setup/assets/* React 构建产物
GET /setup/status 返回安装诊断状态
POST /setup/initialize 执行初始化

5.1 GET /setup/status

checks 中的 redis 项会在 Redis 已配置时执行一次限时连通性探测。生产环境该项为必需检查;非生产环境未配置 Redis 时标记为可选通过,已配置但不可用时只显示安全的修复提示,不回显 Redis URL、凭据或底层连接错误。

返回字段:

{
  "enabled": true,
  "completed": false,
  "environment": "development",
  "admin_client_id_configured": true,
  "admin_client_secret_configured": false,
  "checks": [
    {
      "key": "database_url",
      "label": "Database URL",
      "ok": true,
      "required": true,
      "message": "DATABASE_URL is configured"
    }
  ],
  "endpoints": {
    "issuer": "https://identity.example.com",
    "jwks_uri": "https://identity.example.com/.well-known/jwks.json",
    "admin_token_endpoint": "https://identity.example.com/v1/admin/token",
    "service_token_endpoint": "https://identity.example.com/v1/service/token"
  }
}

5.2 POST /setup/initialize

请求体:

{
  "admin_client_id": "cli-admin-root",
  "admin_client_secret": "replace-with-strong-secret"
}

admin_client_secret 可省略;省略时 Keylo 会使用环境配置中的 ADMIN_CLIENT_SECRET。如果环境配置也未提供,则初始化请求会返回 400

行为:

  • 仅允许在 setup 未完成时执行。
  • 校验 setup 未完成。
  • 检查数据库连接。
  • 执行 migrations。
  • 创建或更新管理客户端。
  • 写入 system_settings.setup.completed=true
  • 返回接入端点摘要。

第一版不支持在线修改数据库地址和 Redis 地址。它们仍通过环境变量或容器编排系统提供。

6. 持久化设计

新增 system_settings 表:

CREATE TABLE IF NOT EXISTS system_settings (
    key TEXT PRIMARY KEY,
    value JSONB NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

关键设置:

  • setup.completed
  • setup.completed_at

7. 实施阶段

阶段一:安装向导 MVP

  • 新增 setup 配置。
  • 新增 system_settings migration 和 DB helper。
  • 新增 /setup/status/setup/initialize
  • 新增最小 HTML 安装页面。
  • 补 API 文档和集成测试。

阶段二:部署体验增强

  • 页面显示更细的诊断建议。
  • 支持复制 .env 示例。
  • 展示 discovery-lite 结果。
  • 提供 Docker Compose 场景说明。

阶段三:可选管理入口

只在确有需求时考虑。业务管理能力应继续保持 API-first,不作为 Keylo 核心安装向导的一部分。