跳转至

为你的项目配置 OIDC

OIDC 是 Legate 在共享和生产环境中推荐的管理员认证方式。身份提供商负责证明“这个人是谁”,Legate 负责内部用户、平台管理员权限、工作空间成员关系、邀请、会话和最终授权。

Legate 没有本地密码数据库、密码重置或公开注册。切换到 OIDC 不会出现一个 Legate 用户名密码表单。

认证模型

Legate 明确区分三个对象:

对象 含义
User Legate 内部稳定用户,以数字 userId 参与授权
Identity 精确的 (providerId, OIDC subject) 外部身份绑定
Session 登录成功后创建的可撤销、不透明浏览器会话

返回用户只通过 (providerId, subject) 匹配。Legate 不会因为 OIDC email 相同就自动合并账号。Email 只在一次性首位管理员匹配和邀请认领时使用,并且必须来自 verified email claim。

前置条件

准备以下资源:

  • 一个支持 OIDC Authorization Code Flow 的身份提供商;
  • 可访问的 HTTPS issuer 和 discovery endpoint;
  • Legate 对外 HTTPS origin,例如 https://legate.example.com
  • 身份提供商中注册的 confidential client;
  • 客户端 ID 和客户端 secret;
  • 可被 Legate 读取的 secret file;
  • 一个新的或已完成身份迁移的 PostgreSQL 数据库;
  • 同源托管的 Legate Console,或经过严格设计的管理客户端。

生产配置要求 issuer、authorization、token 和 JWKS 等 OIDC endpoint 使用 HTTPS。Legate 只接受非对称 RS、PS 或 ES ID Token 签名算法,不支持跳过 issuer、签名或 TLS 验证的危险开关。

1. 在身份提供商创建客户端

为 Legate 创建 confidential OIDC client,并注册精确回调地址:

https://legate.example.com/api/auth/callback

建议至少允许以下 scopes:

openid email profile

openid 是必需 scope。使用 email 邀请或 email bootstrap 时,IdP 还必须返回经过验证的邮箱声明。

只注册实际使用的回调,不要使用通配符。Legate 的 --admin-public-url 必须与浏览器访问的 origin 一致。

2. 保存客户端 Secret

把 secret 放入独立普通文件,不要直接写进 Provider JSON:

install -d -m 700 /etc/legate/secrets
install -m 600 /dev/null /etc/legate/secrets/corp-oidc-client-secret

再通过秘密管理系统把真实值写入该文件。Kubernetes projected Secret 的符号链接可以使用,只要打开后的最终目标是普通文件。

Legate 启动时读取并修剪文件内容。空文件、非普通文件、无法读取或超过大小限制都会导致启动失败。Secret 不会出现在公开认证配置响应中。

3. 编写 Provider 配置

创建 /etc/legate/admin-oidc.json

{
  "entry": "page",
  "defaultProviderId": "corp",
  "providers": [
    {
      "id": "corp",
      "label": "Company SSO",
      "issuerUrl": "https://id.example.com/realms/company",
      "clientId": "legate-admin",
      "clientSecretFile": "/etc/legate/secrets/corp-oidc-client-secret",
      "scopes": ["openid", "email", "profile"],
      "enabled": true
    }
  ]
}

根字段:

字段 说明
entry page 显示登录方式列表;redirect 直接跳转默认 Provider
defaultProviderId 默认 Provider;redirect 模式必填且必须已启用
providers 1 到 32 个 Provider 配置

Provider 字段:

字段 说明
id 永久身份命名空间,小写字母开头,可含小写字母、数字、_-
label Console 展示名称
issuerUrl IdP 发布的精确 issuer URL
clientId OIDC client ID
clientSecretFile secret 文件路径
scopes 必须包含 openid
enabled 是否允许新登录并保留该 Provider 的会话路径

解析器拒绝未知字段、重复 JSON key、尾随 JSON、重复 Provider ID 和无效 URL。不要依赖拼写错误被忽略。

Provider ID 是身份边界

同一个 Provider ID 的 issuer 和 client ID 指纹不能被替换。迁移到新 issuer、租户或 client 时,请创建新的 Provider ID,并通过邀请或明确迁移流程绑定用户。

