多云访问权限评审(IGA)实战:认证活动设计、职责分离 SoD 与审计举证闭环(2026)
访问权限评审(IGA,Identity Governance and Administration)是多云合规里最容易被做成形式主义的一环:企业把"最小权限"写进制度、把 RAM/IAM 策略收得很紧,却在审计时拿不出"这些权限在过去一个周期内仍然必要"的证据。
- 前言
- 为什么"已经最小权限"的组织仍会被审计打回
- 访问评审的四个环节与三类证据
- 架构图:一次季度评审活动的数据流
- 权限清单基线:三家云各能导出什么
- AWS:Access Analyzer 未使用权限分析 + 凭据报告实战
- 阿里云 RAM 与腾讯云 CAM:把权限快照固化下来
- 职责分离(SoD):把"不能同时拥有"写成规则
访问权限评审(IGA,Identity Governance and Administration)是多云合规里最容易被做成形式主义的一环:企业把"最小权限"写进制度、把 RAM/IAM 策略收得很紧,却在审计时拿不出"这些权限在过去一个周期内仍然必要"的证据。本文给出一套可直接落地的闭环:先用 AWS Access Analyzer 的未使用权限分析(按 IAM 角色与用户数以每主体每月 0.20 美元计费)、IAM 凭据报告,以及阿里云 RAM、腾讯云 CAM 的清单接口把"谁有什么"导成统一快照;再用职责分离(SoD)规则引擎做静态冲突检测;然后按主体类型分配评审人与周期(特权 90 天、生产 180 天、只读 365 天);最后把"批准撤销"变成 IaC 变更而不是控制台手删。文中含一次 400 人、460 个主体的季度评审成本复算:人工基线 338.8 小时/年、约 20,328 美元,自动化后 174.8 小时/年、合计 12,792 美元,工时降 48.4%、总成本降 37.1%。
Meta Description: 多云访问权限评审(IGA)实战:AWS Access Analyzer 未使用权限分析、阿里云 RAM 与腾讯云 CAM 权限快照归一化、SoD 冲突规则、认证活动设计与 400 人规模成本复算。
关键词:访问权限评审、IGA、访问认证活动、职责分离、SoD、权限蔓延、多云合规、SOC 2、ISO 27001
前言
出海企业的合规审计有一个共同特征:审计师不问"你们的策略写得严不严",而问"你多久证明一次这些权限还有人用、还有必要"。前者是配置问题,一次性就能答完;后者是流程问题,需要连续多个周期的证据链。
这条链最容易断在三个地方。第一,权限清单不完整——只拉了"直接绑定到用户"的策略,漏掉用户组继承和角色链继承,覆盖率看起来 98%,实际 70%。第二,只有清单没有使用证据——评审人面对一张"张三有 43 项权限"的表,只能全部点"批准",因为没人知道哪条三个月没被用过。第三,决策不落地——评审会开完、Excel 签了字,线上权限一条没变,下一个周期同样的问题再来一遍。
本文不讲 IGA 的产品概念,只讲工程实现:怎么把三家云的权限导成同一张表、怎么用官方的使用数据减少评审人的判断负担、怎么把 SoD 规则写成代码在 CI 里跑、以及怎么让"撤销"这个动作真的发生并且可以举证。
一、为什么"已经最小权限"的组织仍会被审计打回
最小权限(least privilege)描述的是授予时刻的属性:这条策略是否只包含完成工作所必需的动作和资源。权限蔓延(privilege creep)描述的是时间维度的问题:随着项目迭代、人员轮岗、故障应急,权限只增不减,三年后一个"只负责报表"的账号拥有生产数据库的写权限。
这两件事的治理手段完全不同。前者靠策略评审、Permission Boundary、SCP 和访问分析器;后者只能靠周期性认证——把"这条权限还要不要"这个问题,定期推给一个有权回答它的人,并留下他回答过的记录。
审计标准里的落点很明确:
| 标准 | 条款 | 审计师实际要什么 |
|---|---|---|
| SOC 2 | CC6.1 / CC6.2 / CC6.3 | 逻辑访问的授予、变更、撤销有审批记录;撤销在离职/转岗后及时发生 |
| ISO/IEC 27001:2022 | A.5.15 访问控制、A.5.18 访问权限 | 按既定周期复核访问权限,复核结果有留痕 |
| ISO/IEC 27001:2022 | A.8.2 特权访问权限 | 特权账号受限、受监控、定期复核 |
| 等保 2.0(三级) | 访问控制、身份鉴别 | 账户权限最小化、定期检查、离岗账号及时处置 |
注意 A.5.18 的措辞是"at regular intervals"——它不要求你实时完美,它要求你有节奏、有记录、有回收。反过来说,一个每季度真跑、证据完整的评审活动,比一个号称"实时最小权限"但拿不出记录的系统更容易过审。
三种最常见的"假最小权限"现场:
- 角色只增不减。为一次故障开的
prod-emergency-admin角色,故障结束后没人删,半年后成了值班人员的日常入口。这类角色通常还带iam:*或sts:AssumeRole的宽授权。 - 权限靠复制。新人入职时"照着小王的权限配一份",小王的权限本身是三年前堆出来的。复制不会引入新的越权,但会把历史债务按人数放大。
- 服务账号无主。CI/CD、监控 Agent、备份任务用的访问密钥,创建人是已离职的工程师,业务方说"不敢删,怕流水线挂"。这类主体在任何"按人评审"的流程里都是盲区。
第三条尤其致命:多数企业的评审活动按"员工名单"组织,而云上真正高权限的主体里,有相当比例是非人类身份(NHI)。如果把服务账号排除在评审范围外,审计师抽样抽到一个三个月未轮转的 CI 密钥,整个控制项就会被判失效。
二、访问评审的四个环节与三类证据
把 IGA 拆成工程环节,只有四步,每步都有明确的输入输出:
| 环节 | 输入 | 输出 | 失败表现 |
|---|---|---|---|
| 权限清单(Inventory) | 各云账号的 API | 归一化的主体-权限快照 | 漏继承,覆盖率虚高 |
| 使用证据(Usage) | 访问分析器、凭据报告、审计日志 | 每条权限的最后使用时间 | 只有清单,评审人无法判断 |
| 认证决策(Certification) | 快照 + 证据 + 评审人 | 批准/撤销/降级/限期例外 | 全部批准,等于没评 |
| 回收与举证(Remediation & Evidence) | 决策记录 | 线上权限变更 + 证据包 | 签了字没执行 |
对应地,审计师会索要三类证据,缺一类就要解释:
- 清单快照:某个时间点上"谁(主体)对什么(资源/动作)有什么权限"。要求可复现——同一个脚本、同一天重跑,结果一致。
- 使用证据:这条权限在过去 N 天内是否被使用过。这一条决定了评审是"判断"还是"盖章"。
- 决策记录:谁、在什么时间、基于什么理由,批准或撤销了哪一条权限。要求能对应到具体主体和具体权限项,而不是"本季度已完成权限复核"一句话。
这里有一个常见误解需要先破掉:认证(attestation)不是技术审计。技术审计问"配置是否符合基线",认证问"业务上是否仍然需要"。所以评审人不能是安全团队——安全团队没有立场判断"财务系统分析师是否需要导出全部凭证",只有该员工的直属经理或该系统 Owner 能回答。安全团队的角色是设计流程、提供证据、抽样复核、跟踪回收,而不是替业务做决定。
三、架构图:一次季度评审活动的数据流
下面是一条可落地的最小链路。左侧是采集,中间是归一化与规则,右侧是决策与执行。整条链路的关键设计是:采集与决策解耦,采集每周跑一次自动落库,决策按周期批量发起;这样评审人看到的永远是最新快照,而不是活动启动那天导出的过期 Excel。
flowchart LR
subgraph CLOUD["云账号层"]
A1["AWS 组织<br/>12 个账号"]
A2["阿里云 RAM<br/>主账号 + 资源目录"]
A3["腾讯云 CAM<br/>主账号 + 成员账号"]
end
subgraph COLLECT["采集层(每周定时)"]
B1["IAM API<br/>list-users / list-roles"]
B2["RAM API<br/>ListUsers / ListPoliciesForUser"]
B3["CAM API<br/>ListUsers / ListAttachedUserPolicies"]
end
subgraph NORM["归一化与证据"]
C1["统一主体-权限表<br/>subject / entitlement / last_used"]
C2["使用证据<br/>Access Analyzer / 凭据报告 / 审计日志"]
C3["SoD 规则引擎<br/>冲突对 + 例外台账"]
end
subgraph REVIEW["认证活动"]
D1["按主体类型分配周期<br/>特权90d 生产180d 只读365d"]
D2["评审任务分发<br/>经理 + 资源 Owner 双轨"]
D3["决策<br/>批准 / 撤销 / 降级 / 限期例外"]
end
subgraph EXEC["回收与举证"]
E1["IaC 变更<br/>Terraform PR + apply"]
E2["线上验证<br/>权限探针 + 403 计数"]
E3["证据包<br/>快照 + 决策 + 执行回执"]
end
A1 --> B1
A2 --> B2
A3 --> B3
B1 --> C1
B2 --> C1
B3 --> C1
C1 --> C2
C2 --> C3
C3 --> D1
D1 --> D2
D2 --> D3
D3 --> E1
E1 --> E2
E2 --> E3
E3 -.->|下一周期基线| C1
这条链路里有两个容易被省略但决定成败的部件:
其一,last_used 字段必须来自官方数据,不能靠推测。 AWS 提供主体级的服务最后访问时间(generate-service-last-accessed-details)和未使用权限分析器;阿里云 RAM 提供 AccessKey 粒度的最后使用时间(GetAccessKeyLastUsed);腾讯云 CAM 的 ListAccessKeys 返回里没有最后使用时间字段,只能用 CloudAudit 的事件反查。三家能力不对等,所以归一化表里要允许该字段为 unknown,并把 unknown 单独统计——它不是"没用过",而是"没有证据",处置方式不同(前者建议撤销,后者建议先补采集)。
其二,例外必须有到期日。 评审中最常见的产物不是"撤销",而是"这次先留着"。如果例外没有强制到期,它会变成永久权限,且明年评审时评审人看到"历史上已批准",更容易继续批准。规则很简单:例外表必须有 expires_at,到期自动回到待评审队列,超过两次续期自动升级到安全负责人。
四、权限清单基线:三家云各能导出什么
做归一化之前,先要接受一个事实:三家云能导出的字段并不对等。如果按能力最全的那家(AWS)设计表结构,另外两家的必填字段就会永远为空;如果按最弱的那家设计,又会丢掉最有价值的未使用证据。正确做法是"宽表 + 证据等级":字段尽量全,但对每条记录标注证据强度(verified / derived / unknown)。
三家的采集能力对照:
| 能力 | AWS | 阿里云 RAM | 腾讯云 CAM |
|---|---|---|---|
| 主体清单 | iam list-users / list-roles | ram ListUsers / ListRoles | cam ListUsers / ListRoles |
| 直接绑定策略 | list-attached-user-policies / list-role-policies | ListPoliciesForUser | ListAttachedUserPolicies |
| 组继承 | list-groups-for-user + list-attached-group-policies | ListGroupsForUser + ListPoliciesForGroup | ListGroupsForUser + ListAttachedGroupPolicies |
| 权限边界 / 条件 | get-role 的 PermissionsBoundary + 策略 Condition | 策略 Version 里的 Condition | 策略文档 condition |
| 服务级最后访问 | generate-service-last-accessed-details | 无官方等价接口,需 ActionTrail 反查 | 无官方等价接口,需 CloudAudit 反查 |
| 密钥最后使用 | 凭据报告 access_key_N_last_used_date | GetAccessKeyLastUsed | ListAccessKeys 不含该字段,需事件反查 |
| 主体级未使用分析 | Access Analyzer unused access(可组织级) | 无 | 无 |
| 组织级汇总 | Organizations + 组织级分析器 | 资源目录(Resource Directory) | 成员账号 + 主账号视角 |
三条实操结论:
- "直接绑定"永远不等于"实际权限"。 三家的
List*PoliciesForUser类接口都只返回直接绑定到该主体的策略,不包含经用户组继承的部分。只拉直接绑定,覆盖率会系统性偏低,而且漏掉的恰好是最常见的授权方式(把策略挂到组、人放组里)。必须补一次组展开。 - 需要"角色链"展开。 如果企业用"人 → 组 → 角色 → 信任链"的模式(AWS 的
sts:AssumeRole、阿里云的 RAM 角色扮演),清单里要记录可传递性:谁能扮演谁。这条边不进表,后面的 SoD 检测就查不出"通过扮演角色绕过职责分离"的路径。 - 别只取第一页。 三家接口都分页,默认页大小通常 100 条上下。400 人规模的组织,用户列表就要翻 4 到 5 页;漏了第二页,缺口正好出现在按创建时间排序的末尾——通常是最近入职的人,也是审计抽样最爱抽的人。
归一化后的表结构建议如下(字段名保持英文,便于脚本与 BI 直接消费):
{
"subject_id": "arn:aws:iam::111122223333:role/AppDeploy",
"subject_type": "role",
"provider": "aws",
"account": "111122223333",
"display_name": "AppDeploy",
"owner": "platform-team",
"entitlement": "s3:PutObject",
"scope": "arn:aws:s3:::prod-assets/*",
"grant_type": "attached_policy",
"granted_at": "2025-11-04T08:12:00Z",
"last_used_at": "2026-09-18",
"evidence_level": "verified",
"risk_flags": ["write_prod", "no_mfa_boundary"]
}
evidence_level 这个字段是整套方案的核心设计。它的取值规则:
verified:来自云厂商官方接口的使用时间(AWS 服务最后访问、凭据报告、阿里云 AccessKey 最后使用)。derived:从审计日志事件反推(腾讯云 CloudAudit、阿里云 ActionTrail),有时间窗偏差,通常只能给到"某天出现过"。unknown:没有任何使用证据。这类记录不能按"未使用"直接撤销,要先补采集或人工确认,否则误删会打穿生产。
五、AWS:Access Analyzer 未使用权限分析 + 凭据报告实战
AWS 是三家云里唯一提供主体级未使用权限分析的。它有两个关键参数需要理解清楚,否则会得出错误结论。
第一,跟踪期(tracking period)是 1 到 365 天,不是固定档位。官方文档的措辞是:分析器只评估"在所选跟踪期内始终存在的 IAM 实体",也就是说跟踪期设 90 天,只有存在满 90 天的权限才会被分析,且在这 90 天内无使用才会产生 finding。这带来一个直接推论:跟踪期必须大于等于你的评审周期,否则每次评审都会有一批"新权限"永远不出结论,而这批恰好是权限蔓延最快的那部分。
第二,未使用分析的 finding 不随区域变化。同一账号在多个区域开分析器不会得到不同结果,所以不需要按区域创建——这是纯浪费。代价结构是按"被分析的 IAM 角色与用户数 × 每月 × 每个分析器"计费,单价 0.20 美元/主体/月,官方算例是 70 个角色与用户 14 美元/月、850 个 170 美元/月。
创建组织级分析器(覆盖组织内全部账号,跟踪期 90 天):
aws accessanalyzer create-analyzer \
--analyzer-name unused-access-org \
--type ORGANIZATION_UNUSED_ACCESS \
--configuration '{"unusedAccess":{"unusedAccessAge":90}}'
字段名以 aws accessanalyzer create-analyzer help 的当前版本为准;控制台上的同一参数叫 Tracking period,允许 1–365 天的任意整数。创建后 finding 不会立刻出现——需要等分析器积累够数据,官方明确说"创建或更新分析器后,finding 需要一段时间才可用",所以排期上要把"建分析器"放在活动启动前的两周,而不是活动当天。
拉取 finding(v2 接口,返回结构比 v1 更适合批量处理):
aws accessanalyzer list-findings-v2 \
--analyzer-arn arn:aws:access-analyzer:us-east-1:111122223333:analyzer/unused-access-org \
--filter '{"findingType":{"eq":["UnusedPermission"]}}' \
--max-results 100 \
--output json > findings.json
注意 --max-results 有上限且返回带 nextToken,必须循环翻页直到 nextToken 为空。只取第一页是这类脚本最常见的静默缺陷:脚本"跑成功了",但只处理了 100 条。
第二路证据是 IAM 凭据报告,它给出人这一侧的密钥与密码使用情况,是发现"长期不用的 AccessKey"和"未开 MFA 的高权限账号"最快的手段:
aws iam generate-credential-report
aws iam get-credential-report --query Content --output text | base64 -d > creds.csv
报告是 CSV,关键列包括 user、password_enabled、password_last_used、mfa_active、access_key_1_active、access_key_1_last_used_date、access_key_1_last_rotated。注意两个坑:generate 是异步的,刚生成时 get 可能返回 State: STARTED,要轮询到 COMPLETE;以及 password_last_used 对从未登录的用户是 no_information 而不是空值,脚本里要把这个字符串单独处理,否则日期解析会抛异常。
把 CSV 变成"待处理清单"的最小脚本(无第三方依赖):
import csv, datetime
now = datetime.datetime.now(datetime.timezone.utc)
rows = list(csv.DictReader(open("creds.csv", encoding="utf-8")))
stale = []
for r in rows:
for n in ("1", "2"):
if r.get("access_key_%s_active" % n) != "true":
continue
last = r.get("access_key_%s_last_used_date" % n) or "N/A" # 从未使用是 N/A
if last in ("N/A", "no_information"):
age = 9999
else:
age = (now - datetime.datetime.fromisoformat(last + "T00:00:00+00:00")).days
if age > 90:
stale.append((r["user"], n, last, age))
for s in sorted(stale, key=lambda x: -x[3])[:20]:
print(s)
这段脚本给出的榜单,通常是评审活动的第一份"高置信度撤销清单"——从未使用且创建超过 90 天的密钥,几乎没有保留理由。
六、阿里云 RAM 与腾讯云 CAM:把权限快照固化下来
阿里云和腾讯云没有 AWS 那种主体级未使用分析,但这不影响做 IGA,只是"使用证据"这一列要靠别的方式补。采集侧的重点是把继承关系拉全。
阿里云 RAM 的采集顺序(先人、再组、再策略):
aliyun ram ListUsers --MaxItems 100
aliyun ram ListGroupsForUser --UserName alice
aliyun ram ListPoliciesForUser --UserName alice
aliyun ram ListPoliciesForGroup --GroupName data-readonly
aliyun ram ListAccessKeys --UserName alice
aliyun ram GetAccessKeyLastUsed --UserAccessKeyId LTAI5tExampleKeyId
GetAccessKeyLastUsed 返回的是该密钥最后一次被调用的时间;参数名以 aliyun ram GetAccessKeyLastUsed --help 为准。这里有个能力边界要写进文档:它只覆盖 AccessKey,不覆盖控制台登录,也不覆盖角色扮演。所以对"只通过控制台操作"的员工,这个字段会显示从未使用,但人其实天天在操作——直接把这类记录判为"未使用"会造成误撤。正确做法是同时拉 ActionTrail 的登录与 API 事件做交叉验证,并把结果标为 derived。
腾讯云 CAM 的坑更具体:ListAccessKeys 返回的字段里没有最后使用时间。要判断一把密钥是否还在用,只能查 CloudAudit(云审计)的事件,用 LookupEvents 按主体和时间窗反查:
tccli cam ListUsers --Limit 100
tccli cam ListGroupsForUser --Uin 100012345678
tccli cam ListAttachedUserPolicies --TargetUin 100012345678
tccli cam ListAttachedGroupPolicies --TargetGroupId 1234
tccli cam ListAccessKeys --TargetUin 100012345678
tccli cloudaudit LookupEvents --StartTime "2026-07-01 00:00:00" \
--EndTime "2026-09-30 23:59:59" \
--LookupAttributes '[{"AttributeKey":"Username","AttributeValue":"alice"}]'
CloudAudit 默认只保留一段时间的事件(各账号可能不同,常见为 90 天),这意味着跨度 180 天的评审,前 90 天的证据在日志里已经不存在了。这不是脚本问题,是数据保留期问题。处置有两条:一是把审计日志投递到 COS 并设置生命周期保留 365 天以上(成本很低,一个几百人规模的组织每月事件量通常在几十 GB 以内);二是在评审报告里明确"使用证据窗口 = 90 天",并把这一口径写给审计师,而不是假装覆盖了 180 天。
三家云横向对比,值得记住的是这张"证据可得性"表——它决定了你的评审结论有多硬:
| 证据类型 | 可得性 | 时间精度 | 可信度 | 适用判断 |
|---|---|---|---|---|
| 云厂商未使用分析器 finding | 仅 AWS | 天 | 高(官方口径) | 直接进撤销清单 |
| 凭据报告 / AccessKey 最后使用 | 三家均可 | 天 | 高 | 密钥轮转与清理 |
| 审计日志事件反查 | 三家均可 | 秒级但受保留期限制 | 中 | 交叉验证、控制台操作 |
| 服务级最后访问 | 仅 AWS | 天 | 高 | 精细化到动作级 |
| 人工访谈确认 | 三家均可 | 无 | 低(不可举证) | 仅作补充,不能单独作为撤销依据 |
最后一行值得强调:审计师不接受"我问过业务方,他说不用了"作为撤销依据。可以接受的是"系统显示该权限 137 天未使用,业务方在活动内确认撤销,决策记录见附件"。人的确认要有,但必须挂在机器证据上。
七、职责分离(SoD):把"不能同时拥有"写成规则
访问评审解决"这条权限还要不要",职责分离解决"这两个权限能不能落在同一个人身上"。后者是前者的前置过滤:一个同时拥有"发起付款"和"审批付款"的人,即使两项权限都"在用",也必须拆开——这类冲突不是靠评审人判断,而是靠规则直接判红。
云上做 SoD 与 ERP 时代最大的区别是粒度。ERP 的 SoD 按事务码(t-code)划分,一个人能不能同时持有 A 事务码和 B 事务码是明确的;云上的权限是"动作 × 资源"的二维集合,同一个策略包里可能混着读写,同一组动作在不同云上叫法不同。所以规则必须定义在语义动作对上,再映射到各云的实际 action。
六条在出海企业里复现率最高的规则:
| 规则 | 冲突动作对 | 云上映射示例 | 风险 |
|---|---|---|---|
| SOD-01 | 生产代码写入 × 生产变更审批 | codecommit:GitPush / cp:PushRepository 与流水线人工卡点审批 | 自审自发布,变更管控失效 |
| SOD-02 | 密钥管理 × 数据解密 | kms:CreateGrant 与 kms:Decrypt 同主体 | 可自行授权访问任意加密数据 |
| SOD-03 | 审计日志停用/删除 × 被审计业务操作 | cloudtrail:StopLogging、log:DeleteLogStore | 操作后销毁痕迹 |
| SOD-04 | 身份与授权变更 × 安全审计 | iam:PutRolePolicy、ram:AttachPolicyToUser 与安全审计只读 | 自我提权并规避审计 |
| SOD-05 | 备份删除 × 生产数据库运维 | backup:DeleteBackupVault、s3:DeleteObject 与 RDS 写权限 | 勒索场景下无回滚能力 |
| SOD-06 | 全量数据导出 × 客户数据访问审批 | 对象存储批量下载与数据访问审批权 | 批量外带客户数据 |
规则写成代码,进版本库,随清单快照每次采集后执行。用 YAML 描述,便于安全团队自己维护:
version: 1
rules:
- id: SOD-02
name: 密钥管理与解密不可同体
severity: high
left:
aws: ["kms:CreateGrant", "kms:PutKeyPolicy"]
aliyun: ["kms:CreateKey", "kms:ScheduleKeyDeletion"]
tencent: ["kms:CreateKey", "kms:DisableKey"]
right:
aws: ["kms:Decrypt", "kms:GenerateDataKey"]
aliyun: ["kms:Decrypt"]
tencent: ["kms:Decrypt"]
scope: same_account # 同账号内即判冲突
exception_max_days: 30 # 例外最长 30 天,到期自动复活为待评审
评估逻辑本身很简单:把每个主体的有效权限展开成 (action, resource) 集合,对每条规则判断左右集合是否同时非空。真正的工作量在动作归一化——同一语义在不同云上的命名差异,以及通配符的展开。
通配符是这里最容易被忽视的漏洞。一条 s3: 或 oss: 在文本层面看不出任何冲突,展开后却同时命中了左集合和右集合。所以评估前必须做动作展开:用各云的动作清单(AWS 的 policies.js 服务授权参考、阿里云的策略语法文档、腾讯云的 CAM 权限列表)把 和 service: 展开成具体动作,再做集合运算。不做这一步,SoD 检测的召回率会低得离谱——而恰恰是那些"图省事写了全通配"的账号风险最高。
跨云语义映射表(示例,实际项目建议维护到 100 条以上):
| 语义 | AWS | 阿里云 | 腾讯云 |
|---|---|---|---|
| 对象写入 | s3:PutObject | oss:PutObject | cos:PutObject |
| 对象公开读 | s3:PutObjectAcl | oss:PutObjectAcl | cos:PutObjectACL |
| 数据库写入 | rds-data:ExecuteStatement | rds:ExecuteStatement | cdb:* 写类动作 |
| 密钥解密 | kms:Decrypt | kms:Decrypt | kms:Decrypt |
| 密钥策略变更 | kms:PutKeyPolicy | kms:PutKeyPolicy | kms:PutKeyPolicy |
| 日志删除 | logs:DeleteLogGroup | log:DeleteLogStore | cls:DeleteLogStore |
一个经验法则:先做语义层,再做厂商层。如果规则直接按各云的 action 名写死,第二年厂商改一次权限命名就要全量返工;把语义作为主键,映射表作为配置,规则库就能活过版本升级。
八、认证活动设计:评审人、周期、决策分类与超时策略
认证活动(campaign)是 IGA 的执行单元:一次活动有明确的范围、期限、评审人集合和决策口径。设计得好不好,看四个参数。
参数一:周期按主体类型分层,不要一刀切。 全组织统一"每年一次"是最省事也最没用的设计——特权账号在 12 个月里可以做很多事,而一个只读报表账号每周评审一次纯属浪费评审人时间。
| 主体类型 | 建议周期 | 评审人 | 说明 |
|---|---|---|---|
| 特权/管理员(含 break-glass) | 90 天 | 安全负责人 + 系统 Owner 双签 | 数量少、风险高,值得双签 |
| 生产环境写权限 | 180 天 | 直属经理 | 覆盖人数最多的一档 |
| 只读 / 分析 / 报表 | 365 天 | 资源 Owner 批量确认 | 可按组评审,降低碎片化 |
| 服务账号 / CI 密钥 | 随季度 + 任何变更触发 | 平台团队 Owner | 变更触发优先于周期 |
| 外部协作账号 | 90 天或合同到期日 | 业务对接人 + 安全 | 取两者较早者 |
参数二:评审人按"能回答这个问题的人"分配,双轨而不是单轨。 实践中两种模式各有盲区:
| 模式 | 覆盖维度 | 强项 | 盲区 |
|---|---|---|---|
| 经理评审(manager review) | 人 | 知道这个人在做什么项目、是否需要该权限 | 不懂技术细节,看不懂 s3:PutObjectAcl 意味着什么 |
| 资源 Owner 评审(owner review) | 权限 | 懂这条权限的风险等级 | 不认识人,看到陌生主体容易一律拒绝或一律批准 |
结论是双轨:人对人用经理,权限对权限用 Owner。矩阵型组织里单轨会失效——一个员工同时服务三条业务线,他的经理只知道自己那条线的需求,另外两条线的权限在他眼里全是"可疑"。
参数三:决策必须是四选一,不是"保留/撤销"二选一。 只有两个选项会逼评审人选"保留",因为撤销看起来像在惩罚人。给出降级选项,评审人就有了中间地带:
| 决策 | 语义 | 后续动作 | 统计口径 |
|---|---|---|---|
| Approve | 权限仍然必要 | 记入基线,下周期再评 | 批准率 |
| Downgrade | 方向对但过大 | 换成只读 / 限定资源范围 / 缩短会话时长 | 降级率(健康指标) |
| Revoke | 不再需要 | 立即进入回收队列 | 撤销率 |
| Exception | 暂时保留,限期 | 写入例外台账,带 expires_at | 例外率与过期率 |
如果一次活动里降级率和撤销率都是 0,基本可以判定这次评审是走过场——正常组织的权限只增不减,第一次认真评审一定会撤掉一批。
参数四:超时默认要 fail-closed,但要给缓冲。 到期未决策的记录,默认按"撤销"处理,这是审计上唯一站得住的口径(不能因为评审人没空就默认保留)。但直接撤销会误伤:很多评审人只是漏看了邮件。折中是两次提醒 + 7 天宽限 + 到期自动撤销并抄送其经理,同时把"超时撤销"单列为一项指标,按月看趋势——如果超时率高,问题在流程不在人。
另外一个细节常被忽略:要不要给评审人看"最后使用时间"。两种做法都有依据。显示使用证据能显著提高撤销率,但也诱导评审人只按"有没有用过"做决定,忽略"虽然没用但必须有"的合规权限(比如审计只读、灾备切换权限)。可行的折中是:显示使用时间,同时在界面上强制要求填写一句理由(不少于 10 个字),并对"使用时间为空但被批准"的记录做 100% 复核。
最后是抽样。安全团队对已完成的决策做 10% 随机抽检,抽检对象优先包含三类:批准了从未使用的权限、批准了 SoD 冲突例外、由本人评审本人的记录。第三类如果出现,说明评审人分配逻辑有 bug,属于流程缺陷而不是个案。
九、回收执行:从"批准撤销"到"权限真的消失"
这是整条链路里最容易断的一环,也是最容易在审计时暴露的一环。Excel 上写"撤销",线上权限还在,审计师抽一个主体一查就知道。
原则:撤销动作必须走 IaC,不走控制台。 理由不是洁癖,是可追溯性。控制台手删有三个问题:没有 PR 记录、没有评审人关联、下次 terraform apply 会把权限"复活"。
第三个问题最致命,也最常发生。典型现场:工程师在控制台删掉了某个角色的 s3:* 绑定,两周后别人跑了一次 terraform apply,Terraform 的 state 里这条绑定还在,于是它被重新创建——权限回来了,而且没人注意到,因为"我们上季度评审过"。正确的顺序是:
- 改 Terraform 代码(删除
aws_iam_role_policy_attachment资源或缩小 policy 文档); - 提 PR,PR 描述里带
campaign_id与决策记录链接; - 审批合并,CI 执行
terraform plan; - plan 输出必须只包含预期的删除/修改,出现意外新增就阻断;
- apply 之后跑权限探针验证。
权限探针的做法很朴素但有效:用一个只带该主体权限的临时凭据,对"应当被拒绝"的动作发一次请求,断言返回 AccessDenied。AWS 上可以用 iam simulate-principal-policy 做离线模拟,不必真的发请求:
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::111122223333:role/AppDeploy \
--action-names s3:PutObject s3:DeleteObject \
--resource-arns arn:aws:s3:::prod-assets/report.csv \
--output table
阿里云对应 ram SimulatePolicy,返回每个动作的 Allowed / Denied 判定,适合在回收后批量复核。注意模拟接口只判断策略语义,不考虑 SCP、权限边界之外的运行时条件(如源 IP、VPC 端点、MFA 条件),所以它是必要但不充分的验证——最终仍要有一条真实调用失败的证据。
回收的三种形态要区分清楚,因为它们的风险和可逆性不同:
| 形态 | 操作 | 风险 | 可逆性 |
|---|---|---|---|
| 删绑定 | 解绑策略 / 移出用户组 | 低,影响面明确 | 高,重新绑定即可 |
| 缩策略 | 修改 policy 文档,去掉通配、限定资源 ARN | 中,可能影响未识别的调用方 | 中,需要回滚版本 |
| 换主体 | 从管理员角色换成只读角色 | 高,涉及信任链变更 | 低,回滚复杂 |
对第三类(换主体)建议单独走变更评审,不要塞进季度活动的批量执行里。批量执行里混入高风险变更,一旦出事会导致整个 IGA 流程被叫停——这是很多项目半途而废的真实原因。
最后是 break-glass。评审活动必须为紧急访问留出通道,否则会出现"为了合规把应急权限删了,真出事时只能改策略提权"的荒唐局面。可行设计:保留 2 个密封的特权账号,凭据分片存放、双人才能解封,任何一次使用都触发实时告警并自动生成一张"事后评审"工单,要求在 5 个工作日内补决策记录。这条通道本身也要进评审范围——评审的是"用了没有、理由是否成立",而不是"要不要保留"。
十、三类方案对比:自建脚本 / 云原生 / 商业 IGA
做 IGA 有三条路,选错的代价通常不是钱,而是"上线一年还在做权限清单"。三条路的差别不在功能清单,而在谁来维护那 200 条动作映射和 30 条 SoD 规则。
| 维度 | 云原生 + 自建脚本 | 商业 IGA 平台 | 开源自建(OPA + 目录服务) |
|---|---|---|---|
| 典型组成 | Access Analyzer + 凭据报告 + Python/Go 采集器 + 工单系统 | SailPoint、Okta Identity Governance、Microsoft Entra ID Governance | Keycloak/OpenLDAP 做目录 + OPA 做规则 + 自研评审前端 |
| 多云覆盖 | 取决于你写多少采集器,三家云都能覆盖 | 强,通常内置上百个 SaaS/云连接器 | 弱,几乎全部要自己写 |
| 使用证据 | AWS 侧最强(主体级未使用分析),另两家靠日志反查 | 依赖各系统 API,深度不一 | 全靠自建 |
| SoD 规则 | 自己写,语义层完全可控 | 内置规则库 + 图形化编辑 | 自己写,但 OPA/Rego 表达力强 |
| 审计报告 | 自己拼,格式自由 | 开箱有认证报告、签核流、审计导出 | 自己拼 |
| 成本量级(400 人) | 工具费约 0.1 万美元/年 + 人力 | 按用户每月计费,量级个位数到十几美元/用户/月,400 人年费约 3 万美元级 | 许可为零,人力成本最高 |
| 上线周期 | 4–8 周(含脚本与工单对接) | 3–6 个月(含实施商) | 3 个月以上,且要长期养 |
| 适用规模 | 50–800 人,云上主体为主 | 500 人以上,SaaS 应用多、审计压力大 | 有平台工程能力、且要求完全自主可控 |
三点经验判断:
- 人数不是唯一变量,"主体数 / 人数"才是。 一个 200 人的公司如果有 400 个服务账号和 12 个云账号,主体数远超人数,自建脚本的复杂度会接近商业产品;反过来 1000 人的公司如果只有 2 个云账号、权限都挂在 8 个组上,自建完全够用。
- 商业 IGA 的真正价值在"覆盖 SaaS",不在云。Salesforce、Workday、GitHub、Jira 这些系统的权限模型千差万别,自建连接器是无底洞。如果企业的审计范围只覆盖云基础设施,商业产品的溢价很难被证明。
- 开源方案的隐性成本在评审前端。规则引擎好写,"给 200 个经理发任务、收决策、催办、出报告"这一套工作流的工程量和运维量,往往超过规则本身。
十一、成本测算:400 人规模一次季度评审
下面这组数字可以直接拿去改参数复算。假设:400 名员工、60 个 IAM 角色(含服务角色)、3 家云共 12 个账号、每季度一次全量活动、每条决策平均耗时 4.0 分钟、人力综合成本按 60 美元/小时。
先看工具费。Access Analyzer 的未使用权限分析按"被分析的 IAM 角色与用户数 × 每月 × 每个分析器"计费,单价 0.20 美元:
| 项目 | 计算式 | 月 | 年 |
|---|---|---|---|
| 未使用权限分析(400 用户 + 60 角色) | 460 × $0.20 | $92.00 | $1,104.00 |
| 单主体年成本 | $0.20 × 12 | — | $2.40 |
| 官方算例对齐(70 主体) | 70 × $0.20 | $14.00 | $168.00 |
| 官方算例对齐(850 主体) | 850 × $0.20 | $170.00 | $2,040.00 |
再看人力。这是成本的主体,也是自动化真正能省下来的部分:
| 环节 | 人工基线(小时/季度) | 自动化后(小时/季度) | 差异来源 |
|---|---|---|---|
| 权限清单准备与导出 | 24.0 | 2.0 | 定时采集 + 归一化脚本替代手工 Excel |
| 评审判断(460 主体) | 30.7 | 30.7 | 判断本身不可自动化,只减少无效条目 |
| SoD 冲突裁决与例外 | 8.0 | 8.0 | 规则引擎把"发现"自动化,裁决仍需人 |
| 举证归档 | 12.0 | 1.0 | 证据包自动生成,替代人工截图拼装 |
| 回收执行 | 10.0 | 2.0 | PR 批量变更替代控制台逐个操作 |
| 合计 | 84.7 | 43.7 | 工时下降 48.4% |
换算成年化:
| 口径 | 工时/年 | 人力成本/年 | 工具费/年 | 合计/年 |
|---|---|---|---|---|
| 人工基线 | 338.8 | $20,328 | $0 | $20,328 |
| 自动化 | 174.8 | $10,488 | $1,104 + 脚本维护 $1,200 | $12,792 |
| 差额 | −164.0 | −$9,840 | +$2,304 | −$7,536(−37.1%) |
三年口径要把一次性的建设投入算进去(采集器 + 归一化 + 规则库 + 工单对接,按 80 小时计,约 4,800 美元):
| 口径 | 3 年总成本 | 相对基线的节省 |
|---|---|---|
| 人工基线 | $60,984 | — |
| 自动化(含一次性建设) | $43,176 | −$17,808(−29.2%) |
币种与口径说明:Access Analyzer 单价 0.20 美元/主体/月来自 AWS 官方定价页算例(70 主体 $14/月、850 主体 $170/月,2026-10 核验),按 us-east-1 美元计价、不含税;人力成本按 60 美元/小时的综合费率假设,实际应按当地薪资与福利调整;不含商业 IGA 许可费、不含审计服务费;"工时"为管理估算值而非实测,用于相对比较,不应作为预算承诺。
这组数字的意义不在于"省了 37%",而在于看清结构:评审判断(30.7 小时)是唯一无法自动化的大头,占自动化后总工时的 70%。 所以任何"提升评审效率"的投入,都应该指向减少需要判断的条目数(用使用证据过滤、按组评审、批量决策),而不是优化导出脚本——后者只占 2 小时。
十二、审计举证包:给审计师的那一页纸
证据包的组织方式决定了审计时长。把 460 条决策的原始记录丢给审计师,他会随机抽样 25 条逐条追问;给一页汇总 + 可下钻的明细,他通常看 3 条就够。
一页纸应该包含这七项:
| 项 | 内容 | 为什么审计师要看 |
|---|---|---|
| 范围声明 | 覆盖的云、账号、主体类型与数量、排除项及理由 | 判断样本是否代表总体 |
| 周期与评审人 | 活动起止、各类型主体的评审人角色 | 判断评审人是否有权限判断 |
| 决策统计 | 批准 / 降级 / 撤销 / 例外 的条数与占比 | 判断评审是否有效(全批准=无效) |
| 回收闭环 | 已批准撤销数、已执行数、执行率、平均执行时长 | 判断决策是否落地 |
| 例外台账 | 例外条数、到期日分布、过期未处理数 | 判断例外是否被滥用 |
| 使用证据口径 | 证据来源、时间窗、unknown 占比 | 判断结论的证据强度 |
| 签核 | 安全负责人 + 业务负责人的签署与时间 | 责任归属 |
控制项映射(按主流框架):
| 控制项 | 证据材料 | 常见追问 |
|---|---|---|
| SOC 2 CC6.1 | 权限清单快照(含采集脚本与运行日志) | 快照怎么保证完整?→ 出示组展开逻辑与总数核对 |
| SOC 2 CC6.2 | 新授予的审批记录(工单号 + 审批人) | 紧急授予怎么补审批?→ 出示 break-glass 事后评审工单 |
| SOC 2 CC6.3 | 撤销决策 + 执行回执 + 探针验证结果 | 撤销后如何确认生效?→ 出示 simulate-principal-policy 输出 |
| ISO 27001 A.5.18 | 周期性复核报告 | 复核周期依据什么定?→ 出示按主体类型分层的策略文档 |
| ISO 27001 A.8.2 | 特权账号清单 + 双签记录 | 特权账号有多少、谁批的?→ 出示特权清单与 90 天活动记录 |
| ISO 27001 A.8.16(监控) | 审计日志保留策略与查询样例 | 使用证据能回溯多久?→ 出示日志保留配置(如 365 天) |
三个能显著缩短审计时间的细节:
- 给每个数字一条可复现的命令。 报告里写"共 460 个主体",旁边放一行采集命令和它输出的行数。审计师自己跑一次能复现,后面就不会再追问。
- 把
unknown单独列出来。 使用证据缺失的记录占比 8% 是正常的,藏起来被发现才是问题。写明"这 37 条因腾讯云审计日志保留期限制无法取证,已人工确认并标注例外"。 - 保留失败记录。 第一次跑 SoD 一定会有一批误报(通配符展开导致的假冲突)。保留误报清单和修正记录,反而证明规则库被真实校验过。
十三、常见失败模式与处置
下面六种在真实项目里都见过,按出现频率排序:
| 症状 | 根因 | 处置 |
|---|---|---|
| 评审参与率高、撤销率为 0 | 评审人只有"保留/撤销"两个选项,且看不到使用证据 | 增加降级选项;在界面上显示最后使用时间与风险标签 |
| 权限清单覆盖率 98%,审计抽样却抽到漏项 | 只拉直接绑定,未展开用户组与角色链继承 | 采集器强制做组展开,并用"用户数 × 平均组数"核对总数 |
| 撤销后权限两周后复活 | 只改控制台未改 IaC,后续 apply 重建绑定 | 撤销必须走 PR;PR 里带 campaign_id;CI 阻断意外新增 |
| 服务账号永远"暂缓撤销" | 无 Owner、无业务方认领,评审人不敢拍 | 采集时强制打 Owner 标签,无标签直接判为治理缺陷(高优先级) |
| Access Analyzer 一直不出 finding | 跟踪期短于评审周期,或分析器刚建数据不足 | 跟踪期设为 1–365 天内不小于评审周期;提前两周建分析器 |
| 同一人被本人评审 | 评审人分配用了"主体 Owner = 主体本身"的默认逻辑 | 加一条硬规则:评审人 ≠ 主体;抽检 100% 覆盖此类 |
最后一条值得展开。自评审(self-review)在审计上等于没有评审,但它常常是无意造成的:很多 IGA 工具默认"资源 Owner 评审该资源上的权限",而平台团队自己既是 Owner 又是被评审主体。修法不是靠人盯,而是在分配逻辑里加断言,跑完后输出一张"自评审清单",非空就不允许活动进入签核阶段。
总结
多云访问评审的工程难点不在工具选型,而在三个具体动作:把三家云的继承关系拉全、把使用证据挂到每条权限上、把撤销变成 IaC 变更。这三件事做完,剩下的都是流程编排。
本文的几个关键数字可以带回去用:Access Analyzer 未使用权限分析 0.20 美元/主体/月(460 个主体 = 92 美元/月,年 1,104 美元),跟踪期 1–365 天且必须不小于评审周期,finding 不随区域变化因此不必按区域建分析器;腾讯云 ListAccessKeys 不返回最后使用时间、审计日志保留期常为 90 天,这两条决定了 180 天评审的证据只有一半;400 人规模下自动化把工时从 338.8 小时/年降到 174.8 小时/年,总成本降 37.1%,而剩下 70% 的工时集中在"人做判断"这一环,这提示优化的方向是减少需要判断的条目,而不是写更快的导出脚本。
如果只做一件事:先给所有主体打上 Owner 标签,再去做评审。 没有 Owner 的权限,在任何评审会上都只能"暂缓",而"暂缓"就是永久。
企业出海需要云架构咨询?通过 7.chengzicloud.cloud 联系我们,获取专属方案。
相关阅读
- 多云统一身份认证实战:阿里云 RAM SSO + AWS IAM Identity Center 联合登录
- 非人类身份(NHI)治理:工作负载身份联邦与机器凭据生命周期
- 多云特权访问管理(PAM):堡垒机、会话审计与临时提权
- 多云合规审计自动化:SOC 2、ISO 27001 与 GDPR 的证据流水线
- 阿里云 RAM 身份与权限安全实践
- 多云数字取证与事件响应(DFIR):证据固定顺序与证据链
- 软件资产许可合规与 ITAM 治理
本文由 7.chengzicloud.cloud 提供,点击访问首页了解更多
常见问题(FAQ)
Q1:访问评审和 IAM 权限审计有什么区别,能不能只做一个?
两者回答的问题不同。权限审计看"配置是否符合基线"(有没有通配、有没有开 MFA、有没有过期密钥),是技术检查,可以全自动;访问评审看"业务上是否仍然需要",必须由人做判断。只做审计会漏掉"权限合规但业务已不需要"的情况——这正是权限蔓延的主体;只做评审会漏掉"配置本身就越权"的情况。审计师通常两项都要看,SOC 2 里分别对应 CC6.1 和 CC6.3。
Q2:小团队(50 人以内)也需要做 IGA 吗?
需要,但形态可以极简。50 人规模用一张归一化表 + 每季度一次的经理确认就够了,工具成本可以是零:AWS 侧用凭据报告加 simulate-principal-policy,另两家用清单接口导 CSV,评审用共享表格加签核留痕。关键不是工具,而是"有周期、有证据、有回收"这三件事存在。等主体数超过 200 或云账号超过 5 个,再考虑脚本化。
Q3:Access Analyzer 的跟踪期设多长合适?
不小于你的评审周期,且不小于 90 天。原因是它只分析"在跟踪期内始终存在"的实体:跟踪期设 30 天,则刚创建 20 天的权限根本不会进入分析范围,而这批新权限恰恰是权限蔓延最快的部分。常见配置是 90 天(配季度评审)或 180 天(配半年评审),取值范围 1–365 天。
Q4:腾讯云没有最后使用时间,怎么证明权限没人用?
三条路并用:一是把 CloudAudit 事件投递到 COS 并保留 365 天以上,用 LookupEvents 按主体反查;二是用 CAM 的授权边界与策略文档做静态收缩(把 * 收敛到具体资源),降低"未知"的风险面;三是对无法取证的记录不判"未使用",而是标 unknown 并进人工确认队列。不要用"控制台看起来没动过"作为证据,审计不认。
Q5:SoD 规则要写多少条才够?
起步 6–10 条,覆盖"自审自批、自授权、可销毁审计痕迹、可删除备份、可批量外带数据"这五类高危组合即可,不必追求覆盖全部动作。规则的价值在准确率不在数量:一条误报率 30% 的规则会在两个周期内被业务方要求关掉。建议先把通配符展开做对,再加规则。
Q6:撤销权限导致线上故障怎么办?
用"三步降级"替代"一步撤销":先把管理员角色换成只读角色观察 7 天,再把只读范围收敛到实际使用的资源,最后才删除绑定。同时保留 24 小时快速回滚路径(IaC 的 revert PR + 预授权的 break-glass 通道)。实践上,因为评审撤销导致的生产故障远少于因为权限过大导致的故障,但流程上仍要给出回滚路径,否则评审人不敢做决定。
Q7:服务账号(非人类身份)怎么评审?
按"Owner + 用途 + 最后使用"三要素评审,而不是按人。要求每个服务账号必须有标签化的 Owner(团队而非个人)、有文档化的用途、有最后使用时间;三者缺一即判为治理缺陷。另外把密钥轮转周期纳入同一张表:超过 180 天未轮转的 CI 密钥,无论是否在用都应强制轮转。跨云的 workload identity 联邦能显著减少这类静态密钥的数量。
Q8:评审活动的证据要保留多久?
至少保留到下一次外部审计结束,通常意味着 3 年。低成本做法是把每次活动的证据包(快照 JSON + 决策记录 + 执行回执 + 一页纸报告)打包成一个不可变对象存进对象存储,开启版本控制与对象锁,单个活动包通常在几十 MB 量级,三年成本可以忽略。不要只存在工单系统里——工单系统换供应商时,历史证据会一起消失。