4. 服务控制策略SCP实战

服务控制策略(Service Control Policy,SCP)是 AWS Organizations 中用于集中限制成员账户可用权限边界的策略类型。它本身不授予任何权限,只负责“划定上限”:一个 IAM 身份或角色最终能否执行某个操作,取决于 SCP 允许的集合与 IAM 策略允许的集合之间的交集。理解这一点,是写好 SCP 的前提。

一、SCP 的语法结构

SCP 使用与 IAM 策略一致的 JSON 语法,核心字段包括 Version、Statement,以及语句中的 Sid、Effect、Action、Resource、Condition。与 IAM 策略不同的是,SCP 中的 Resource 通常写为 "*",因为 SCP 关注的是“能不能调用这个 API”,而不是“能操作哪个具体资源”。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyS3DeleteBucket",
      "Effect": "Deny",
      "Action": "s3:DeleteBucket",
      "Resource": "*"
    }
  ]
}

上面这段策略的含义是:禁止成员账户中任何身份删除 S3 存储桶。注意 Effect 只有 Allow 和 Deny 两种取值,Action 支持通配符如 s3:*、ec2:Describe*,Condition 可引用全局条件键,例如 aws:RequestedRegion、aws:PrincipalArn、aws:PrincipalTag 等。

二、允许与拒绝的判定逻辑

SCP 的判定遵循三条规则:

  • 默认拒绝:如果没有任何 SCP 显式允许某个操作,该操作在成员账户中就被拒绝。
  • 显式拒绝优先:只要任意一层 SCP 中出现 Deny,无论其他层是否 Allow,该操作都会被拒绝。
  • 必须逐层允许:从根到目标账户路径上的每一层 SCP,都必须对该操作存在 Allow,操作才可能被允许。

因此,SCP 的最终效果是“所有生效 SCP 的交集”。如果根上有一条 Allow *,某个 OU 上有一条 Allow s3:*,账户上又有一条 Allow ec2:*,那么该账户实际可用的服务范围是 s3 与 ec2 的交集,即两者都允许的部分;若账户上还有一条 Deny s3:DeleteBucket,则即使前面都允许,删除存储桶仍会被拒绝。

SCP 生效路径与判定逻辑 Root(根) Allow * OU:Workloads Allow s3:* Account:A-01 Allow ec2:* 最终可用权限 = 各层 SCP 交集 s3:* ∩ ec2:* = 两者都允许的操作 若任一层 Deny,则直接拒绝 账户级 Deny:s3:DeleteBucket 即使上层 Allow s3:*,删除仍被拒绝 结果:可读 S3、可管理 EC2 但不可删除 S3 存储桶

三、OU 级与账户级绑定

SCP 可以绑定到根、OU 或成员账户。绑定到 OU 时,该 OU 下所有账户(包括子 OU 中的账户)都会继承这条策略;绑定到账户时,只影响该账户。实际使用中,推荐“OU 级为主、账户级为辅”:把通用防护策略放在 OU 上,把个别账户的特殊限制放在账户级。

需要注意,SCP 不会影响管理账户(Management Account),也不会影响服务关联角色(Service-Linked Role)。此外,SCP 只对成员账户中的 IAM 用户和角色生效,对根用户同样生效,但根用户仍受其他限制约束。

四、常见防护策略编写

下面给出几条在生产环境中经常使用的 SCP 示例,可直接作为模板修改。

1. 禁止关闭 CloudTrail 与 GuardDuty

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ProtectSecurityServices",
      "Effect": "Deny",
      "Action": [
        "cloudtrail:StopLogging",
        "cloudtrail:DeleteTrail",
        "guardduty:DeleteDetector",
        "guardduty:DisassociateFromMasterAccount"
      ],
      "Resource": "*"
    }
  ]
}

2. 限制可使用的区域

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyNonApprovedRegions",
      "Effect": "Deny",
      "NotAction": [
        "iam:*",
        "organizations:*",
        "cloudfront:*",
        "route53:*"
      ],
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "aws:RequestedRegion": [
            "cn-north-1",
            "cn-northwest-1"
          ]
        }
      }
    }
  ]
}

这里使用 NotAction 排除全球性服务,避免误伤 IAM、Organizations 等必须跨区域调用的操作。

3. 禁止删除或修改关键资源

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyDestructiveActions",
      "Effect": "Deny",
      "Action": [
        "s3:DeleteBucket",
        "rds:DeleteDBInstance",
        "ec2:TerminateInstances",
        "kms:ScheduleKeyDeletion"
      ],
      "Resource": "*"
    }
  ]
}

4. 要求请求必须带特定标签

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "RequireProjectTag",
      "Effect": "Deny",
      "Action": "ec2:RunInstances",
      "Resource": "*",
      "Condition": {
        "StringNotEquals": {
          "aws:RequestTag/Project": "prod"
        }
      }
    }
  ]
}

五、编写与验证建议

SCP 一旦绑定,影响范围大,建议先在测试 OU 或测试账户上验证。验证时可以使用 IAM Policy Simulator 或直接在成员账户中尝试目标操作,观察是否被拒绝。若发现误伤,优先检查 Deny 语句是否覆盖了不该覆盖的 Action,以及 Condition 中的条件键是否写错。

SCP 只做“边界控制”,不替代 IAM 策略。正确的做法是:SCP 负责“不能做什么”,IAM 策略负责“能做什么”,两者配合才能既安全又可用。
不要在生产根上直接绑定过于严格的 SCP。建议先在根上保留 Allow *,再逐层在 OU 和账户上叠加限制,避免因一条策略导致整个组织无法操作。

总结来说,SCP 的核心是“交集 + 显式拒绝优先”。掌握语法、理解判定逻辑、合理选择绑定层级,再配合常见防护模板,就能在 AWS Organizations 中建立起清晰、可维护的权限边界。