3、证书链与权限映射:角色到权限的落地之路
证书链验证通过之后,下一步就是权限映射。说白了,就是拿着证书链里的身份信息,去决定「这个人能干什么」。这一步如果做不好,前面的加密和验证全白搭。
我个人习惯把权限映射分成两层:角色映射和属性映射。角色映射解决「你是谁」的问题,属性映射解决「你在什么条件下能做什么」的问题。两者结合,才是完整的权限隔离方案。
3.1 从证书链中提取角色信息
证书链的每一级证书,都可能携带角色信息。最常见的方式是通过 X.509 证书的扩展字段来传递。我常用的字段有三个:
| 字段 | 位置 | 典型值 | 说明 |
|---|---|---|---|
| Subject | 每个证书 | CN=admin, OU=IT, O=Company |
主体信息,包含组织、部门、通用名 |
| Extended Key Usage | 终端证书 | clientAuth, serverAuth |
客户端/服务器用途,可自定义 OID |
| Subject Directory Attributes | 任意证书 | role=auditor |
自定义属性,最灵活 |
举个例子。我在项目中遇到过这样一个场景:同一个 CA 签发的证书,有的用户是「只读审计员」,有的是「系统管理员」。怎么区分?就是在证书的 Subject Directory Attributes 里加了一个 role 属性。CA 签发时根据申请人的身份写入,后续权限系统直接读取。
核心原则:角色信息必须在签发时固化到证书里,运行时只读取不修改。这样可以防止权限篡改。
3.2 角色到权限的映射模型
拿到角色之后,怎么映射到具体的系统权限?我推荐用 RBAC(基于角色的访问控制) 作为基础框架。证书链中的角色对应 RBAC 中的角色,RBAC 中的角色再关联权限集合。
你想想看,这样做的好处是什么?解耦。证书只负责告诉系统「我是谁」,具体的权限定义在系统内部维护。哪天权限变了,不需要重新签发证书。
我习惯用一张映射表来管理:
| 证书角色 | 系统角色 | 权限集合 |
|---|---|---|
admin |
超级管理员 | 全部读写、用户管理、配置修改 |
operator |
运维操作员 | 服务启停、日志查看、告警配置 |
auditor |
审计员 | 只读日志、导出报表 |
viewer |
访客 | 仅查看公开信息 |
这里要注意一点:证书链可能有多个层级,每个层级都可能携带角色信息。比如根 CA 的角色是「CA 管理员」,中间 CA 的角色是「部门管理员」,终端证书的角色是「普通用户」。我建议以 终端证书的角色为准,上级证书的角色只用于验证链的合法性,不直接参与权限判定。
避坑指南:我曾经遇到过一个项目,把中间 CA 的角色也纳入了权限判定。结果某个中间 CA 被攻破后,攻击者直接用中间 CA 签发了高权限证书。从那以后,我坚持只信任终端证书的角色字段。
3.3 ABAC 与证书链的结合
RBAC 够用吗?说实话,大部分场景够了。但如果你需要更细粒度的控制,比如「只允许在工作时间访问」「只允许从内网 IP 访问」,那就得上 ABAC(基于属性的访问控制)。
ABAC 的核心思想是:权限判定不再只看角色,而是看一组属性。这些属性可以来自证书链,也可以来自上下文环境。
我画了一张图,展示 ABAC 与证书链的结合方式:
从图里可以看到,属性提取器从三个维度收集信息:
- 证书属性:角色、部门、组织、密钥用途等,直接从证书链解析
- 环境属性:请求时间、来源 IP、设备指纹、认证方式等
- 资源属性:资源的敏感级别、所属部门、操作类型(读/写/删)
策略引擎拿到这些属性后,去策略库匹配规则。规则通常写成 if-then 的形式。举个例子:
# 策略示例:审计员只能在工作时间查看低敏感资源
rule "auditor_access":
when
cert.role == "auditor"
and env.time between "09:00" and "18:00"
and resource.level == "low"
then
permit
else
deny
我的建议:ABAC 策略不要写得太复杂。我见过有人写了上百条规则,最后自己都搞不清优先级。保持策略数量在 20 条以内,每条规则只做一件事。
3.4 证书链属性传递的注意事项
证书链有多级,属性怎么传递?这是个容易踩坑的地方。我总结了几条经验:
- 属性只向下传递,不向上。根 CA 的属性可以影响中间 CA,中间 CA 的属性可以影响终端证书,但反过来不行。
- 同名属性以低层级为准。如果根 CA 和终端证书都定义了
role,以终端证书的为准。这样可以防止上级覆盖下级的权限。 - 敏感属性必须签名。比如
role=admin这种高权限属性,必须在签发时由 CA 签名,运行时验证签名有效性。
我曾经踩过的坑:有一次,我们允许终端证书通过 Subject Directory Attributes 自定义角色。结果有人把自己的角色改成了 admin,直接拿到了管理员权限。从那以后,我要求所有角色属性必须由 CA 签名,终端证书不能自行添加。
3.5 权限隔离的落地检查清单
最后,我分享一份检查清单。每次做证书链权限隔离方案时,我都会逐条过一遍:
| 检查项 | 说明 | 通过标准 |
|---|---|---|
| 角色来源唯一 | 角色信息只从终端证书读取 | 中间 CA 和根 CA 的角色不参与权限判定 |
| 属性签名验证 | 所有权限相关属性必须由 CA 签名 | 运行时验证签名,拒绝未签名属性 |
| 策略最小化 | ABAC 策略不超过 20 条 | 每条策略覆盖一个明确场景 |
| 属性传递规则 | 同名属性以低层级为准 | 测试用例覆盖属性覆盖场景 |
| 权限变更流程 | 权限变更不需要重新签发证书 | 修改系统角色映射表即可生效 |
嗯,这一章的内容就到这里。证书链与权限映射的核心,就是「用证书证明身份,用策略控制行为」。RBAC 解决大部分问题,ABAC 解决剩下的细粒度需求。两者结合,基本能覆盖 90% 的企业场景。