4. 配置首位平台管理员

新的 OIDC 数据库还没有可登录的平台管理员。推荐用精确 subject 配置一次性 bootstrap:

--admin-bootstrap-provider-id=corp
--admin-bootstrap-subject=exact-idp-subject

如果无法提前得到 subject,可以改用 verified email:

--admin-bootstrap-provider-id=corp
[email protected]

Subject 和 email 只能选择一个。第一个完全匹配的成功回调会在一个事务中:

  1. 创建内部用户;
  2. 绑定外部 identity;
  3. 授予平台管理员;
  4. 创建会话;
  5. 永久封存 bootstrap 标记。

封存后保留或修改这些启动参数都不会再创建第二位平台管理员。不要使用共享邮箱做 bootstrap,也不要在确认匹配人之前把服务暴露给用户。

已有可用平台管理员的数据库通常不需要 bootstrap 参数。

5. 启动 Legate

export LEGATE_DATABASE_DSN='postgres://legate:[email protected]:5432/legate?sslmode=require'

legate \
  --listen=:8080 \
  --redis-addr=redis.internal:6379 \
  --redis-prefix=legate-production \
  --admin-auth-mode=oidc \
  --admin-public-url=https://legate.example.com \
  --admin-oidc-providers-file=/etc/legate/admin-oidc.json \
  --admin-bootstrap-provider-id=corp \
  --admin-bootstrap-subject=exact-idp-subject

启动期间 Legate 会执行 OIDC discovery,并要求 discovery 文档中的 issuer 与配置精确相等。结构性错误、issuer 不匹配或不安全 endpoint 会阻止启动。

首次成功 discovery 会缓存经过验证的元数据。之后遇到临时网络故障时,可以使用完整缓存启动但暂停该 Provider 的新登录,并在后台有界重试。不要因为 IdP 临时故障切换到 disabled

6. 配置 HTTPS 入口

OIDC 的正常部署要求浏览器通过 --admin-public-url 指定的 HTTPS origin 访问 Console 和 /api。如果 TLS 在反向代理终止:

  1. Central 的监听端口不能被不受信任网络直接访问;
  2. 代理必须覆盖 HostX-Forwarded-ProtoX-Forwarded-For
  3. Central 只信任通过 --admin-trusted-proxy-cidr 配置的直接代理网络;
  4. 代理不能把客户端传入的 X-Forwarded-For 原样转发。

典型的 Nginx API 片段:

location /api/ {
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_pass http://legate-central:8080;
}

对应 Central 参数应精确到实际入口网络,例如:

--admin-trusted-proxy-cidr=10.20.30.0/24

不要为了省事信任整个集群、VPC 或 0.0.0.0/0。Legate 使用解析后的客户端 IP 对登录、回调和恢复请求限速。

会话与 CSRF

OIDC 登录使用 Authorization Code Flow、PKCE、nonce、一次性 state 和浏览器绑定。登录尝试保存在 PostgreSQL,因此回调可以落到任意 Central 副本。

正常会话:

  • 空闲超时 60 分钟;
  • 绝对超时 12 小时;
  • 浏览器只保存不透明 Cookie;
  • PostgreSQL 保存会话和 CSRF 值的 SHA-256 散列;
  • 退出、用户停用、身份禁用或 Provider 禁用会立即使相关会话失效。

生产 Cookie 使用 SecureHttpOnly 或受控可读属性、SameSite=LaxPath=/。修改状态的请求必须把 CSRF Cookie 值放入 X-Legate-CSRF。存在 Origin 时必须与 public URL 精确一致。

因此 OIDC Console 推荐同源部署。--admin-cors-origin 不是绕过 Cookie 和 CSRF 约束的办法。

邀请其他用户

OIDC 模式没有公开注册。平台管理员或目标工作空间的 admin 成员可以邀请新用户:

{
  "email": "[email protected]",
  "providerId": "corp",
  "role": "admin"
}

邀请有效期为 7 天。只有同一 Provider 返回的相同 verified email 可以认领邀请。认领后,权限来自 Legate 已保存的工作空间成员关系,而不是 OIDC claim 中的 group 或 role。

