ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AWS IAM权限管理实战:最小权限策略、角色与SCP配置指南

AWS IAM权限管理实战:最小权限策略、角色与SCP配置指南 我做了这么多年的 AWS 架构和运维说实话最让我头疼的往往不是建了几个复杂的分布式系统而是 IAM 权限配置。权限放得太松审计出问题轻则收账单收到肉疼重则出安全事故权限卡得太死开发同事一天八次来找你工单系统里全是“Access Denied”的截图。AWS IAM 这东西说简单也简单无非是用户、组、角色、策略几件事说复杂也复杂稍微不留神一个条件键写错一个资源 ARN 没配对排查起来能让你怀疑人生。这篇文章我打算换个写法不照抄文档而是按我实际工作中最常碰到的几个核心场景来拆把理念、策略写法、配置步骤、排障思路全串起来。无论是刚入门的云运维还是被权限问题折磨了一段时间的开发者看完应该都能直接照着落地少踩几个坑。1. IAM 到底是什么先读懂权限模型再动手配置1.1 四大核心组件一句话理解我在带新人的时候喜欢打一个比方。IAM 里的 User用户就是公司员工Group用户组就是部门Role角色就是临时访客工牌Policy策略就是写在工牌上的门禁权限。你在公司里能进哪几间办公室不是看你这人有多厉害而是看你身上挂的这张卡写了哪些权限。落到 AWS 里具体的关系是这样的User用户给真实的人或应用程序用的长期身份标识可以分配密码控制台登录或者访问密钥Access Key/Secret Access Key。Group用户组把用户聚合在一起统一分配权限。比如“dev-group”、“ops-group”这样省得一个用户一个用户地贴策略。Role角色不是给某个具体的人而是给一个“身份”使用的。这个身份可以被用户、AWS 服务比如 EC2、Lambda、其他 AWS 账户Assume。角色本身没有长期密钥而是通过 STS 颁发临时凭证。Policy策略定义“谁可以对什么资源做什么操作”。策略分托管策略AWS 托管、客户托管和内联策略。生产环境我基本不用内联策略理由后面会说。很多人容易把 Role 和 User 搞混尤其是不常写 IAM 的人。我的经验是能用 Role 的场合不要用 User。User 带了长期密钥长期密钥就意味着泄露风险Role 用临时凭证过期自动失效安全性和灵活性都好得多。1.2 策略生效的底层逻辑IAM 策略的评估逻辑可以用三条规则概括默认全部拒绝、显式允许才放行、显式拒绝一票否决。这里有个关键点实际判断权限时系统会把所有适用于这个请求的权限策略收集起来做一次联合判断只要有一条显式 Deny不管 Allow 有多少条结果都是拒绝。我在实战中见过不少同事在这上面栽过跟头。比如一个人先写了一条 Deny 策略禁止删除某个 S3 桶后面又追加了一条 Allow 策略允许对s3:*操作。直觉上觉得“后写的更具体应该覆盖前面的吧”结果照样删不掉。原因很简单Deny 的优先级就是比 Allow 高这不是“覆盖”的关系是一票否决的关系。这个逻辑想清楚之后很多奇怪的权限问题都能解释得通了。比如策略里明明有某个权限调用还是报 Access Denied那就要去检查是不是还有别的策略在悄悄 Deny。常见的有这几个权限边界Permissions Boundary、SCPService Control Policy、Bucket Policy、角色的信任策略一层一层叠下来哪个环节卡了请求都过不去。1.3 先明确业务场景再拆权限我在帮客户设计权限之前都会先问一句这个权限是给谁用的用在什么场景下。不同的场景方案选择差别很大。人员管理开发、运维、财务各归各组走用户组策略这套模型。工作负载EC2 要访问 S3Lambda 要读 DynamoDB这些不需要真人登录直接给对应的 AWS 服务绑定角色就行。跨账户协同多个账户共用一套身份或者第三方供应商需要访问你账户里的资源。用跨账户角色 ExternalId不要用对方的长期 AK。资源级权限对 S3 桶、KMS 密钥这类资源除了 IAM 侧还要注意资源侧的策略比如 Bucket Policy也在做校验两边都要配好。梳理清楚场景后面写策略、排问题才会有方向。我没有见过哪家公司在 IAM 上混乱是单纯因为“不会写 JSON”基本都是因为没有想清楚“谁在什么场景下需要什么权限”。2. 最小权限策略设计从最简需求写出可落地的 JSON2.1 先学会看懂 ARN这是策略的地基写 IAM 策略第一步不是写 Action而是写对 ARN。ARNAmazon Resource Name是 AWS 资源的唯一标识策略里 Resource 字段填的就是它。举个例子arn:aws:s3:::my-bucket这是桶本身的 ARN。如果想代表桶里的所有对象要在后面加一层/*arn:aws:s3:::my-bucket/*这两者的差别极其容易踩坑。只写arn:aws:s3:::my-bucket你给用户开s3:GetObject他访问s3://my-bucket/xxx照样报错因为 GetObject 对应的资源是对象不是桶。反过来你只写arn:aws:s3:::my-bucket/*用户能读写桶里的对象但s3:ListBucket列桶对象列表会失败因为这条 Action 作用在桶本身上。我见过的真实项目里至少有 50% 的 S3 权限问题出在 ARN 的层级写错了。所以我的建议是开 S3 权限时Resource 同时写上桶 ARN 和对象 ARN。2.2 从一个实战需求拆解策略写法假设现在有个数据分析岗位的同事工作内容是读取 S3 里某个项目桶例如s3://data-lake-raw-prod的数据在 Athena 上跑查询把结果写到另外一个结果桶s3://data-lake-result-prod。如果按“最简单省事”的做法直接给这个同事挂AmazonS3FullAccess他确实能干活但他也能把你整个账号下的所有 S3 桶删光。审计的时候这种权限是头皮发麻的。正确的写法是拆成几条限制{ Version: 2012-10-17, Statement: [ { Effect: Allow, Action: [ s3:ListBucket ], Resource: [ arn:aws:s3:::data-lake-raw-prod, arn:aws:s3:::data-lake-result-prod ] }, { Effect: Allow, Action: [ s3:GetObject ], Resource: [ arn:aws:s3:::data-lake-raw-prod/* ] }, { Effect: Allow, Action: [ s3:PutObject ], Resource: [ arn:aws:s3:::data-lake-result-prod/* ] } ] }这里面对应了权限设计里一个很重要的理念不同操作的角色不一样。Get 和 Put 是数据读写List 是浏览桶这三类职责分开写后续审计时候一目了然想撤销哪块就撤销哪块。2.3 用 Condition 限制“谁能访问”把权限再收紧一层很多人在写 IAM 策略时忽略了 Condition 这个字段而我把它当成第二道保险。举个例子很多公司会要求必须开了 MFA 才能访问生产资源。写法如下{ Version: 2012-10-17, Statement: [ { Effect: Allow, Action: [ ec2:StopInstances, ec2:StartInstances ], Resource: *, Condition: { Bool: { aws:MultiFactorAuthPresent: true } } } ] }注意aws:MultiFactorAuthPresent这个键的坑如果你用会话凭证比如 AssumeRole 之后这个键可能不存在那判断结果就是 false从而拒绝访问。所以实际生产里我往往还会加一个 “IfExists” 后缀比如这样Condition: { BoolIfExists: { aws:MultiFactorAuthPresent: true } }意思就是如果这个键存在就必须是 true如果不存在也算通过。这样既保证了交互式用户的 MFA 校验又不至于误伤服务间的非交互式调用。另外从安全角度强烈建议只要是涉及生产环境的写操作Delete、Put、Stop、Start、Terminate能加 Condition 就加 Condition不要嫌麻烦。有一次我排查一个问题某部门员工离职后 AK 没有及时轮转但因为策略里挂了 MFA 条件攻击者就算拿到了密钥也越不过 MFA 这一关。这种防护机制平时不起眼关键时刻能救命。2.4 权限边界给子账户加一道“天花板”权限边界Permissions Boundary是我非常推荐启用的功能尤其是管理多个子账户或者给外包团队开权限的时候。权限边界的作用是给某个 IAM 用户或角色设定一个最大权限范围。即使后来有人给这个用户附加了再大的策略也不能超过权限边界划定的范围。举个例子你给一个外包开发团队创建了一个角色outsource-role并设置了权限边界arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess那就算你在某个项目里意外给这个角色附加了AdministratorAccess他的实际权限仍然只有 S3 只读。这就是个天花板能拦住很多“手滑”。我踩过的最痛的一次坑是某次自动化脚本给一批角色批量附加策略时误把AmazonS3FullAccess附加到了只有一个只读需求的角色上。幸亏当时已经给这个角色预先设置了权限边界否则整个 S3 的数据都可能被误删。从此之后所有跨团队使用的角色我都会要求先设权限边界再谈权限。3. 核心场景实操演练生产环境最常用的三种配置3.1 场景一给开发者账号配置最小权限假设有个新来的后端工程师他需要查看 EC2 实例状态和 CloudWatch 日志查看 S3 里某个业务桶的数据对某个开发环境的 ECS 服务进行重启。我首先创建一个用户组developer-group然后把对应的策略挂到组上。这样以后再来新人直接加入组就有权限告别反复改策略。这个场景下我习惯用客户托管策略Customer Managed Policy而不是 AWS 托管策略。AWS 托管策略虽然省事但往往范围太大不符合最小权限原则。例如AmazonECS_FullAccess这类策略基本把所有 ECS 操作的权限都给了。自己写一个客户托管策略反而更可控。这里给出一个参考策略{ Version: 2012-10-17, Statement: [ { Effect: Allow, Action: [ ec2:Describe*, cloudwatch:GetMetricData, cloudwatch:ListMetrics ], Resource: * }, { Effect: Allow, Action: [ s3:ListBucket, s3:GetObject ], Resource: [ arn:aws:s3:::business-bucket-dev, arn:aws:s3:::business-bucket-dev/* ] }, { Effect: Allow, Action: [ ecs:UpdateService, ecs:DescribeServices ], Resource: arn:aws:ecs:ap-southeast-1:123456789012:service/my-cluster/my-service } ] }这套策略妙在 Resource 精确到了 ECS 的具体服务而不是整个集群。以后这个开发者就算想捣乱也只会影响这一个服务影响面被控制住了。在控制台操作时记得在 IAM 控制台的“用户组”页面下选择对应组然后在“权限策略”里贴上这个 JSON。实测下来策略生效通常几秒钟但偶尔也有缓存如果急着验证等个十几秒钟就好。3.2 场景二给 EC2 实例绑定 IAM 角色这个场景我要重点强调不要再用 Access Key 放进代码里了真的求大家别这么干了。很多老项目里EC2 实例上跑的应用会读环境变量里的 AK/SK或者直接写在配置文件里。这些密钥一旦泄露等于把你云账号的后门交给了别人。正确做法是给 EC2 绑定一个 IAM Role让实例临时申请 STS 凭证。配置步骤如下在 IAM 控制台创建角色类型选择AWS Service使用场景选EC2。附加权限策略比如这个实例需要访问 S3 的某个桶就挂一个和之前类似的 S3 只读策略。在角色信任关系Trust Relationship里确保 Principal 是ec2.amazonaws.com这样 EC2 服务才有权限代入这个角色。信任策略示例{ Version: 2012-10-17, Statement: [ { Effect: Allow, Principal: { Service: ec2.amazonaws.com }, Action: sts:AssumeRole } ] }在 EC2 控制台的实例操作里选择“安全” - “修改 IAM 角色”把刚才的 Role 绑到实例上。绑定完成后在实例里通过元数据服务获取临时凭证curl http://169.254.169.254/latest/meta-data/iam/security-credentials/会返回角色名再执行curl http://169.254.169.254/latest/meta-data/iam/security-credentials/你的角色名返回的 JSON 里包含AccessKeyId、SecretAccessKey、Token这三个值。SDK 会自动去这个地址拉取临时凭证应用层完全不用关心密钥管理。权限下发给运行在 EC2 上的应用这个模型能极大降低 AK 泄露风险。临时凭证有效期通常最长 6 小时会自动轮转出了事故也不用慌“啊我们密钥丢了”。3.3 场景三跨账户角色切换Switch Role多账户架构下最常见的需求是总部账号主账号要访问子公司账号成员账号的某个资源比如查看日志、操作数据库。跨账户访问别直接用对方的 AK而是用跨账户角色。在成员账号中创建角色信任策略里Principal 选择另一个 AWS 账号的 ID{ Version: 2012-10-17, Statement: [ { Effect: Allow, Principal: { AWS: arn:aws:iam::主账号ID:root }, Action: sts:AssumeRole, Condition: { StringEquals: { sts:ExternalId: a-very-random-id-9527 } } } ] }这里面的sts:ExternalId是关键。它相当于两个公司之间约定的暗号只有知道这个暗号的一方才能代入角色能够有效防止混淆代理人攻击Confused Deputy Problem。尤其是和第三方合作时必须加 ExternalId而且不要让这个 ID 用常规的员工编号或公司名用随机字符串。在主账号这边用户要切换过去需要拥有sts:AssumeRole的权限。在用户策略里加上{ Version: 2012-10-17, Statement: [ { Effect: Allow, Action: sts:AssumeRole, Resource: arn:aws:iam::成员账号ID:role/cross-account-ops-role } ] }之后用户在 AWS 控制台右上角选择“切换角色”填上账号 ID、角色名、显示名称就能直接以对方的角色身份进行操作。这个方式既不用分享长期密钥每次操作都有完整的 CloudTrail 日志审计的时候非常清楚是谁从哪个账号执行了什么操作。4. 从单账户 IAM 走向组织级治理SCP 与权限边界配合4.1 SCP 是什么和 IAM 策略有什么关系到了多账号阶段你会碰到的第一个管理层工具就是 AWS Organizations。组织里有根Root、组织单元OU、账号。SCPService Control Policy是在这层控制权限的比 IAM 策略层级更高。理解 SCP 最好的方式就是继续用门禁卡类比SCP 是大楼物业的规定比如“不管谁进来周末禁止进入 5 楼机房”IAM 策略是你公司内部给员工的授权“员工 A 可以进 5 楼员工 B 不能进”。SCP 限制的是整个账号的最大可用权限就算 IAM 策略写的再宽只要 SCP 说不行就是不行。在设计上SCP 的评估逻辑和 IAM 策略不完全一样。对于同一个账号SCP 和 IAM 策略要做“交叠”运算先看 SCP 允许了哪些权限再看 IAM 允许了哪些两者都允许的情况下操作才会真正被放行。也就是说SCP 像一个大框IAM 策略只能在这个框里发挥作用。4.2 三层权限模型SCP、权限边界、IAM 策略我通常会把权限体系分成三个层级来设计这样可以避免“头痛医头、脚痛医脚”第一层SCP 控制账号级上限。比如禁止在开发环境账号里开启某些高风险服务禁止删除 CloudTrail 等。它是账号的大边界。第二层权限边界控制角色/用户级上限。限制某个团队的角色最高能拿到什么权限。第三层IAM 权限策略控制具体动作。这是日常每个人真正生效的权限。举个例子。公司规定任何成员账号都不允许删除 KMS 密钥。那可以在 SCP 里写{ Version: 2012-10-17, Statement: [ { Effect: Deny, Action: [ kms:ScheduleKeyDeletion ], Resource: * } ] }然后给某个团队的角色设置权限边界为arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess。最后团队成员本身的 IAM 策略再按需附加。这样从账号、角色、个人三层都做了限制即使被攻破一个点也打不穿整层防线。实际配置中有一种“Deny 列表策略”很常用就是把高危操作全都列进去放进 SCP 的根级别对所有账号生效。比如删除日志、修改 CloudTrail、停用 GuardDuty 等。这种方式能有效防止一些“上帝之手”误操作。4.3 组织级实施样例主账号统一控制台登录如果公司账号很多每个账号都有各自独立的 IAM 用户那管理起来是灾难。推荐的做法是用 IAM Identity Center原 SSO做集中身份认证配合 Permission Set 来分配权限。简单说主身份目录放所有人每个账号根据 OU 逻辑自动发放对应的 Permission Set用户登录后选择账号和权限集通过角色代入方式访问。这个方案的底层还是跨账户角色和 STS但对使用者来说体验和单点登录一样且权限集中管控。实施之后那个“谁在哪个账号有什么权限”的表格终于可以从 Excel 里删掉了。5. 审计与监控权限配置完不等于完事5.1 开启 CloudTrail 追踪 IAM 事件很多用户把 IAM 配完就跑了等到出了问题再去查日志。实际上IAM 服务的所有管理事件默认都会被 CloudTrail 记录只要你在 CloudTrail 里创建一条追踪并将事件存到 S3 或者 CloudWatch Logs就能随时回溯谁在什么时间调用了什么 API。经验之谈不要只创建默认的“事件历史”Event History一定要创建一条“跟踪”Trail。默认的事件历史只保留 90 天而且没法配置告警自定义 Trail 可以存到 S3 保存很多年配合 Athena 查询历史记录来做审计。我之前处理过一次违规删除事件就是靠 CloudTrail 日志定位到具体用户进一步挖掘发现他的 AK 在 GitHub 上被泄露了。如果没有完整日志这种问题基本别想查清楚。5.2 用 IAM Access Analyzer 找出隐藏的“外联权限”IAM Access Analyzer 是我这几年越来越依赖的工具。它不需要额外装什么在控制台开启后它会扫描你账户里的资源策略自动识别那些“允许外部实体访问”的配置。打个比方你有一扇门你以为加了密码锁就安全了但 Access Analyzer 走过去一推发现门旁边的窗户没关。它能发现诸如S3 桶策略里Principal: *配了GetObject且没有限定条件KMS 密钥策略允许某个外部账号使用IAM 角色信任策略允许任意 AWS 账户代入。这些策略单看可能没什么感觉但一旦被外部扫描到就是安全风险。我建议每个月跑一次 Access Analyzer把发现的外部访问提醒清理一遍形成固定巡检项。5.3 密钥轮换和根用户禁用访问密钥Access Key是长期凭证必须定期轮换。AWS 官方建议 90 天一轮。我在企业里推动过一套流程在 IAM 用户的“上次使用时间”列开启后定期拉取 90 天以上未使用的 AK 列表直接禁用并通知用户。现实中不少问题不是权限配错而是遗留的长期密钥完全是僵尸账户在“裸奔”。另外一个红线AWS 根用户Root User要开启 MFA并且平时尽量不用根用户操作。根用户的权限是全量的一旦泄露后果非常严重。我的习惯是创建完账号后根用户只用于创建第一个 IAM 管理员用户给根用户绑上硬件 MFA 或 App MFA然后锁进密码管理器里平时所有操作都走 IAM 用户或角色。这条看起来简单但我见过不少初创团队图省事长期用根用户操作直到某天账单飙升才发现问题。真的不建议这么干。6. 常见问题与排查技巧实录6.1 Access Denied 排查思路速查表先说一个最常见的现象策略 JSON 看起来没问题权限也配了但还是拒绝访问。按照这条链路排查基本能解决 80% 的问题检查项操作SCP 是否限制了去 Organizations 控制台检查该账号所属 OU 的 SCP权限边界是否限制检查用户/角色是否设置了 Permissions Boundary是否有多条策略叠加检查同一实体上是否附着 Deny 策略资源策略是否允许检查 S3 Bucket Policy、KMS Key Policy 等资源侧策略角色信任策略是否允许检查角色能否被当前身份 AssumeCondition 是否满足检查 MFA、SourceIp、ExternalId 等条件键我遇到过最离谱的一个案例用户执行s3:PutObject一直 Access Denied排查了一圈最后发现问题出在 KMS 密钥策略。S3 默认不加密时可以传输但一旦桶开启了 SSE-KMS 加密S3 的 PutObject 还会触发 KMS 的kms:GenerateDataKey。结果用户只有 S3 权限没有 KMS 权限所以被拒绝。这个问题不看底层逻辑光查 IAM 权限可能要查到天亮。类似的坑还有EC2 使用 AWS Backup 备份时备份服务要扮演 Backup Role 才能读取实例角色没配好就会报权限不足ECS 任务要拉镜像需要 ECR 的 GetAuthorizationToken 和 Pull 权限Lambda 执行角色要能写 CloudWatch Logs否则函数一跑就报日志组权限错误。这些跨服务权限调用关系都是实践中积累出来的“暗坑”。6.2 一个跨账户角色切换失败的定位实录前阵子有个项目同事从主账号切换角色到成员账号时一直报错提示“Not authorized to perform sts:AssumeRole”。我拿到这个报错第一反应就是信任策略是不是没写对。于是打开成员账号的角色配置一看发现 Principal 写的是对方的 Account ID 数字AWS 要求填写的是 ARN 形式的账号例如arn:aws:iam::123456789012:root。改完之后切换立刻成功。除了这种硬格式错误还有两种高频问题主账号用户没有sts:AssumeRole的权限。这个好理解跨账号角色需要“目标侧信任源侧授权”双方配合缺一不可。目标角色信任策略里设了aws:PrincipalArn条件指定了某个具体的用户 ARN但用户实际是 AssumeRole 后拿到的会话身份这时候 PrincipalArn 可能是会话角色 ARN导致条件不匹配。6.3 注意ASG 缩容到 0 之后还在扣费的问题有段时间我在处理账单异常测试环境把 Auto Scaling Group 的 Desired 调成 0但成本还在上涨。排查后发现ASG 缩容到 0 只是把 EC2 实例数降下来了但旁边那台 NAT 实例还是按量付费负载均衡器、EIP、EBS 快照这些都不在 ASG 的管辖范围内。这套问题虽然涉及的不是 IAM 权限配置但排查思路是一样的先把所有资源类型过一遍确定哪些服务还在计费再定位访问控制策略是否有漏洞。对资源和权限都要有整体的治理观。6.4 用 IAM Policy Simulator 快速验证策略当你修改策略后不想直接在生产环境验证可以到 IAM 控制台左侧找到Policy Simulator策略模拟器它会模拟一个用户/角色在指定资源上执行某个操作的最终结果。我在修改敏感权限之前一定会先把这个动作放模拟器里跑一遍。比如要给某个角色增加删除 RDS 的权限先在模拟器里选rds:DeleteDBInstance、填上目标库的 ARN看返回的 Decision 是 Allow 还是 Deny。特别是多个策略叠加时这个工具可以直观地告诉你最终生效结果比在环境里验证要安全得多、快得多。写在最后的一点体会AWS IAM 发展到今天其实已经是一个非常成熟的权限体系了。但越是功能强大越需要使用者有克制力。权限给得太满等于没设防权限给得太乱等于给自己挖坑。我自己的项目习惯是从立项第一天就建立好权限基线把“最小权限”从口号变成默认动作。哪怕团队成员只有三个人也要把 IAM 当生产系统来设计。各种工具本身并不复杂复杂的是“怎么持续地保持安全”。我的做法是每个季度做一次 IAM 巡检拉一遍用户和角色的权限清单、检查长期 AK 使用时间、用 Access Analyzer 扫一遍外部访问、把 SCP 和权限边界再过一遍。每次巡检都能发现一些之前遗留下来的小问题但这些小问题如果不处理日积月累就是大坑。另外分享一个平时自己用的小技巧凡是写完了 IAM 策略我都会在 JSON 里加上注释性质的命名前缀比如>
返回列表