多租户 IAM 架构设计与方案对比 — 隔离模式、实现与选型 | IDaaS Book
多租户 IAM 要解决什么问题
多租户(Multi-Tenancy)是 SaaS 平台和企业 IAM 系统中绕不开的架构命题。核心问题是:
在同一个 IAM 系统中,如何安全隔离不同租户(组织/客户/部门)的身份数据,同时保持运维效率和成本可控?
多租户 IAM 不是简单的"加一个 org_id 字段",它涉及:
- 数据隔离:租户 A 的管理员不能看到租户 B 的用户
- 认证隔离:租户 A 的用户不能登录到租户 B 的应用
- 授权隔离:租户 A 的权限策略不污染租户 B
- 可观测性隔离:租户 A 的审计日志不能让租户 B 看到
- 运维效率:新增一个租户的成本是分钟级还是天级?
关于 IAM 的整体架构设计思路,请参阅 IAM 架构设计指南;IAM 基础概念见 IAM 基础。
三种多租户 IAM 隔离模式
模式一:共享 IDP + 逻辑隔离
所有租户共享同一个身份提供者(IDP)实例,通过属性/组/组织单元做逻辑区分。
graph TB
subgraph "共享 IDP 实例"
IDP[IDP Server<br/>共享实例]
R[(身份存储)]
subgraph "租户 A"
UA[用户组 A]
PA[策略 A]
end
subgraph "租户 B"
UB[用户组 B]
PB[策略 B]
end
subgraph "租户 C"
UC[用户组 C]
PC[策略 C]
end
end
subgraph "应用层"
APP_A[应用 A]
APP_B[应用 B]
APP_C[应用 C]
end
UA --> IDP
UB --> IDP
UC --> IDP
IDP --> R
APP_A --> IDP
APP_B --> IDP
APP_C --> IDP
style IDP fill:#f9f,stroke:#333,stroke-width:2px
style R fill:#bbf,stroke:#333
实现方式:在 Keycloak 中用同一个 Realm,通过 Group、Role、Attribute 区分租户;在 Auth0/Okta 中用 Organization 特性。
适用场景:
- 租户数 < 100,且每个租户的用户数不大
- 所有租户使用相同的认证策略(同样的 MFA 要求、密码策略、Token 有效期)
- 内部平台或 B2E 场景,不需要面向外部客户的强隔离
- 开发团队规模小,运维自动化程度低
优点:
- 运维成本最低,只需维护一套 IDP 实例
- 新增租户是配置操作(创建一个 Group 或 Organization),分钟级完成
- 升级和补丁只需一次操作
缺点:
- 隔离强度弱——配置错误可能导致跨租户数据泄漏
- 无法为不同租户定制登录页、MFA 策略、密码复杂度
- 所有租户共享性能资源——一个租户的高负载可能影响其他租户
- 审计日志天然混在一起,需要应用层做过滤
模式二:独立 Realm / 独立实例
每个租户拥有独立的 IDP Realm 或完整的 IDP 实例,物理级隔离。
graph TB
subgraph "IDP 层"
subgraph "Realm A"
IDP_A[Realm A<br/>独立配置]
STORE_A[(存储 A)]
end
subgraph "Realm B"
IDP_B[Realm B<br/>独立配置]
STORE_B[(存储 B)]
end
subgraph "Realm C"
IDP_C[Realm C<br/>独立配置]
STORE_C[(存储 C)]
end
end
subgraph "应用层"
APP_A[应用 A]
APP_B[应用 B]
APP_C[应用 C]
end
APP_A --> IDP_A
APP_B --> IDP_B
APP_C --> IDP_C
IDP_A --> STORE_A
IDP_B --> STORE_B
IDP_C --> STORE_C
实现方式:在 Keycloak 中为每个租户创建一个 Realm;在高隔离要求下,每个 Realm 甚至可以对应独立的数据库 schema 或独立的 Keycloak 实例。
适用场景:
- 租户数 100~1000,且每个租户需要独立的安全策略
- B2B SaaS 平台(一个租户 = 一个外部企业客户)
- 需要为不同租户定制登录页、MFA、密码策略
- 合规要求(如 GDPR 数据驻留)需要物理隔离
- 部分租户有特殊的性能 SLA
优点:
- 隔离强度高——一个 Realm 的配置错误不会影响其他 Realm
- 每个租户可以独立定制:登录主题、MFA 策略、Session/Tokens 超时、密码策略
- 性能隔离——一个租户的高负载不会拖垮其他租户
- 可以按租户粒度做备份/恢复/导出
缺点:
- 运维成本显著增加——100 个 Realm 意味着 100 套配置要维护
- 新增租户需要创建 Realm、配置客户端、设置策略,自动化要求高
- 升级需要确保所有 Realm 兼容(Keycloak 版本升级可能涉及每个 Realm 的迁移)
- Keycloak 在 1000+ Realm 时会遇到性能瓶颈(需要仔细规划缓存和资源)
模式三:联邦 IDP + 租户自带身份
每个租户可能已有自己的 IDP(企业内部 AD/LDAP、Azure AD、Okta 等),IAM 平台作为联邦层,桥接多个上游 IDP。
graph TB
subgraph "联邦层(IAM 平台)"
FED[Federation Broker<br/>统一认证网关]
end
subgraph "租户自有 IDP"
T1[租户 A IDP<br/>Azure AD]
T2[租户 B IDP<br/>Okta]
T3[租户 C IDP<br/>自建 Keycloak]
T4[租户 D<br/>无自有 IDP<br/>使用平台账户]
end
subgraph "应用层"
APP1[应用 1]
APP2[应用 2]
APP3[应用 3]
end
T1 -- SAML/OIDC --> FED
T2 -- SAML/OIDC --> FED
T3 -- SAML/OIDC --> FED
T4 -- 本地账户 --> FED
FED --> APP1
FED --> APP2
FED --> APP3
style FED fill:#f9f,stroke:#333,stroke-width:2px
实现方式:Keycloak Identity Provider Broker、Dex、Pomerium 等作为联邦层,将不同上游 IDP 的认证结果统一转换为下游应用识别的 Token。
适用场景:
- 大型企业 / 集团,各子公司已有自己的 IDP
- B2B 平台,客户希望使用自己企业的 SSO(“Bring Your Own IDP”)
- 并购场景——需要快速整合被收购公司的身份系统
- 政府 / 跨组织协作,各方坚持使用自己的身份源
优点:
- 最大灵活性——租户保留对自己 IDP 的完全控制权
- 符合企业安全策略——租户不需要在外部平台创建账户
- 减少用户管理摩擦——租户用自己熟悉的账号密码登录
缺点:
- 联邦层成了新的单点——联邦网关不可用时所有租户都无法登录
- 调试复杂度高——一个登录失败可能涉及用户→上游IDP→联邦层→下游应用四跳
- 租户 IDP 的配置变更可能导致集成断裂(例如证书过期、端点变更)
- Token 转换可能丢失信息——上游 IDP 的 claims 不一定完整映射到下游
三模式对比一览
| 维度 | 共享 IDP | 独立 Realm | 联邦 IDP |
|---|---|---|---|
| 隔离强度 | 低(逻辑隔离) | 高(物理/逻辑隔离) | 高(各自独立 IDP) |
| 运维成本 | 低 | 中-高 | 中(联邦层需维护) |
| 新增租户速度 | 分钟级 | 分钟-小时级(自动化) | 天级(需协调客户 IDP) |
| 策略定制 | 受限 | 完全灵活 | 依赖上游 IDP 能力 |
| 性能隔离 | 无 | 可配置 | 天然隔离 |
| 合规支持 | 弱 | 强(可按 Realm 部署) | 强(数据不经过平台) |
| 适合租户数 | <100 | 100~5000 | 50~500 |
| 典型场景 | 内部平台、B2E | B2B SaaS、多客户 | 企业集团、BYOIDP |
多租户 IAM 选型决策树
graph TD
START[开始:选择多租户 IAM 模式] --> Q1{租户是否需要<br/>独立安全策略?}
Q1 -->|否| Q2{租户数 < 100?}
Q2 -->|是| SHARED[共享 IDP<br/>逻辑隔离]
Q2 -->|否| Q3{有自动化运维能力?}
Q3 -->|是| REALM[独立 Realm<br/>自动化管理]
Q3 -->|否| SHARED_OPT[共享 IDP +<br/>数据库级分片]
Q1 -->|是| Q4{租户是否有<br/>自有 IDP?}
Q4 -->|是| FED[联邦 IDP<br/>BYOIDP]
Q4 -->|否| Q5{租户数 > 500?}
Q5 -->|是| Q6{有 K8s/容器化<br/>运维能力?}
Q6 -->|是| REALM_K8S[独立 Realm<br/>Per-Tenant K8s Namespace]
Q6 -->|否| REALM_LITE[独立 Realm<br/>共享部署 + 按需扩容]
Q5 -->|否| REALM
style SHARED fill:#bfb,stroke:#333
style REALM fill:#bbf,stroke:#333
style FED fill:#fbf,stroke:#333
关键决策因素:
- 租户数量是最重要的分水岭:< 100 个租户,共享 IDP 通常够用;100~1000 个,独立 Realm 是主流;> 1000 个,需要考虑 Realm 的管理自动化甚至自研路由层
- 安全/合规要求是硬约束:只要有一个租户有 GDPR 数据驻留要求,就必须走独立 Realm 或联邦模式
- 运维能力决定天花板:独立 Realm 模式的"自动化新增 Realm"流程如果没做好,新增租户的周期会从分钟级变成天级
Keycloak 多租户实战要点
Keycloak 原生支持上述三种模式,以下是生产实践中的关键经验。
模式一落地:共享 Realm + Group 隔离
# 租户通过 Group 区分
# /Tenant-A/users/ → 租户 A 的用户
# /Tenant-B/users/ → 租户 B 的用户
# 每个租户的 Client 可以配置不同的 Scope 和 Mapper
# 关键配置:Client Scope 中的 Group Membership Mapper
# 确保 Token 中包含 group 信息,下游应用据此做权限判断注意事项:
- 必须严格限制租户管理员的 Group 管理权限,防止越权
- 审计日志中必须带上 group/tenant 维度,否则排查问题会非常痛苦
- 不要用 Realm Role 做租户隔离——Role 是跨 Group 的
模式二落地:Per-Tenant Realm
Keycloak 26 中,每个 Realm 是独立的配置域。自动化新增 Realm 的典型流程:
- 通过 Keycloak Admin REST API 创建 Realm(
POST /admin/realms) - 复制一份基础配置(Base Realm Partial Import):必需的 Client、Scope、Mapper
- 配置租户特定的 IdP(如果租户用 LDAP/AD)、自定义登录主题
- 创建初始管理员账户,发送激活邮件
# 获取 Master Realm 的 admin token
ADMIN_TOKEN=$(curl -s -X POST "https://idp.example.com/realms/master/protocol/openid-connect/token" \
-d "client_id=admin-cli" -d "username=admin" -d "password=$ADMIN_PWD" \
-d "grant_type=password" | jq -r '.access_token')
# 创建新 Realm
curl -X POST "https://idp.example.com/admin/realms" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"realm": "tenant-acme-corp", "enabled": true}'生产注意事项:
- Keycloak 在 1000+ Realm 时需注意 JVM 堆内存和 Infinispan 缓存配置,参见 Keycloak 集群缓存调优
- 定期清理不再使用的 Realm,避免配置膨胀
- 考虑 Realm 的数据库连接池独立配置(Keycloak 默认按 Realm 分配连接)
模式三落地:Keycloak Identity Provider Broker
在 Keycloak 中为每个租户创建一个 Identity Provider:
Identity Providers→Add provider→ 选择SAML v2.0或OpenID Connect v1.0- 配置租户的 IDP metadata URL 或手动输入端点
- 配置
mappers做属性映射(租户 IDP 的 group → Keycloak 的 group) - 在 Client 的 Authentication Flow 中把该 IdP 设为可选项
关于 OIDC 协议实现的详细原理,参见 OpenID Connect 深入解析。
常见误区
误区 1:「共享 IDP 不安全,必须独立 Realm」 事实:10 个以内租户的 B2B SaaS,共享 IDP + 严格的 Group 权限控制完全可以满足安全需求。过度隔离带来的运维成本可能远超安全收益。
误区 2:「多租户 = 多 Realm,一个租户一个 Realm」 事实:如果 80% 的租户都是 50 人以下的小团队,每个都建 Realm 是资源浪费。可以考虑混合模式——大客户独立 Realm,小客户共享 Realm+Group 隔离。
误区 3:「联邦 IDP 是万能解」 事实:BYOIDP 的调试成本极高。租户 IDP 配置错误、证书过期、SAML metadata 变更、OIDC discovery endpoint 不可达,每一个都会导致该租户所有用户无法登录。联邦层需要做好超时、降级和告警。
多租户 IAM FAQ
Q: 多租户 IAM 和 RBAC 是什么关系? A: RBAC(基于角色的访问控制)是授权模型,决定"谁能访问什么";多租户是架构模式,决定"谁的数据和谁隔离"。多租户 IAM 架构内部仍然使用 RBAC(或 ABAC/ReBAC)做权限管理。详请见 IAM RBAC、ABAC、ReBAC 授权模型对比。
Q: Keycloak 每个 Realm 的资源开销有多大? A: 一个空 Realm 约占用 5-10MB 内存和少量数据库记录。主要开销来自 Realm 内的 User/Session/Client 数量。1000 个轻度使用的 Realm 和一个有 10 万用户的单 Realm 相比,前者在 Infinispan 缓存上的开销更大。Keycloak 26 的 Infinispan 15 对此有明显改善,详见 Keycloak 高可用集群部署。
Q: 如何实现多租户的审计日志隔离?
A: 在 Keycloak 中,审计事件(Event)天然包含 realmId,如果使用共享 Realm+Group 模式,需要通过自定义 Event Listener 在事件中注入 group/tenant 信息。下游日志系统(如 ELK/Loki)按 tenantId 做索引分区。
Q: 多租户 SSO 如何实现?不同租户的用户可以互访吗? A: 标准做法是不允许跨租户 SSO——每个租户的 session 绑定在自己的 Realm/Group 内。但如果业务上需要(例如集团内跨子公司访问),可以通过身份联邦 + Token Exchange 实现,详见 身份联邦与代理。
Q: 多租户 IAM 的数据库应该怎么设计? A: 三种方式:(1) 共享数据库 + 共享表(tenant_id 字段过滤)——最低成本,最低隔离;(2) 共享数据库 + 独立 schema(每个租户一个 schema)——中等成本,中等隔离;(3) 独立数据库——最高成本,最高隔离。Keycloak 支持共享数据库 + 共享表(默认模式),也支持通过配置 JDBC 连接实现 schema 级隔离。生产环境数据库配置见 Keycloak PostgreSQL 生产数据库配置。
总结
多租户 IAM 没有银弹。选择取决于三个核心约束:
- 租户规模决定了隔离的最低要求
- 合规需求决定了隔离的上限
- 运维能力决定了你能驾驭的复杂度上限
从共享 IDP 起步,在租户数突破 100、出现差异化策略需求时切换到独立 Realm,在遇到 BYOIDP 客户时引入联邦层——这是最常见的安全增长路径。