多云访问权限评审(IGA)实战:认证活动设计、职责分离 SoD 与审计举证闭环(2026)

📅 · 企业出海多云架构实战 - ChengziCloud

一句话结论

访问权限评审(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 2CC6.1 / CC6.2 / CC6.3逻辑访问的授予、变更、撤销有审批记录;撤销在离职/转岗后及时发生
ISO/IEC 27001:2022A.5.15 访问控制、A.5.18 访问权限按既定周期复核访问权限,复核结果有留痕
ISO/IEC 27001:2022A.8.2 特权访问权限特权账号受限、受监控、定期复核
等保 2.0(三级)访问控制、身份鉴别账户权限最小化、定期检查、离岗账号及时处置

注意 A.5.18 的措辞是"at regular intervals"——它不要求你实时完美,它要求你有节奏、有记录、有回收。反过来说,一个每季度真跑、证据完整的评审活动,比一个号称"实时最小权限"但拿不出记录的系统更容易过审。

三种最常见的"假最小权限"现场:

  1. 角色只增不减。为一次故障开的 prod-emergency-admin 角色,故障结束后没人删,半年后成了值班人员的日常入口。这类角色通常还带 iam:* 或 sts:AssumeRole 的宽授权。
  2. 权限靠复制。新人入职时"照着小王的权限配一份",小王的权限本身是三年前堆出来的。复制不会引入新的越权,但会把历史债务按人数放大。
  3. 服务账号无主。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-rolesram ListUsers / ListRolescam ListUsers / ListRoles
直接绑定策略list-attached-user-policies / list-role-policiesListPoliciesForUserListAttachedUserPolicies
组继承list-groups-for-user + list-attached-group-policiesListGroupsForUser + ListPoliciesForGroupListGroupsForUser + ListAttachedGroupPolicies
权限边界 / 条件get-role 的 PermissionsBoundary + 策略 Condition策略 Version 里的 Condition策略文档 condition
服务级最后访问generate-service-last-accessed-details无官方等价接口,需 ActionTrail 反查无官方等价接口,需 CloudAudit 反查
密钥最后使用凭据报告 access_key_N_last_used_dateGetAccessKeyLastUsedListAccessKeys 不含该字段,需事件反查
主体级未使用分析Access Analyzer unused access(可组织级)无无
组织级汇总Organizations + 组织级分析器资源目录(Resource Directory)成员账号 + 主账号视角

三条实操结论:

  1. "直接绑定"永远不等于"实际权限"。 三家的 List*PoliciesForUser 类接口都只返回直接绑定到该主体的策略,不包含经用户组继承的部分。只拉直接绑定,覆盖率会系统性偏低,而且漏掉的恰好是最常见的授权方式(把策略挂到组、人放组里)。必须补一次组展开。
  2. 需要"角色链"展开。 如果企业用"人 → 组 → 角色 → 信任链"的模式(AWS 的 sts:AssumeRole、阿里云的 RAM 角色扮演),清单里要记录可传递性:谁能扮演谁。这条边不进表,后面的 SoD 检测就查不出"通过扮演角色绕过职责分离"的路径。
  3. 别只取第一页。 三家接口都分页,默认页大小通常 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:PutObjectoss:PutObjectcos:PutObject
对象公开读s3:PutObjectAcloss:PutObjectAclcos:PutObjectACL
数据库写入rds-data:ExecuteStatementrds:ExecuteStatementcdb:* 写类动作
密钥解密kms:Decryptkms:Decryptkms:Decrypt
密钥策略变更kms:PutKeyPolicykms:PutKeyPolicykms:PutKeyPolicy
日志删除logs:DeleteLogGrouplog:DeleteLogStorecls: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 里这条绑定还在,于是它被重新创建——权限回来了,而且没人注意到,因为"我们上季度评审过"。正确的顺序是:

  1. 改 Terraform 代码(删除 aws_iam_role_policy_attachment 资源或缩小 policy 文档);
  2. 提 PR,PR 描述里带 campaign_id 与决策记录链接;
  3. 审批合并,CI 执行 terraform plan;
  4. plan 输出必须只包含预期的删除/修改,出现意外新增就阻断;
  5. 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 GovernanceKeycloak/OpenLDAP 做目录 + OPA 做规则 + 自研评审前端
多云覆盖取决于你写多少采集器,三家云都能覆盖强,通常内置上百个 SaaS/云连接器弱,几乎全部要自己写
使用证据AWS 侧最强(主体级未使用分析),另两家靠日志反查依赖各系统 API,深度不一全靠自建
SoD 规则自己写,语义层完全可控内置规则库 + 图形化编辑自己写,但 OPA/Rego 表达力强
审计报告自己拼,格式自由开箱有认证报告、签核流、审计导出自己拼
成本量级(400 人)工具费约 0.1 万美元/年 + 人力按用户每月计费,量级个位数到十几美元/用户/月,400 人年费约 3 万美元级许可为零,人力成本最高
上线周期4–8 周(含脚本与工单对接)3–6 个月(含实施商)3 个月以上,且要长期养
适用规模50–800 人,云上主体为主500 人以上,SaaS 应用多、审计压力大有平台工程能力、且要求完全自主可控

三点经验判断:

  1. 人数不是唯一变量,"主体数 / 人数"才是。 一个 200 人的公司如果有 400 个服务账号和 12 个云账号,主体数远超人数,自建脚本的复杂度会接近商业产品;反过来 1000 人的公司如果只有 2 个云账号、权限都挂在 8 个组上,自建完全够用。
  2. 商业 IGA 的真正价值在"覆盖 SaaS",不在云。Salesforce、Workday、GitHub、Jira 这些系统的权限模型千差万别,自建连接器是无底洞。如果企业的审计范围只覆盖云基础设施,商业产品的溢价很难被证明。
  3. 开源方案的隐性成本在评审前端。规则引擎好写,"给 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.02.0定时采集 + 归一化脚本替代手工 Excel
评审判断(460 主体)30.730.7判断本身不可自动化,只减少无效条目
SoD 冲突裁决与例外8.08.0规则引擎把"发现"自动化,裁决仍需人
举证归档12.01.0证据包自动生成,替代人工截图拼装
回收执行10.02.0PR 批量变更替代控制台逐个操作
合计84.743.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 联系我们,获取专属方案。

相关阅读

本文由 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 量级,三年成本可以忽略。不要只存在工单系统里——工单系统换供应商时,历史证据会一起消失。