在 AWS 安全治理中,”如何限制用户可以操作的区域”是最常见的问题之一。无论是为了合规审计、成本控制,还是为了减少攻击面,你都需要确保团队成员只能在指定的区域中创建资源。
这篇文章会详细对比两种实现方式——DisableRegion API 和 SCP 策略,告诉你它们的区别、各自的局限性,以及如何配合使用。
一、DisableRegion:关闭不需要的区域
背景
过去很长一段时间,AWS 没有一个统一的方式可以关闭区域。如果你不想让用户在某个区域干活,只能在 IAM Policy 或 SCP 里用 aws:RequestedRegion 条件拒绝。但从 2022 年底开始,AWS 在 Account Management API 中新增了 DisableRegion / EnableRegion,支持在账号级别关闭区域。
用法
1
2
3
4
5
6
7
8
# 查看当前账号的区域状态
aws account list-regions --region ap-northeast-1
# 关闭一个区域
aws account disable-region --region-name af-south-1
# 开启一个区域
aws account enable-region --region-name af-south-1
还可以通过 Organizations 的 Management 账号批量关闭成员账号的区域,无需逐个登录。
局限性
最重要的限制:只能关闭 opt-in 区域
AWS 把区域分为两类:
| 类型 | 特点 | 数量 | 能否 Disable |
|---|---|---|---|
| ENABLED_BY_DEFAULT | 所有账号默认开启,不可关闭 | 17 个(us-east-1、ap-northeast-1 等) | ❌ |
| Opt-in 区域 | 默认关闭,需要手动开启 | ap-east-1、af-south-1 等 | ✅ |
用 list-regions 可以查到:
1
2
3
4
5
6
// ENABLED_BY_DEFAULT — 关不掉
{ "RegionName": "ap-northeast-1", "RegionOptStatus": "ENABLED_BY_DEFAULT" }
{ "RegionName": "us-east-1", "RegionOptStatus": "ENABLED_BY_DEFAULT" }
// DISABLED — 已经关了
{ "RegionName": "af-south-1", "RegionOptStatus": "DISABLED" }
所以 DisableRegion 只能帮你关闭那些你还没有用过的 opt-in 区域(通常是后来 AWS 新增的区域),而 us-east-1、us-west-2 这些”老区”关不掉。
使用建议
如果你是一个新建的账号,opt-in 区域默认就是 DISABLED 状态,你甚至不需要做任何操作。但如果担心有人误操作开启,可以建立一个定期的合规扫描检查。
二、SCP aws:RequestedRegion:覆盖所有区域的终极方案
既然关不掉默认区域,那就需要另一个工具——SCP(Service Control Policy)。
核心思路
用 SCP 拒绝在所有非允许区域执行操作。IAM 条件键 aws:RequestedRegion 记录了 API 请求的目标区域,我们利用它来做 Deny。
1
2
3
4
5
6
7
8
9
10
{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["ap-northeast-1"]
}
}
}
这样,任何在 ap-northeast-1 之外的操作都会被拒绝。
全局服务的问题
但直接这样写会出问题——有些 AWS 服务是全局的,它们不绑定到特定区域。IAM 的用户管理、Route53 的 DNS 记录、CloudFront 的分发配置,这些操作的 API 调用不带有 aws:RequestedRegion。对于不带 region 的调用,StringNotEquals 条件会匹配,Deny 就会生效,导致这些全局服务也无法使用。
解决方案是用 NotAction 把这些全局服务排除在外:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyAllOutsideAllowedRegions",
"Effect": "Deny",
"NotAction": [
"account:*", // 账号管理(区域开关、联系人等)
"budgets:*", // 预算
"cloudfront:*", // CloudFront
"iam:*", // IAM(密码策略、用户、角色)
"organizations:*", // Organizations
"route53:*", // Route53 DNS
"sso:*", // IAM Identity Center
"sts:*", // STS(AssumeRole、GetCallerIdentity)
"support:*" // Support 工单
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["ap-northeast-1"]
}
}
}
]
}
绑定策略
绑定到哪些 OU 决定了影响范围。有两种常见模式:
方案 A:绑定到 Root
- 所有账号生效
- 如果想豁免某些账号(如 BreakGlass),需要在 SCP 中使用
aws:PrincipalAccount条件
方案 B:绑定到各 OU
- 用
for_each绑定到所有非 BreakGlass OU - BreakGlass 账号天然不受限制
推荐方案 B,逻辑更清晰——紧急情况下要用其他区域,直接从 BreakGlass OU 操作,不受任何 SCP 限制。
需要注意的点
1. Management 账号不受 SCP 影响
SCP 不控制 Management 账号,这是 AWS 的安全设计。所以管理员仍然可以在其他区域操作,这是正常的。
2. 服务相关角色(SLR)也会被限制
如果你开启了 Config 聚合器的 all_regions 功能,Config 服务会跨区域拉取资源信息。但这条 SCP 不会影响 AWS 服务自身,它只控制 IAM 主体的 API 调用。
3. Console 登录不受影响
AWS 控制台的登录认证走的是 signin.aws.amazon.com,不需要区域授权。用户仍然可以登录看到 Console,但点击”切换区域”后会看到无权限访问。
三、组合方案:DisableRegion + SCP = 纵深防御
| 手段 | 负责范围 | 无法覆盖的 |
|---|---|---|
| DisableRegion | 关闭不需要的 opt-in 区域 | 17 个默认开启的区域 |
SCP aws:RequestedRegion | 拒绝在非允许区域操作 | Management 账号、全局服务 |
两者结合:
- 先用
DisableRegion关掉所有你用不到的 opt-in 区域 - 再用 SCP 限制只能在
ap-northeast-1操作 - BreakGlass OU 不绑定 SCP,保留紧急通道
- 定期审计是否有人开启了新的 opt-in 区域
自动化审计
可以用 Config 规则 + account:ListRegions API 定期检查账号的区域状态,发现异常自动告警:
1
2
3
4
5
# 检查是否有非预期的区域被开启
aws account list-regions \
--region-opt-status-contains ENABLED \
--query "Regions[?RegionOptStatus=='ENABLED'].[RegionName]" \
--output text
四、总结
DisableRegion API 是一个好的补充工具,但它解决不了核心问题——你关不掉那些默认开启的区域。真正有效的方案还是 SCP。
如果你正在搭建 AWS 组织的安全基线,推荐的做法:
- 确认你的核心区域(该用哪个区)
- 检查你的账号已经开启了哪些区域(
list-regions) - 关掉所有不用的 opt-in 区域(
disable-region) - 在 SCP 中拒除非允许区域的操作(
aws:RequestedRegion+NotAction) - 对 BreakGlass OU 做豁免
这样一套下来,不管有多少默认区域开着,你的用户都只能在允许的区域中干活。