AK/SK 别进聊天记录:华为云多账号凭证的三层隔离与 hcloud 实战坑位

举报
yd_245773411 发表于 2026/11/06 08:06:12 2026/11/06
【摘要】 一台服务器要同时跑脚本、发作品、读工单,长期密钥放环境变量里等于把账号交出去。这篇记录三层隔离的落地:600 权限的密钥文件、hcloud profile 隔离账号与区域、24 小时的 IAM 委托换一次性 STS。附带四个实测坑:hcloud 不认环境变量、默认 readTimeout 太短、委托 409 不等于可用、临时凭证落盘必须 finally 删。

脚本化操作云平台,第一个绕不开的问题不是接口怎么调,而是密钥放在哪。贴进聊天框、写进 crontab、塞进环境变量,三种做法都在扩大泄露面。这篇讲我在一台 ARM 服务器上给华为云做凭证分层的过程,目标是:日常脚本手里永远只有一次性凭证,长期密钥只有一个 600 权限的文件能读到。

一、三层边界

先把边界划清楚,后面每个坑都是某一层没守住导致的:

  • 第一层 · 账号密钥:主账号 AK/SK,唯一合法存放点是 ~/.secrets/*.env,权限 600,不 source 到交互 shell,只被需要它的脚本读取。
  • 第二层 · CLI profile:hcloud 的 profile 把账号、密钥、区域、超时绑在一起,切账号不用改环境变量,也就不会出现「A 账号的密钥打 B 账号的接口」。
  • 第三层 · 临时凭证:用 IAM 委托换 STS token,有效期一天,落盘到临时目录,跑完删除。业务脚本只认这一层。

这样一层层下来,能泄露的东西从「永久密钥」变成「24 小时的临时 token」,而且 token 只能干委托里授权的事。

二、坑一:hcloud 根本不读环境变量

直觉做法是 export HUAWEICLOUD_SDK_AK=... 然后调 CLI。实测直接 Unauthorized——CLI 走的是自己的配置体系,环境变量只对 SDK 生效。两条路:要么每次显式传参,要么写进 profile。

# 方式一:显式传参(适合一次性调用,不留痕)
hcloud IAM KeystoneListAuthDomains   --cli-access-key="$AK" --cli-secret-key="$SK"   --cli-region=cn-north-4

# 方式二:写进 profile(适合反复调用)
hcloud configure set   --cli-access-key="$AK" --cli-secret-key="$SK"   --cli-domain-id="$DOMAIN" --cli-region=cn-north-4   --cli-profile=default

注意方式二的收尾:配置会落在 ~/.hcloud/config.json 明文里。用完必须把 accessKeyId / secretAccessKey 清空。这里有个小坑——hcloud configure set --cli-access-key="" 会报参数错误,清不掉,只能改 JSON:

python3 - <<'EOF'
import json, os
p = os.path.expanduser('~/.hcloud/config.json')
d = json.load(open(p))
for prof in d.values():
    if isinstance(prof, dict):
        prof['accessKeyId'] = ''
        prof['secretAccessKey'] = ''
json.dump(d, open(p, 'w'), indent=1)
EOF

三、坑二:默认超时短到必失败

IAM 和 STS 这类鉴权接口跨区域调用经常 10~30 秒才回。CLI 默认的读超时只有几秒,表现是 API calling timed out,而脚本里再包一层解析,就会变成「解析 hcloud 输出失败(无 JSON 内容)」——看起来像返回格式问题,实际是根本没等到响应。

hcloud configure set --cli-read-timeout=90 --cli-connect-timeout=20

同样的错我在 Node 脚本里也踩过一次:子进程默认超时 30 秒,而真实调用要 10~30 秒,边缘概率直接抛 spawnSync ETIMEDOUT。所以凡是跨公网的鉴权调用,超时一律按 90 秒配,别用默认值。

四、坑三:委托 409 不等于可用

临时凭证要靠一个「委托」(agency)来换。第一次跑会报「委托不存在」,因为平台不会自动建;自己建一次,24 小时过期。第二天再跑,创建接口回 409 已存在,看着像成功,但换 token 时又报找不到——因为同名委托的 expire_time 已经过了。

# 先查过期时间,别直接建
hcloud IAM ListAgencies --cli-region=cn-north-4   | jq -r '.agencies[] | "\(.id)  \(.name)  \(.expire_time)"'

# 过期就删掉重建
hcloud IAM DeleteAgency --agency_id="$OLD_ID" --cli-region=cn-north-4
hcloud IAM CreateAgency --agency.name=SELF_VERIFY   --agency.domain_id="$DOMAIN" --agency.trust_domain_id="$DOMAIN"   --agency.duration=ONEDAY --cli-region=cn-north-4

判定标准写清楚:409 只说明名字被占用,能不能用只看 expire_time 是否在未来。这一条让排障从「玄学」变成一次查询。

五、第三层落地:换 token、用完就删

拿到委托后换 STS,把三件套(ak / sk / token)写成 0600 的临时文件,交给业务脚本;脚本读到内存后立刻删文件。关键是 finally 里删——中途抛异常也要删,否则临时凭证就变成长期凭证躺在磁盘上。

import json, os, subprocess, tempfile

creds = os.path.join(tempfile.mkdtemp(), 'sts.json')
try:
    subprocess.run([
        'python3', 'gen_sts.py',
        '--account', domain, '--region', 'cn-north-4',
        '--creds-out', creds,
    ], check=True)
    d = json.load(open(creds))
    ak, sk, tok = d['accessKeyId'], d['secretAccessKey'], d['securityToken']
    # ... 交给业务调用
finally:
    if os.path.exists(creds):
        os.remove(creds)

验证方式别靠「没报错」:用临时凭证调一个只读接口,看 HTTP 状态码。

curl -s -o /dev/null -w '%{http_code}
'   -H "X-Auth-Token: $TOKEN"   "https://iam.myhuaweicloud.com/v3/auth/projects"

200 才算通;401 说明 token 拼错或过期,403 说明委托里没这条权限——三种状态对应三个完全不同的修法,比看日志猜快得多。

六、为什么值得做

这套东西第一次搭要花一两个小时,之后每次跑多三行代码。换来的是:脚本仓库里没有明文密钥,服务器上只有一个 600 文件,临时凭证的权限被委托卡死、寿命只有一天。真要出事,暴露窗口从「永久」压缩到「至多 24 小时,且只能做委托允许的那几件事」。

顺带一个副产品:因为凭证要手动换,反而逼着把「谁在调什么接口」梳理清楚了。这比任何密钥管理系统都管用。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。