RAM/IAM 与临时凭据:把 SSO、OIDC、角色和 STS 变成可验证的最小权限链
部署脚本突然开始返回 AccessDenied,值班同学在 CI 变量里找到一对由离职开发者创建的长期 AK/SK。没人能立即回答这对密钥属于哪个身份、在哪些仓库被复制、是否还能创建资源、撤销后哪些流水线会停。此时“换一对新密钥”只会把未知风险续期:人的身份、程序的身份、可进入哪个角色、角色能做什么、一次会话还能被怎样收窄,仍然混在同一个秘密里。
更可靠的链路是让人通过企业身份源登录,让仓库、集群或云内工作负载提交 OIDC 等可验证断言,由云端 STS 换发短期凭据;权限不写进 token,而由目标角色、资源策略、组织边界、会话策略和请求条件共同决定。短期凭据泄漏仍然危险,但它有明确签发者、受众、主体、权限上限、过期点和审计会话,团队才有机会准确阻断而不是全局换钥。
先把泄漏现场拆成六个独立对象
初学者最容易把“登录”和“授权”当成一件事。实际上,一次云 API 请求至少经过六类对象:principal 表示谁发起请求;IdP 负责证明这个身份;role 是被临时扮演的云端身份;trust policy 决定谁有资格进入角色;permission policy 决定角色允许哪些动作;STS session 则是一次有期限的角色实例。Condition 不是附注,它读取请求上下文中的 audience、subject、来源账号、标签、MFA、区域、时间或网络条件,决定某条语句是否生效。
以一次 CI 上传开发制品为例,身份不是“某个 access key”,而是 <oidc-issuer> 签发、aud=<sts-audience>、sub=repo:<org>/<repo>:environment:<env> 的断言。目标角色 <artifact-read-role> 先验证 issuer、audience 和 subject;STS 随后签发 access key、secret key 与 session token 三件套;对象存储收到请求后,再按请求上下文求值角色权限、会话策略、桶策略、组织策略和显式拒绝。AWS 的策略求值逻辑明确规定显式 Deny 优先;权限边界、会话策略、SCP/RCP 会在各自适用的情形限制允许结果,而同账号资源策略直接授予 role session 与跨账号访问还有不同规则,不能压缩成一条固定的“所有策略取交集”。阿里云 RAM 的角色扮演求值说明同样要求调用方拥有 sts:AssumeRole,并且目标角色信任策略接受调用方。
这也解释了三个常见误判。信任策略允许某主体,只代表它可以尝试进入角色,不代表它能读取任意资源;给角色附加管理员策略,也不能越过组织级显式拒绝;传入会话策略只能缩小角色已有权限,不能凭空放大。排障时必须先判断失败发生在“换取会话”还是“使用会话”,否则会在错误的策略层反复加权限。
人员走 SSO,工作负载走 OIDC,角色不保存自己的密钥
开发者日常进入多个账号时,首选企业 IdP 加 SSO:入职、离职、组成员、MFA 和登录风险在身份源集中治理,云账号只接收用户被分配的 permission set 或角色。AWS CLI v2 的 IAM Identity Center 配置会缓存 SSO token,并按 profile 对应的账号与角色取得临时凭据;不要从门户复制三段临时密钥再粘到共享脚本里。阿里云角色 SSO、Azure Entra 联合身份和 Google Cloud Workforce Identity Federation采用的产品对象不同,判断标准相同:人员身份的生命周期应留在身份源,云端只接受受控映射。
无人值守任务不能借用人的 SSO 缓存。Git 托管流水线、Kubernetes ServiceAccount 或外部部署平台应使用 OIDC/SAML/云原生工作负载身份,把运行时已有断言交换为短期访问令牌。Google Cloud 官方把 Workload Identity Federation定位为外部工作负载避免服务账号密钥的方式;Microsoft Entra 的联合身份凭据也会逐项匹配 issuer、subject 与 audience。OIDC 的价值不是“免密”三个字,而是把信任绑定到可验证的运行上下文。
已经运行在云内的虚机、容器、函数优先使用实例角色、托管身份或服务账号,不再绕到外部 OIDC,也不把元数据服务返回的凭据写入磁盘。只有不支持联合身份、托管身份和标准凭据链的遗留工具才考虑长期密钥;这类例外要绑定独立机器身份、最小动作、来源限制、轮换周期、使用清单和退出负责人,不能发给个人后长期存在。
安装 CLI 后先隔离配置,再允许浏览器登录
CLI 是验证身份链最直接的入口,但它也会同时读取参数、环境变量、共享配置、凭据文件、进程凭据和实例身份。先从厂商维护的分发入口安装;AWS 明确建议只使用官方 AWS CLI v2 分发点,安装后用 aws --version 记录团队基线,不要把文档页面展示的某个构建号当成永久版本。升级时在测试 profile 跑同一组身份与拒绝实验,再更新团队镜像。
下面用临时目录隔离 AWS 配置。空目录下的身份查询应失败为“无法定位凭据”,而不是返回某个意外账号;若仍返回身份,说明环境变量、credential process、容器元数据或实例角色仍在参与解析。get-caller-identity 返回账号和角色身份,适合放在每个变更脚本的第一行,该调用本身不依赖额外授权。
$sandbox = Join-Path $env:TEMP 'cloud-auth-<run-id>'
New-Item -ItemType Directory -Force -Path $sandbox | Out-Null
$env:AWS_CONFIG_FILE = Join-Path $sandbox 'config'
$env:AWS_SHARED_CREDENTIALS_FILE = Join-Path $sandbox 'credentials'
$env:AWS_EC2_METADATA_DISABLED = 'true'
aws --version
aws sts get-caller-identity --no-cli-pager
# 预期:Unable to locate credentials 或等价无凭据错误,而不是账号信息。管理员已经分配 SSO 入口、账号、角色和承载 Identity Center 的区域后,开发者再运行 aws configure sso --profile <dev-read-profile> 与 aws sso login --profile <dev-read-profile>。浏览器确认的是 <sso-start-url> 对应的企业身份;随后必须再次查询身份,不能把“Successfully logged in”当作目标账号正确的证据。
aws configure sso --profile <dev-read-profile>
aws sso login --profile <dev-read-profile>
aws sts get-caller-identity \
--profile <dev-read-profile> \
--query '{account:Account,principal:Arn}' \
--output json
# 预期特征:account 等于 <expected-account-id>,principal 包含预期角色名。
# 失败特征:UnauthorizedException、Token has expired,或返回了其他账号。SSO region 是身份目录所在区域,业务命令的 region 是资源所在区域,两者不能互相推断。profile 中显式写业务默认区域,脚本仍在关键命令上传 --region <target-region>。配置文件可保存 start URL、账号 ID 与角色名,但 SSO 缓存、session token、浏览器 cookie、MFA code 和调试日志都是敏感数据,不进入仓库、制品或工单附件。
信任策略只回答谁能进入,还要钉住受众与主体
OIDC 提供者建立后,角色信任不能只写“信任这个 issuer”。攻击者若能从同一 IdP 获得面向其他应用或其他仓库的合法 token,宽泛信任就会把它当成自己的部署身份。AWS 的 OIDC 提供者说明要求 audience 与 token 中的 aud 匹配,并允许把 OIDC claims 用作条件键;issuer、JWKS、TLS 链、aud 与 sub 任一不匹配,STS 都应拒绝交换。
并非每个 OIDC claim 都会进入后续角色会话。AWS 的 OIDC 条件键表区分“只在换取会话时可用”和“可带入会话”的键;在 trust policy 中成功匹配某个自定义 claim,不代表业务资源策略还能读取它。若授权必须依赖环境、租户或项目属性,应先确认该属性能否成为会话上下文,或者把它映射为受控 session tag / source identity,并限制谁有权传入。否则信任层看起来很精确,资源层却只能退回宽泛角色权限。
下面的信任策略使用明显占位符。真实环境应让 <oidc-provider-host>、<audience> 和 <subject-pattern> 来自 IdP 的稳定契约;能写精确 subject 就不要写全组织通配符。生产和开发使用不同角色与 subject,拉取请求、普通分支和受保护环境也不应共享可变更资源的角色。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<account-id>:oidc-provider/<oidc-provider-host>"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"<oidc-provider-host>:aud": "<audience>",
"<oidc-provider-host>:sub": "repo:<org>/<repo>:environment:<env>"
}
}
}
]
}人员跨账号 AssumeRole 则把受信账号或具体角色放入 Principal,同时让调用方策略显式允许目标 RoleArn。高风险人工角色在 trust policy 检查 aws:MultiFactorAuthPresent=true;AWS 的 MFA 保护 API 指南说明 AssumeRole 和 GetSessionToken 的差异:MFA 应在角色进入时强制,不能假定所有联合身份令牌都携带云端可识别的 MFA 上下文。外部 IdP 的 MFA 强度要在身份源条件访问中治理,再把认证方法、设备状态或组映射成云端可审计属性。
第三方 SaaS 跨账号接入还要使用由资源拥有方分配的 external ID,防止混淆代理问题;external ID 不是密码,不能替代精确 principal 和最小权限。角色 session name 与 source identity 应携带稳定、非敏感且可追踪的 <workload>-<run-id>,因为它会进入目标账号审计日志;不要把邮箱、工单正文或 token 片段塞进会话名。
session name 由每次调用指定,source identity 则适合保存跨角色链不应被改写的原始主体。AssumeRoleWithWebIdentity 只有在 IdP 把值放进 https://aws.amazon.com/source_identity claim 时才会建立 source identity;建立后它会出现在该会话及后续角色链的请求上下文中。AWS 的临时角色监控说明给出了该 claim 的传递方式。团队应让值来自 IdP 的稳定标识或 workload/run 标识,并用 trust policy 约束格式;不能让流水线把任意用户名或生产标签自报成 source identity。
权限、条件和会话策略共同形成实际能力
角色权限应从业务动作倒推,而不是从托管的管理员策略向下删。假设任务只需列出 <dev-bucket> 并读取 <prefix> 下的制品,桶级 ListBucket 与对象级 GetObject 使用不同资源 ARN;删除、改 ACL、改策略、列其他前缀都没有 Allow。条件再把区域、资源标签、principal 标签或加密上下文收紧。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListOnlyExpectedPrefix",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::<dev-bucket>",
"Condition": {
"StringLike": { "s3:prefix": ["<prefix>", "<prefix>/*"] }
}
},
{
"Sid": "ReadOnlyExpectedObjects",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<dev-bucket>/<prefix>/*"
}
]
}一次发布只需要读取某一个构建前缀时,再给 STS 传 session policy,把角色上限缩到 <prefix>/<build-id>/*。AWS AssumeRole 的命令参考明确说明,session policy 与角色身份策略取交集,且不能增加角色原本没有的动作。阿里云 STS 的 Policy 参数也采用角色权限与会话策略交集,具体调用方式见扮演 RAM 角色。
不要把条件当作“多写一点更安全”。StringEquals 与 StringLike、缺失键、大小写、服务是否把某个键放入请求上下文都会改变结论。ABAC 使用 session tag 时,要限制谁能传哪些 tag、哪些 tag 可跨角色链传递;否则调用者可以自称 environment=prod。资源策略直接授权 session principal 还可能与权限边界产生容易误判的效果,重要资源应围绕角色 ARN、组织 ID 和显式拒绝建模,并用真实请求验证。
正向实验必须证明身份、允许动作和资源范围
正向实验不是“拿到了三段凭据”。它应依次证明调用者身份正确、允许动作成功、返回资源属于目标范围、会话将在预期时限内过期。人工角色可用 MFA 进入;命令输出重定向到进程内受控变量,不要 Write-Host 或上传 JSON,因为 STS 响应包含 secret 和 session token。
$session = aws sts assume-role `
--profile <source-profile> `
--role-arn 'arn:aws:iam::<account-id>:role/<dev-artifact-read-role>' `
--role-session-name '<operator>-<run-id>' `
--serial-number 'arn:aws:iam::<account-id>:mfa/<mfa-device>' `
--token-code '<mfa-code>' `
--duration-seconds <approved-duration-seconds> `
--output json | ConvertFrom-Json
$env:AWS_ACCESS_KEY_ID = $session.Credentials.AccessKeyId
$env:AWS_SECRET_ACCESS_KEY = $session.Credentials.SecretAccessKey
$env:AWS_SESSION_TOKEN = $session.Credentials.SessionToken
aws sts get-caller-identity --output json
aws s3api list-objects-v2 `
--bucket '<dev-bucket>' `
--prefix '<prefix>/' `
--max-items 5 `
--region '<target-region>'预期 Arn 形如 assumed-role/<dev-artifact-read-role>/<operator>-<run-id>,列表只出现目标前缀。空列表不等于拒绝;它说明授权调用成功但当前没有对象。AccessDenied 才进入授权排查,InvalidClientTokenId、ExpiredToken、SignatureDoesNotMatch 则优先检查三段临时凭据是否配套、时钟、endpoint 和签名区域。
会话时长要短到足以限制泄漏窗口,也要长到覆盖一次正常任务和合理重试。过短会诱导脚本在中途复制新 token,过长会放大缓存和日志泄漏。不要把最大允许时长当默认值;按交互式开发、只读诊断、自动构建、高风险变更分级。并发任务使用不同 session name/source identity,审计才能把同一角色的请求归回具体运行。
反向实验要让错误稳定发生并保留拒绝证据
最小权限只有在明确不允许的动作确实失败时才被证明。先用同一会话查询错误前缀,验证资源边界;不要为了“看报错”向真实服务发出 DeleteObject 之类的写操作。对删除权限,先审查角色、会话、资源和组织策略中不存在允许项及存在的显式拒绝;IAM policy simulator 只能辅助验证身份策略,不能替代资源策略、SCP/RCP 和服务请求上下文。需要真实反例时,由管理员在隔离账号、明确批准的无数据金丝雀上执行,并保存 request ID;通用教程不提供可直接删除对象的命令。
# 使用上一步已导入环境变量的同一临时会话;不要在这里切换 profile。
# 正例:目标前缀只读查询应成功。
aws s3api list-objects-v2 `
--bucket '<dev-bucket>' `
--prefix '<prefix>/' `
--max-items 1 `
--region '<target-region>'
# 反例:其他前缀应返回 AccessDenied,而不是空列表或真实对象。
aws s3api list-objects-v2 `
--bucket '<dev-bucket>' `
--prefix '<forbidden-prefix>/' `
--max-items 1 `
--region '<target-region>'OIDC 还要固定三组反例:把 aud 换成 <wrong-audience>,把 sub 换成 <other-repo-subject>,从未受保护的环境请求同一角色。三者都应在 STS 阶段拒绝,根本拿不到会话。如果错误 subject 仍成功,不是“流水线配置灵活”,而是信任策略越界。MFA 角色则省略 --serial-number/--token-code 再请求一次,预期 AssumeRole 直接拒绝。
拒绝记录至少保存云端错误码、request ID、目标动作、脱敏资源、调用角色 session、账号和区域。不要开启 --debug 后原样上传,因为签名头、endpoint、token 来源和本机路径可能进入日志。AWS 可使用 CloudTrail 对照 AssumeRole 与后续数据/管理事件;如果存在编码授权消息,由有权限的管理员解码,开发者不通过扩大权限“试到成功”。
项目接入只依赖标准凭据链,不接收明文 token
项目代码不应该知道 access key 从 SSO、OIDC、实例角色还是 STS broker 获得。使用厂商 SDK 默认凭据链或命名 profile,把身份交换留给运行环境。开发机设置 AWS_PROFILE=<dev-read-profile>;CI 通过 OIDC action 或 credential process 获取会话;云内运行时挂角色。应用只配置区域、目标资源和超时,不配置 secret。
[profile <dev-read-profile>]
sso_session = <team-sso-session>
sso_account_id = <account-id>
sso_role_name = <dev-read-role>
region = <target-region>
output = json
[sso-session <team-sso-session>]
sso_start_url = https://<sso-portal-host>/start
sso_region = <identity-center-region>
sso_registration_scopes = sso:account:access仓库只保存这个不含真实账号与域名的 .example,个人实际配置位于受操作系统权限保护的用户目录。容器不要挂载整个 home;只挂需要的配置或使用进程级联合身份文件,且设为只读。SDK 初始化不显式传 credentials,避免异常对象、APM span 或序列化配置把 secret 带入日志。
项目启动时执行一次低成本身份自检并输出脱敏摘要:provider 类型、角色名、账号别名映射、区域和 token 剩余时长,不输出 account 原值也可通过内部映射显示 <dev-account>。高风险命令再要求 EXPECTED_ACCOUNT_ALIAS、EXPECTED_ROLE 与 EXPECTED_REGION 全部匹配。身份查询失败时快速退出,不能悄悄回退到开发者机器上的 default profile。
排障沿签发、交换、授权和资源四段逐层收敛
浏览器 SSO 成功而 CLI 报 token 过期,先检查 profile 是否使用可刷新 sso-session 配置、缓存目录权限、系统时钟和 IdP 会话;aws sso logout 后重登,不能删除整个用户目录来碰运气。CLI 返回了错误账号,则检查命令参数、AWS_PROFILE、AWS_CONFIG_FILE、环境变量和 credential process 优先级。AWS 允许用 AWS_CONFIG_FILE 与 AWS_SHARED_CREDENTIALS_FILE 改变配置位置,配置文件说明也提醒凭据文件含敏感信息。
AssumeRoleWithWebIdentity 失败时,按 issuer、TLS/JWKS、签名、token 有效期、audience、subject、provider ARN、trust action 顺序检查。不要把 JWT 粘进在线解码站;可在受控本机只解码 header/payload,验证后立即删除。签名正确但 audience 错误,修 IdP 的受众;subject 不符,修流水线环境或精确条件;不要把 StringEquals 改成全局通配符临时解围。
STS 成功而业务 API AccessDenied,说明信任链已经通过,继续检查 role policy、session policy、permissions boundary、SCP/RCP、资源策略、KMS key policy 和条件上下文。先确认 Action 与 Resource 形态,例如桶与对象 ARN 不同;再确认 region、resource tag、principal tag 和加密参数。策略模拟器可辅助单账号身份策略,但不能代替跨账号资源策略、组织控制与服务真实上下文。
请求成功却访问了错误数据,权限系统可能完全“正常”。这属于范围配置故障:账号、区域、资源名或前缀错误。身份摘要、目标资源清单、业务断言和数据分类必须同时验证。权限只回答能不能做,不替项目判断做的是不是正确对象。
退出与吊销要区分本机缓存、单用户和整角色影响
任务结束先清除进程环境变量,再注销 SSO 登录并删除隔离目录。aws sso logout 会清除本机缓存并使对应的 IAM Identity Center 登录会话失效,但不等于撤销其他机器、其他登录会话或已经换出的 IAM 角色临时凭据。清理命令只作用于刚创建的 <cloud-auth-run-id> 目录,绝不能递归删除默认 ~/.aws。
Remove-Item Env:AWS_ACCESS_KEY_ID -ErrorAction SilentlyContinue
Remove-Item Env:AWS_SECRET_ACCESS_KEY -ErrorAction SilentlyContinue
Remove-Item Env:AWS_SESSION_TOKEN -ErrorAction SilentlyContinue
Remove-Item Env:AWS_PROFILE -ErrorAction SilentlyContinue
aws sso logout
$tempRoot = [System.IO.Path]::GetFullPath($env:TEMP).TrimEnd('\\') + '\\'
$sandboxFull = [System.IO.Path]::GetFullPath($sandbox)
if (-not $sandboxFull.StartsWith($tempRoot, [System.StringComparison]::OrdinalIgnoreCase) -or
[System.IO.Path]::GetFileName($sandboxFull) -notlike 'cloud-auth-*') {
throw "Refuse to remove unexpected path: $sandboxFull"
}
Remove-Item -LiteralPath $sandboxFull -Recurse -Force发现 token 泄漏时先判断来源。长期 AK/SK 要立即禁用并轮换,搜索仓库历史、CI 变量、镜像层、日志与下载制品;OIDC 泄漏还要检查 token 是否仍可重放、受众和时效,必要时收窄或停用受影响角色的信任条件、停用相关工作流,并按 IdP 事件流程处理签名材料。修改 trust policy 只会阻止新的 AssumeRoleWithWebIdentity,已经换出的 STS 凭据仍需等待过期或通过角色会话阻断;盲目轮换 IdP 签名 key 还可能让所有正常工作负载同时失去换票能力。SSO 账号异常则在身份源禁用用户、撤销登录会话并检查组分配。
STS 临时凭据通常一直有效到过期,不能想当然地寻找“删除这一串 token”的按钮。AWS 的角色会话吊销通过给角色附加按 token 签发时间拒绝旧会话的 AWSRevokeOlderSessions 内联策略实现阻断;它针对该角色在阻断点之前签发的会话,因此会影响正常任务,且不是删除某一串凭据。执行前列出受影响任务、准备新会话验证;执行后旧会话应稳定拒绝,阻断点之后取得的新会话才应恢复。
由 IAM Identity Center permission set 创建的角色不能在 IAM 中直接套用上述操作。AWS 的活动 permission set 会话撤销流程要求先以用户 ID 建立拒绝保护,再移除直接和组内 permission set 分配、阻止身份源继续登录、删除 Active sessions,并让拒绝保护覆盖既有 IAM 角色会话的剩余寿命。仅禁用用户、仅删除访问门户会话或仅移除分配,都可能留下“不能重新登录但旧角色凭据仍可调用”的窗口。自动化应记录阻断开始时间、用户 ID、受影响账号、旧会话最后拒绝时间和拒绝策略移除时间;不能为了快速恢复而提前撤掉保护。
删除角色不是首选止血动作,因为资源策略、实例 profile、流水线配置和自动化可能仍引用它。先显式拒绝或收窄信任,确认审计不再出现旧 session,再解除关联、删除内联/托管策略和角色。退出证据包括:旧凭据拒绝、新身份通过、引用清单归零、缓存清理、审计事件和异常访问调查结论。
架构选择取决于身份来源与失败半径
人员多账号访问采用集中 SSO,优点是生命周期、MFA 和组映射统一;代价是身份源或同步故障会影响广泛登录,需要受控的紧急访问身份、双人审批和定期演练。外部 CI 采用 OIDC 联合,减少静态 secret;代价是 issuer、JWKS、aud/sub 契约成为关键依赖,仓库重命名、环境保护或 claim 变化必须先做信任迁移。
云内工作负载采用实例角色、托管身份或 Pod 身份,凭据自动轮换且不落盘;代价是元数据端点、节点隔离、service account 绑定和侧向移动成为新的攻击面。跨云统一 STS broker 可以集中审计和策略,但也会成为高价值、需高可用的安全边界;小团队若没有维护能力,优先使用各云托管联合身份而非自建 token 服务。
角色按业务能力和风险分,不按每个人复制。只读诊断、制品读取、开发资源变更、权限管理、账单查看应是不同角色;生产与开发分账号或项目后再分角色。角色太粗,单次泄漏半径大;角色太碎,permission set、信任关系、审计和培训成本急剧上升。选型指标应包括身份数量、账号数、会话签发峰值、策略变更频率、紧急访问恢复时间、审计查询时延和跨云迁移成本。
凭据、敏感数据、容量和费用一起治理
session token、OIDC ID token、SSO refresh token、MFA code、浏览器 cookie、签名 URL、CLI cache 和 debug 日志都属于凭据材料。JWT payload 即使未加密也可能含邮箱、仓库、组、环境和内部主机名,不能因“只是 claim”就公开。CloudTrail、RAM 操作审计、Entra 登录日志和 CI artifact 也可能含 principal、IP、资源 ARN 与失败上下文,应按安全日志控制访问、驻留、加密和保留。
短会话会增加 STS 与 IdP 交换频率,数千并发 job 若同时刷新可能触发配额、IdP 限流或冷启动放大。客户端应在进程内缓存到安全阈值前再刷新,失败使用有上限的指数退避,不把 token 放进共享 Redis。监控签发成功率、拒绝原因、刷新时延、每角色并发 session、异常 region、未知 subject、长期密钥数量和未使用角色,而不是只统计登录次数。
IAM、STS、SSO、审计、第三方 IdP 和 SIEM 的收费与配额模型并不相同,且会随区域、租户和产品版本变化。启用前从目标云账号的官方价格页确认:身份席位或目录费用、审计事件和数据事件、日志存储与查询、跨区域导出、SIEM 摄入、支持计划及超额调用。临时凭据减少的是密钥运营风险,不自动消除身份平台和审计成本。
长期治理靠可重复的正反金丝雀
每个角色有 owner、调用主体、允许动作、资源模式、条件、最长会话、MFA/IdP 要求、审计入口、紧急吊销与退出记录。策略变更走代码评审;扩大 Action、Resource 通配符、放宽 subject、允许传 session tag、延长会话和新增跨账号 principal 都需要安全审查。离职、仓库归档、项目迁移和账号关闭会自动触发角色引用复核。
持续金丝雀至少包含一条允许路径和三条拒绝路径:正确 subject 读取目标前缀应成功;错误 subject 不能换取会话;同一会话不能读取其他前缀;删除动作必须拒绝。IdP、CLI、SDK、action、claim 模板或策略引擎升级时先跑金丝雀,再扩大到开发账号。若反例意外成功,升级立即停止;若正例失败,保留旧版本和旧 trust policy 以便回滚,不通过添加管理员权限恢复流水线。
季度审查关注未使用角色、长期密钥、过长 session、宽泛 trust、没有 owner 的 IdP、未消费的审计日志和吊销演练结果。真正成熟的临时身份体系不是“所有 token 都会过期”,而是团队能对任一请求回答:谁用什么证据进入了哪个角色,哪几层策略给出最终结果,凭据在哪里缓存,泄漏时怎样限制影响,旧会话何时被可靠拒绝。
