别再用主账号干活:IAM 子用户与最小权限入门
翻一下老项目,配置文件里是不是躺着一串主账号的 AK/SK?它等于整个云账号的钥匙——能删数据库、能开几十台机器烧钱、能把域名转走,而且没有任何权限边界。这篇文章讲清主账号、子用户、用户组的关系,并手把手建一个只能管对象存储的子用户,让凭证泄露时的损失可控。
翻一下你以前的项目,config.py 或 .env 里是不是躺着一串 AK/SK?
或者更糟——它已经跟着代码提交到 Git 了。就算后来删掉,提交历史里还在。
很多人的想法是「反正是自己的账号,方便最重要」。但主账号的 AK/SK 等于整个云账号的钥匙:它能删你的数据库、能开几十台机器让你一夜之间欠一笔钱、能把域名转到别人名下。更麻烦的是,主账号没有任何权限边界——一旦泄露,你没办法限制它能做什么,唯一的补救是把所有密钥和密码全部重置。
子用户就是用来解决这个问题的。
一、主账号、子用户、用户组
1.1 三者的关系
主账号(你注册的那个账号)
│ 拥有全部权限,不可被限制
│
├─ 用户组 A(比如「运维组」)
│ ├─ 子用户 1 ← 权限来自用户组
│ └─ 子用户 2
│
└─ 用户组 B(比如「开发组」)
└─ 子用户 3
主账号是你注册时用的那个身份,也叫「账号」。它对名下所有资源有完全控制权,而且这个权限无法被收窄——不能给主账号「只允许操作 OBS」这样的限制。这是设计使然:总得有一个身份能兜底。
子用户(IAM 用户)是你在主账号下创建的独立身份。它可以有密码登录控制台,也可以有 AK/SK 供程序调用。子用户能做什么,完全由你授予的策略决定。
用户组是批量授权的容器。把子用户加进用户组,组上的权限自动生效。一个人干多种活时可以进多个组,权限叠加。
1.2 为什么必须分开
三个很具体的理由:
第一,权限可以被收窄。 给程序用的凭证只需要管对象存储,那就只给 OBS 权限。就算这个 AK 泄露,攻击者也只能动你的存储桶,碰不到数据库和服务器。
第二,出事能追溯。 每个子用户的操作在日志里是分开记的。用主账号操作,所有动作都记在同一个身份下,分不清是谁干的。
第三,离职/换人时只需停用一个身份。 如果所有人共用主账号,有人离开就得改密码,所有人都受影响。子用户单独停用即可。
1.3 一条实用原则
主账号只用来做两件事:管理 IAM,和付钱。 其他所有日常操作——开机器、传文件、跑脚本、看监控——都该用子用户。
这条原则听起来麻烦,但它把「最高权限」的使用频率压到了最低。
二、AK/SK 到底是什么
2.1 不是密码
AK/SK 是给程序用的凭证,不是给人登录用的:
- AK(Access Key ID):相当于用户名,公开也无所谓
- SK(Secret Access Key):相当于密码,绝对不能泄露
用 AK/SK 调用 API 时,客户端会用 SK 对请求做签名,服务端验签。所以 SK 一旦泄露,别人就能以你的身份调用 API。
它和登录密码的区别在于:密码泄露了你可以改,但用密码登录需要过二次验证;AK/SK 泄露了,对方直接调接口,没有任何二次验证挡着。
2.2 三条铁律
不进代码仓库。 不要写在源码、配置文件、Dockerfile 里。用环境变量或密钥管理服务。如果已经提交过,删掉文件没用——提交历史里还在,必须把密钥作废重发。
不进前端。 浏览器里的任何东西都能被看到,包括打包压缩后的 JS。
定期轮换。 建议半年到一年换一次。轮换方式是新建一个 AK,切换应用,确认无误后删掉旧的——不要先删后建,那会导致服务中断。
2.3 泄露的后果取决于挂了什么权限
这一点值得强调:AK/SK 泄露的危害,等于它被授予的权限。
- 一个只有 OBS 只读权限的 AK 泄露 → 别人最多看看你的文件
- 一个 Administrator 权限的 AK 泄露 → 别人能做你能做的一切,包括再创建新用户、删掉你的资源
所以「给最小权限」不是洁癖,它直接决定了你在最坏情况下的损失上限。
三、动手:建一个只能管 OBS 的子用户
下面这个例子做一个「给程序上传文件用」的子用户,只允许操作对象存储。
3.1 创建用户
路径:统一身份认证服务 IAM → 用户 → 创建用户
要填的几项:
| 项目 | 填什么 | 说明 |
|---|---|---|
| 用户名 | 例如 app-uploader |
建议体现用途,不要用「test」 |
| 访问方式 | 只勾「编程访问」 | 程序用,不需要登录控制台 |
| 凭证类型 | 访问密钥 | 创建时可直接生成 |
如果勾了「控制台访问」,会要求设密码,后续还要处理密码策略、首次登录改密等一堆事。纯程序调用不需要开控制台访问,别给自己找麻烦。
3.2 建用户组并授权
不建议直接给单个用户授权,用用户组更清晰。
- IAM → 用户组 → 创建用户组,命名为
obs-app - 给这个组授权:选择策略
OBS FullAccess(如果需要限制更细,用OBS ReadOnlyAccess或自定义策略) - 回到用户,把
app-uploader加入obs-app组
系统策略的粒度比较粗——OBS FullAccess 意味着能操作所有桶。如果需要限制到某个桶,得写自定义策略:
{
"Version": "1.1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"obs:object:PutObject",
"obs:object:GetObject"
],
"Resource": [
"obs:*:*:object:my-app-files/*"
]
}
]
}
这段的意思是:只允许对 my-app-files 这个桶里的对象做上传和下载,其他一概不行。即使这个 AK 泄露,攻击者也碰不到别的桶。
3.3 生成 AK/SK
IAM → 用户 → 选中 app-uploader → 访问密钥 → 新增访问密钥。
SK 只在创建时显示一次,关掉页面就再也看不到了。妥善保存:密码管理器、或者服务器的密钥管理里。丢了只能删掉重建。
3.4 给主账号开 MFA
这一步经常被跳过,但它比任何权限配置都重要。
IAM → 安全设置 → 多因素认证(MFA),绑定一个虚拟 MFA 应用(手机上的认证器)。
开启后,即使有人拿到了你的主账号密码,没有动态验证码也登不进去。主账号必须开,没有例外。
3.5 验证一下
配好了别急着上线,先用这个 AK 试一次该做的和不该做的:
# 应该成功:上传到指定的桶
obsutil cp ./test.txt obs://my-app-files/test.txt
# 应该失败:访问别的桶
obsutil ls obs://other-bucket/
# 预期返回 AccessDenied
第二条能正常返回,说明权限给大了,回去检查策略。
四、最小权限怎么落地
「最小权限」不是一句口号,有三条可操作的做法。
4.1 从「给服务」到「给动作」
不要给 Administrator,也不要图省事给 FullAccess。问自己一句:这个程序具体要做哪几个动作?
一个只需要上传文件的后台,权限就是 PutObject,不需要 DeleteObject,不需要 ListBucket,更不需要管桶的配置。
4.2 按资源收窄
权限有两个维度:能做什么动作,和能对哪些资源做。
很多人只限制了前者(给了 PutObject),忘了限制后者(所有桶都能传)。用 Resource 字段收窄到具体桶的前缀,才是完整的最小权限。
4.3 定期回头看
权限给多了不会立刻出问题,所以很难被发现。两个检查方法:
- 看操作日志:哪些动作从来没被调用过?说明对应权限是多余的
- 定期列一遍子用户:离职的人、废弃的脚本、测试期建的临时账号,都该清理
五、五个常见错误
| 现象 | 原因 | 解法 |
|---|---|---|
| 子用户登录控制台后一片空白 | 只开了控制台访问,没授任何策略 | 给用户组授权 |
| 提示「没有权限执行该操作」 | 策略里缺对应的 Action | 按报错补 Action |
| 能上传但列不出文件 | 缺 ListBucket / ListBucketVersions |
补列表权限 |
| AK 生成后找不到了 | SK 只显示一次,没保存 | 删掉重建,这次存好 |
| 程序报签名错误 | AK/SK 复制时多了空格或换行 | 重新粘贴,注意首尾空白 |
六、如果 AK/SK 已经泄露了
这是最现实的问题。假设你刚发现一个 AK 已经提交到公开仓库,或者不小心发到了群里,按这个顺序处理:
6.1 第一时间作废凭证
IAM → 用户 → 选中对应用户 → 访问密钥 → 删除那个泄露的 AK。
删除是立即生效的,之后所有用这个 AK 的请求都会失败——包括你自己的程序。先止血,再恢复业务,这个顺序不能反。
如果是主账号的 AK,处理方式一样,但之后必须把全部权限重新核对一遍,因为这段时间里对方可能做了任何事。
6.2 查操作日志,看对方做了什么
这是判断损失范围的关键一步。云审计服务(CTS)里能看到所有 API 调用记录,按时间和用户筛选。
重点看三类动作:
- 有没有创建新的用户或 AK(对方通常会留后门)
- 有没有删资源(数据库、快照、存储桶)
- 有没有开新机器(挖矿是最常见的滥用方式,账单会异常增长)
6.3 查账单
看最近几天的消费有没有突然上涨。挖矿、开高配机器、跑流量,都会直接体现在账单上。
发现异常消费,除了停资源,还要保留证据(账单截图、操作日志),有些云厂商对凭证泄露导致的损失有申诉流程。
6.4 修根因,不是只换密钥
换掉 AK 只解决这一次。如果不解决泄露的原因,下次还会发生。
问自己:它是怎么泄露的?
- 写进了代码 → 清理仓库历史,加
.gitignore,考虑用 pre-commit 钩子扫描密钥 - 写在配置文件里 → 改用环境变量或密钥管理服务
- 放在共享文档/群里 → 建立凭证流转规范
- 被恶意软件窃取 → 排查服务器是否已被入侵
6.5 一个容易被忽略的点
删掉 Git 里的文件不等于删掉密钥。 提交历史里还在,任何人 clone 下来都能翻到。要么用 git filter-repo 重写历史(会改变所有 commit hash,需要团队协调),要么直接认账——把密钥作废比清理历史更彻底也更省事。
七、小结
云账号的安全模型里,最重要的一条分界线是**「谁是所有者」和「谁在干活」**。
主账号是所有者,它的权限无法限制,所以它的凭证不该出现在任何代码里。所有实际的活都该交给子用户——它们的权限可以被精确收窄,出事能追溯,泄露的损失有上限。
回到开头那个问题:如果 config.py 里那串 AK/SK 是主账号的,那它就意味着整个账号。换成子用户的、只挂了 OBS 权限的 AK,同样的泄露,损失从「一切」变成「几个文件」。
这件事花不了十分钟,但它决定了你在最坏情况下的底线。
- 点赞
- 收藏
- 关注作者
评论(0)