对于已经存在的用户,先按精确 email 解析内部 userId,再用 userId 加入工作空间。不要重复邀请已经激活的用户。

验证配置

启动后检查公开配置:

curl -fsS https://legate.example.com/api/auth/config | jq

应看到 mode: "oidc"、预期的登录方式和默认 Provider,但不应看到 client secret。

匿名访问当前用户接口应返回 401

curl -sS -o /dev/null -w '%{http_code}\n' \
  https://legate.example.com/api/auth/me

然后完成以下人工检查:

  1. 从 Console 发起登录,确认跳转到正确 IdP tenant。
  2. 确认回调返回同一 HTTPS origin。
  3. 完成首位管理员 bootstrap。
  4. 刷新页面,确认会话可以落到多个 Central 副本。
  5. 邀请一个非平台管理员并验证工作空间边界。
  6. 退出后确认旧会话立即失效。

恢复认证(可选)

恢复认证用于 IdP 登录路径全部不可用时,为一个已经存在的启用平台管理员换取 15 分钟恢复会话。它不能创建用户、不能授予平台管理员,也不能替代正常 OIDC。

生成 32 个随机字节的无填充 base64url Token:

openssl rand 32 \
  | openssl base64 -A \
  | tr '+/' '-_' \
  | tr -d '=' \
  > /etc/legate/secrets/admin-recovery-token
chmod 600 /etc/legate/secrets/admin-recovery-token

三个参数必须一起配置:

--admin-recovery-user-id=1
--admin-recovery-token-file=/etc/legate/secrets/admin-recovery-token
--admin-recovery-source-cidr=10.20.0.0/16

source CIDR 描述最终管理员客户端网络,不是入口代理网络。成功交换会撤销目标用户之前的会话。恢复 Token 应离线保管、定期演练,并限制能够读取文件和访问恢复源网络的主体。

本地 OIDC 开发

--admin-allow-insecure-local-oidc 允许隔离开发环境使用 HTTP,但所有 public、issuer、discovery、authorization、token 和 JWKS URL 都必须是:

  • localhost
  • *.localhost
  • 回环 IP。

该开关在其他认证模式或远程 HTTP endpoint 上会被拒绝。不要把它暴露到局域网。

Docker Compose 本机部署为了快速入门显式使用 --admin-auth-mode=disabled,不包含 IdP,不能用于验证 OIDC。OIDC 环境必须另外提供 HTTPS 同源入口和符合本页约束的 Provider;不要把入门 Compose 直接暴露到局域网或共享环境。

配置变更与上线

当前版本不支持 OIDC Provider、bootstrap 或 recovery 配置的混合版本滚动变更。每次改变这些配置时:

  1. 在所有目标节点渲染完全一致的参数、JSON 和 Secret;
  2. 预先验证 IdP discovery、回调、Secret、恢复用户和 CIDR;
  3. 停止接收管理请求并停止全部旧 Central 实例;
  4. 确认旧进程完全退出后应用配置;
  5. 使用相同二进制和字节一致配置启动所有实例;
  6. 验证公开配置、登录、会话撤销和恢复路径。

把 Provider 设置为 enabled: false 或从配置中删除会撤销它的 OIDC 会话,但不会删除用户、身份、邀请和工作空间成员关系。重新启用不会恢复已经撤销的会话。

生产检查清单

  • [ ] public URL 是精确 HTTPS origin。
  • [ ] IdP 回调只注册 /api/auth/callback 的精确地址。
  • [ ] Provider ID、issuer 和 client ID 已作为长期身份边界评审。
  • [ ] client secret 位于只读 Secret 文件,不在 JSON、镜像或日志中。
  • [ ] 首位管理员使用精确 subject;使用 email 时已确认 verified claim。
  • [ ] Central 监听端口不被入口之外的网络访问。
  • [ ] trusted proxy CIDR 只包含真实直接代理。
  • [ ] Console 与 API 同源,CSRF 流程未被代理破坏。
  • [ ] 至少有两条经过验证的平台管理员登录路径,或已配置恢复认证。
  • [ ] IdP 故障、Provider 禁用和 stop-all 配置变更已演练。