阿里云、腾讯云与华为云 CLI:身份、项目与可审计资源查询
一条查询命令为什么看到了不该看的资源
开发者只是想确认测试环境还有几台云服务器,于是在终端里运行了熟悉的列表命令。命令退出码为 0,结果也确实有三台实例,但实例名、地域和费用中心里的记录对不上。继续追查才发现:上周处理故障时切换过另一个账号的 profile,终端里还残留一个覆盖默认地域的环境变量;脚本没有打印当前调用者,也没有记录 Request ID;结果文件随后被当成测试环境库存继续处理。
云 CLI 最危险的失败并不总是 403,而是“用错误身份成功执行”。阿里云 CLI、腾讯云 TCCLI 和华为云 KooCLI 都是本地客户端:它们读取凭证与默认参数,选择服务 endpoint,对请求签名,再调用厂商控制面 API。客户端显示“配置成功”,只说明本地文件可以写入;列表返回空数组,既可能表示资源确实为零,也可能表示地域、项目、账号或过滤条件错了;命令返回资源,更不能自动证明这些资源属于当前开发任务。
安全的第一条远程命令应回答“我是谁”,第二条回答“我在哪个地域或项目”,第三条才查询资源。每次变更还应把调用者、profile、地域、项目、动作、资源 ID、退出码和 Request ID 组织成同一份证据。这样权限不足是可解释的拒绝,空结果是可以继续验证的状态,成功结果也不会脱离身份与归属上下文。
先分清账号、身份、地域和项目四层对象
三家云的名词相似,授权边界却不能互换。
阿里云账号是资源与账单的顶层归属,RAM 用户和 RAM 角色是调用身份。CLI profile 保存或获取该身份所需的凭证以及默认地域。地域决定区域化服务的 endpoint 和资源集合;资源组可以辅助分组、授权和成本治理,但不是所有 API 都有统一的“项目”参数,也不能把资源组名称当作账号证明。
腾讯云主账号是资源归属,CAM 子用户、角色和联合身份承担调用。TCCLI profile 将凭证文件与普通配置文件分开,地域仍是每次区域化 API 的关键输入。腾讯云部分产品支持项目 ID 过滤,但项目不是 TCCLI 的全局身份容器;未传项目过滤并不等于“只查默认项目”。CAM 策略、角色信任关系和具体 API 的资源级授权共同决定最终结果。
华为云账号之下由 IAM 用户、用户组、委托或联合身份获得权限。许多区域级服务以 project_id 作为 URL 路径中的授权和资源隔离维度,因此“region 正确但 project_id 错误”会直接查询另一个项目或被拒绝。domain_id 表示账号级对象,企业项目又是另一条资源治理维度,不能拿企业项目 ID 替代 IAM 项目 ID。华为云 IAM 的项目查询 API返回项目的 id、name、domain_id 与启用状态,正适合把名称和 ID 的映射保存为受控台账。
可以把调用链画成同一个心智模型:
操作人或工作负载
-> 本地 profile / SSO session / 临时凭证
-> RAM、CAM 或 IAM 身份
-> 显式 region + 可选 resource group/project/enterprise project
-> 云产品 OpenAPI endpoint
-> 资源结果 + Request ID + 审计事件profile 只是“如何找到凭证与默认参数”,region/project 才描述请求落点,RAM/CAM/IAM 策略决定能做什么,审计服务记录实际发生了什么。把这四层压成一个 default,是跨账号误操作最常见的起点。
把三套 CLI 装进可复现的工具目录
安装包、支持系统和当前版本会继续变化,建立基线时应从三家的阿里云 CLI 安装页、TCCLI 安装页和KooCLI 安装页进入,按目标操作系统与 CPU 架构选择包,并记录下载来源、哈希、安装方式和版本输出。团队脚本不要静默安装“latest”后立刻操作云资源;升级应先在只读探针中验证。
阿里云 CLI 是独立可执行文件。插件化版本按产品安装命令元数据;官方说明低于 3.3.0 的版本不再维护,旧环境应先迁移再接入自动化。TCCLI 通过 Python 包分发,适合放进虚拟环境,避免系统 Python 与腾讯云 SDK 被全局升级。KooCLI 也是独立可执行文件,首次运行会询问隐私声明;无人值守节点需要由平台负责人预先审阅并显式记录同意,不能靠脚本向任何交互提示盲目输入 y。
# 阿里云:安装方式按官方页面选择,验证时不需要凭证
aliyun version
aliyun --help
aliyun ecs describe-instances --help
# 腾讯云:放在项目外的工具虚拟环境中
python -m venv .tooling/tccli
. .tooling/tccli/bin/activate
python -m pip install 'tccli==<approved-version>'
tccli --version
tccli sts GetCallerIdentity help
# 华为云:解压官方包并校验发布页提供的 SHA-256 后
hcloud version
hcloud configure test
hcloud IAM KeystoneListProjects --help版本号只作为本机证据保存,不把某次运行结果写成长期推荐版本。命令差异应由当前二进制的帮助页确认:阿里云使用 version,TCCLI 使用 --version,KooCLI 使用 version。阿里云 3.3.0+ 的产品命令可能依赖产品插件;先执行目标命令的 --help,再按该版本 CLI 给出的安装提示补齐所需组件,避免在自动化里猜测或批量安装插件。
Windows 可以把虚拟环境激活命令替换为 .tooling\tccli\Scripts\Activate.ps1。CI 中更稳妥的做法是直接调用虚拟环境里的完整可执行文件路径。安装目录只放二进制和依赖,不放云凭证;缓存二进制时将操作系统、架构、CLI 版本和插件版本都放进缓存键。
RAM、CAM、IAM 的最小授权不是三个管理员账号
个人开发机不应保存主账号长期 AK/SK。正确的授权关系至少分成“获得会话”和“会话能调用哪些 API”两层:人的身份通过 SSO、OAuth 或受控入口获得短期会话;基础身份只能扮演指定角色;角色只在指定账号、地域或项目内拥有完成任务所需的读写动作。工作负载运行在云主机或容器时,优先使用实例角色、委托或 OIDC,让平台轮换临时凭证。
阿里云 RAM 角色需要信任策略决定谁可扮演,权限策略决定角色可调用什么。调用 AssumeRole 的基础身份也必须被允许扮演那个明确 ARN,而不是获得不受约束的 STS 权限。阿里云的STS CLI 调用说明展示了 RAM 用户、角色 ARN、会话名和临时凭证之间的关系;开发环境至少把 sts:GetCallerIdentity、地域查询和目标产品只读查询作为第一阶段探针,变更动作另设短时角色。
腾讯云 CAM 角色同样由信任策略与权限策略组成。官方CAM 角色概念特别提醒,不受限制的 AssumeRole 权限可能让子账号扮演不应访问的角色。TCCLI 当前支持实例角色、角色、TKE OIDC、临时密钥与长期密钥,并按凭证管理说明解析;这不是“找到哪个就都能用”,而是要防止高优先级环境输入悄悄覆盖预期 profile。
华为云 IAM 权限通常授予用户组、IAM 项目或账号级作用域。先使用系统策略 ECS ReadOnlyAccess 验证只读链路,再根据 API 的授权信息缩小自定义动作;例如列出 ECS 详情对应 ecs:cloudServers:listServersDetails,官方服务授权参考同时说明了访问级别、资源类型和条件键。运行在 ECS 上的程序应使用 IAM 委托取得自动轮换的临时凭证,华为云的访问凭证实践也给出了临时 AK/SK、安全令牌、ecsAgency 与 SSO 的适用方式。
“只读”仍可能读取实例名称、内网地址、标签、镜像、组织结构和账单关联信息。授权评审要同时看动作、资源、条件和返回数据,不应只看策略名称。
阿里云:profile、STS 身份和插件化资源查询
阿里云 CLI 的配置文件默认位于用户主目录下的 .aliyun/config.json。官方凭证配置说明支持 OAuth、AK、STS Token、ECS RAM 角色、RAM 角色 ARN 与 Cloud SSO 等模式。人的日常终端优先使用组织启用的 OAuth/Cloud SSO 或角色会话;必须从基础凭证扮演角色时,让 RamRoleArn profile 自动获取临时凭证,避免把 STS 三元组手工复制到多个文件。
# 交互创建角色 profile;只在受控提示中输入身份平台发放的值。
aliyun configure --mode RamRoleArn --profile PROFILE_ALIYUN_DEV_RO
aliyun configure get --profile PROFILE_ALIYUN_DEV_RO profile mode region
aliyun sts get-caller-identity \
--profile PROFILE_ALIYUN_DEV_RO \
--region cn-hangzhou远程身份查询成功时,应看到账号 ID、当前主体 ARN 和角色会话信息,并保留顶层 RequestId。如果 ARN 仍是基础 RAM 用户而不是预期角色,不能继续执行资源查询。官方快速入门也用 sts get-caller-identity 验证凭证,并说明产品响应中的 RequestId 可用于排障。
插件化 ECS 查询的参数名以 --help 为准,不要把 OpenAPI 的驼峰字段想当然地复制成旧 CLI 语法。下面只读取两条实例记录,并同时显式提供 endpoint 解析地域和业务地域:
aliyun ecs describe-instances \
--profile PROFILE_ALIYUN_DEV_RO \
--region cn-hangzhou \
--max-results 2 \
--resource-group-id RESOURCE_GROUP_ID_PLACEHOLDER \
--cli-query '{RequestId:RequestId,Items:Instances.Instance[].{Id:InstanceId,Name:InstanceName,Status:Status}}'--region 是 CLI 用来选择服务 endpoint 的地域输入;DescribeInstances 的资源地域也由该输入确定,不要额外拼接未经当前插件帮助确认的业务地域参数。预期结果包含 RequestId 和至多两条实例摘要。空 Items 只证明当前账号、角色、地域、资源组与过滤条件的交集为空;去掉资源组过滤再次查询、在控制台核对账号与地域、查询另一个已知只读对象,才能判断是“没有资源”还是“作用域选错”。--cli-query 只减少终端显示,不改变服务端权限,也不保证敏感字段从调试日志中消失。
阿里云 CLI 要分开理解“选择哪个 profile”和“同名参数从哪里取值”。profile 选择顺序是命令行 --profile、ALIBABA_CLOUD_PROFILE、当前活动 profile;选定 profile 后,同一运行参数通常按命令行、配置文件、环境变量的顺序覆盖,--region 还会高于 profile 与 ALIBABA_CLOUD_REGION_ID。官方环境变量清单还提供 ALIBABA_CLOUD_IGNORE_PROFILE=TRUE,用于明确忽略配置文件而只使用环境输入。项目脚本应每次传 --profile 和 --region,启动时拒绝意外存在的长期 AK 环境变量,并用 aliyun configure get --profile ... profile mode region 与远程 STS 身份一起留证。不要依赖 configure switch 改全局活动 profile,因为并行终端会共享这个持久状态。
腾讯云:CAM 身份、双配置文件和显式地域
运行 tccli configure --profile PROFILE_TENCENT_DEV_RO 后,TCCLI 会在 ~/.tccli 生成同名前缀的 .credential 与 .configure 文件:前者保存密钥材料,后者保存地域、输出格式、服务 API 版本与 endpoint。官方TCCLI 配置说明给出了文件结构和多 profile 行为。不要把整个目录打包进项目缓存,因为普通配置与敏感凭证同目录相邻。
组织已启用集团身份管理时,优先走TCCLI SSO 登录,它能为不同 profile 取得并刷新临时密钥。没有 SSO 时,由受控基础身份扮演限定的 CAM 角色;临时密钥由 TmpSecretId、TmpSecretKey 和 Token 三部分组成,少传 Token 会表现为签名或身份失败。
# SSO 地址、账号和角色均使用组织发放值
tccli sso configure --url SSO_LOGIN_URL_PLACEHOLDER
tccli sso login \
--uin ACCOUNT_UIN_PLACEHOLDER \
--rolename ROLE_NAME_PLACEHOLDER \
--profile PROFILE_TENCENT_DEV_RO
# 每次远程操作先证明调用者
tccli sts GetCallerIdentity \
--profile PROFILE_TENCENT_DEV_RO \
--region ap-guangzhou \
--output json
# 再查询受控地域的少量实例
tccli cvm DescribeInstances \
--profile PROFILE_TENCENT_DEV_RO \
--region ap-guangzhou \
--Limit 2 \
--Filters '[{"Name":"tag:owner","Values":["OWNER_PLACEHOLDER"]}]' \
--output jsonGetCallerIdentity 的成功响应位于 Response 下,关键字段是 Type、AccountId、UserId、PrincipalId、Arn 和 RequestId。腾讯云STS API 概览明确列出该接口;当 Type 为 CAMRole 时,还应核对会话名与承担者账号。资源查询的 Response.RequestId 必须和身份查询分别保存,因为它们是两次调用。
TCCLI 当前通用参数说明把同一参数的来源优先级定义为命令行、环境变量、配置文件、内置默认值;--profile 高于 TCCLI_PROFILE,但只选中配置文件,并不会让其他环境输入消失。凭证模式还有独立选择顺序:实例角色、角色、TKE OIDC、临时密钥、长期密钥。TENCENTCLOUD_SECRET_ID、TENCENTCLOUD_SECRET_KEY、TENCENTCLOUD_TOKEN、TENCENTCLOUD_ROLE_ARN 和 TENCENTCLOUD_REGION 都可能改变实际身份或落点;脚本若使用 --profile,启动时仍应检查并拒绝冲突变量,不能只看到 profile 名正确就继续。tccli configure list 会打印很长的服务版本和 endpoint 元数据,不适合作为身份探针,也不宜原样上传;只读取需要的配置键,远程身份仍由 STS 响应证明。
华为云:KooCLI 的 region、project_id 与委托
KooCLI 默认将 profile 存在用户主目录的 .hcloud/config.json。hcloud configure show 展示的是本地配置,不是服务端对当前调用者的确认。华为云很多 API 要求同时传 --cli-region 与 --project_id;profile 中可以保存常用值,但项目脚本仍应显式传入并与台账比对。--cli-profile、--cli-region 和命令中的 --project_id 是本次调用的显式输入,脚本应在执行前把它们与受控目标清单逐项比较。domain_id 用于账号级 IAM 查询,project_id 用于区域项目资源,二者字符形态相近,互换后常见结果是 401、403、404 或空列表。
# 在受控终端按当前版本的交互提示创建 profile;不要把 AK/SK 或 SecurityToken
# 放进命令行、shell 历史、仓库文件或 CI 日志。
hcloud configure --help
hcloud configure show --cli-profile=PROFILE_HUAWEI_DEV_RO
# 服务端查询可访问项目;本地 show 不能替代它
hcloud IAM KeystoneListProjects \
--cli-profile=PROFILE_HUAWEI_DEV_RO \
--cli-region=cn-north-4 \
--domain_id=DOMAIN_ID_PLACEHOLDER \
--cli-query='projects[].{Id:id,Name:name,DomainId:domain_id,Enabled:enabled}' \
--cli-output=jsonIAM 身份中心已经启用时,人的开发机可从当前 KooCLI 的 hcloud configure sso 入口登录。交互过程会分别要求 SSO profile、IAM 身份中心门户地址、SSO region 和业务服务常用 region;前者描述身份中心所在位置,后者描述云服务调用位置,两者可能不同。登录后只用 hcloud configure show --cli-profile=PROFILE_HUAWEI_DEV_RO 核对非敏感配置,再通过 IAM 项目列表和目标产品 API 证明权限。SSO 会话材料仍写入本地配置目录,不能把 .hcloud 缓存进构建产物或多人共享目录。
项目列表成功后,脚本应断言目标 PROJECT_ID_PLACEHOLDER 存在、enabled 为 true、其 domain_id 等于预期账号,再调用 ECS。列出 ECS 详情所需的权限动作可在官方ECS 列表 API核对;KooCLI 的操作名随 API 元数据生成,先运行 hcloud ECS --help 与目标操作 --help,不要凭另一版本文档猜命令。
运行在华为云 ECS 上时可以配置 ecsAgency profile,不保存 AK/SK:
hcloud configure set \
--cli-profile=PROFILE_HUAWEI_ECS_AGENCY \
--cli-mode=ecsAgency \
--cli-region=cn-north-4 \
--cli-project-id=PROJECT_ID_PLACEHOLDER这个 profile 只有在已绑定正确 IAM 委托的 ECS 内才成立。普通笔记本无法访问实例元数据服务,出现“获取 ECS 委托认证信息失败”是正确拒绝,不应通过代理元数据地址、关闭 TLS 校验或写入长期 AK 来绕过。KooCLI 还支持 SSO;团队应在 SSO、临时 AK/SK、ECS 委托之间选择与执行环境匹配的一种身份源,不能在同一 profile 里混入多套可用凭证后靠优先级碰运气。
正向实验:先证明二进制隔离,再证明云端身份
正向实验分两段。第一段完全本地,不需要云账号,用临时主目录证明版本与帮助命令不读取个人 profile;第二段由读者在测试账号中使用只读角色完成,验证远程身份、项目和资源查询。两段都成功,才能说明“工具可运行且目标身份可用”。
$sandbox = Join-Path $env:TEMP 'cloud-cli-profile-sandbox'
New-Item -ItemType Directory -Force -Path $sandbox | Out-Null
$oldHome = $env:HOME
$oldUserProfile = $env:USERPROFILE
try {
$env:HOME = $sandbox
$env:USERPROFILE = $sandbox
aliyun version
aliyun ecs describe-instances --help
tccli --version
tccli sts GetCallerIdentity help
hcloud version
hcloud IAM KeystoneListProjects --help
}
finally {
$env:HOME = $oldHome
$env:USERPROFILE = $oldUserProfile
}本地成功证据是三套工具在空主目录中都能输出版本与目标命令帮助,且没有产生凭据文件或云端 Request ID。这个实验故意不写入哪怕是“占位”的 AK/SK、Token 或 profile:示例值会被复制、命令行参数会进入历史和进程观察面,二者都不应成为配置教学的一部分。
远程正向实验使用前三节的身份命令。通过标准是:身份响应中的账号与角色会话符合台账;阿里云和腾讯云资源响应有各自 Request ID;华为云项目列表包含目标项目,资源查询的 --debug 输出能取得 HTTP 状态和 X-Request-Id;三套查询都限制返回数量,且结果中的每个资源都能用 owner、environment、expires-at 等标签证明归属。资源为零可以通过,但必须保留身份和作用域证据,不能只保存 []。
反向实验:让错误身份和错误项目稳定失败
反向实验的目标不是制造随机网络错误,而是证明保护机制会在错误输入下停住。最先做“空主目录无凭证”实验:
# 在隔离 HOME/USERPROFILE 中执行,不能继承个人配置
aliyun sts get-caller-identity \
--profile PROFILE_DOES_NOT_EXIST \
--region cn-hangzhou
tccli sts GetCallerIdentity \
--profile PROFILE_DOES_NOT_EXIST \
--region ap-guangzhou
hcloud IAM KeystoneListProjects \
--cli-profile=PROFILE_DOES_NOT_EXIST \
--cli-region=cn-north-4不同版本对不存在 profile 的本地报错文本并不稳定,测试只断言命令在网络调用前失败、退出码非零,且没有可关联的服务端 Request ID。排障时不要去审计服务里搜索一个根本没有形成有效云 API 调用的请求。
第二组实验由测试账号管理员准备“身份探针可用、产品资源查询被拒绝”的专用角色,不授予任何写动作,也不让它接触生产数据。先运行三家的 STS/IAM 身份探针,证明凭据有效;再分别执行同一测试地域的 ECS/CVM/ECS 只读列表:
aliyun ecs describe-instances \
--profile PROFILE_ALIYUN_DENY_TEST \
--region cn-hangzhou \
--max-results 1
tccli cvm DescribeInstances \
--profile PROFILE_TENCENT_DENY_TEST \
--region ap-guangzhou \
--Limit 1 \
--output json
hcloud ECS ListServersDetails \
--cli-profile=PROFILE_HUAWEI_DENY_TEST \
--cli-region=cn-north-4 \
--project_id=PROJECT_ID_PLACEHOLDER \
--limit=1 \
--cli-output=json正确证据是身份探针成功,而产品查询非零退出并带服务端授权错误与 Request ID;这把“凭据坏了”和“权限按设计拒绝”分开。若列表成功、只返回空数组,或脚本自动换用其他 profile,反向门禁都算失败。另一类反例是故意把 region 或 project ID 换成不在受控清单中的占位值:API 可能返回授权拒绝、项目不存在或空列表,保护层必须先因账号、角色、地域、project ID 或 owner 标签断言不匹配而非零退出,不能要求所有厂商都返回同一个 403。
KooCLI 还有一个很容易误判的反例:在普通开发机配置 ecsAgency 后执行带 --dryrun 的命令,仍会先尝试访问 ECS 元数据服务,并因无法取得委托凭证而失败。这证明 dryrun 负责构造与检查请求,不代表它绕过认证。阿里云产品 API 的 --dry-run 也可能真正调用服务端权限检查,并以特定错误码表示检查通过;TCCLI 的 --generate-cli-skeleton 只生成参数结构。三个“预演”词义不同,自动化不得抽象成一个统一的 dryRun=true 后就默认安全。
项目脚本先做守卫,再执行只读动作
团队脚本不应把三个 CLI 命令直接散落在构建步骤里。先集中维护账号、profile、地域、项目和允许动作映射,再由守卫脚本验证环境变量冲突、远程身份与资源标签。凭证由 CI 身份提供者注入,仓库只保存非敏感映射和断言。
targets:
aliyun-dev:
provider: aliyun
profile: PROFILE_ALIYUN_DEV_RO
expectedAccount: ACCOUNT_ID_PLACEHOLDER
expectedRole: ROLE_NAME_PLACEHOLDER
region: cn-hangzhou
resourceGroupId: RESOURCE_GROUP_ID_PLACEHOLDER
tencent-dev:
provider: tencent
profile: PROFILE_TENCENT_DEV_RO
expectedAccount: ACCOUNT_UIN_PLACEHOLDER
expectedRole: ROLE_NAME_PLACEHOLDER
region: ap-guangzhou
huawei-dev:
provider: huawei
profile: PROFILE_HUAWEI_DEV_RO
expectedDomain: DOMAIN_ID_PLACEHOLDER
projectId: PROJECT_ID_PLACEHOLDER
region: cn-north-4
policy:
requiredTags: [owner, environment, expires-at, cost-center]
allowedOperations: [identity, list-regions, list-projects, list-resources]实际 cloud-targets.yaml 如果包含真实账号和项目 ID,应按内部敏感配置管理,不要默认公开。守卫的执行顺序固定为:解析目标;拒绝不在 allowlist 的 provider 和 operation;检查 CLI 版本;清除或拒绝冲突凭证环境变量;调用远程身份;对账号、角色、domain/project 做精确字符串比较;执行限量只读查询;逐条检查资源标签;最后把脱敏摘要和 Request ID 写入受控证据目录。
脚本解析 JSON 应使用 jq、PowerShell ConvertFrom-Json 或语言 SDK,不能用 grep AccountId。错误输出与正常 JSON 分开保存,任何命令非零立即停止。重试只用于明确的限流和瞬时网络错误,并采用抖动退避;身份错误、权限错误、项目错误、参数错误和断言错误都不重试。对于创建、停止、释放、删除等写动作,使用另一条短时角色和人工批准流程,不能因为同一个只读脚本“已经登录”就继承权限。
Request ID 是连接终端、工单与审计的主键
一次合格的调用证据至少包含:工具及版本、profile 名、凭证模式、脱敏调用者、账号或 domain、region、project/resource group、产品与动作、参数摘要、开始和结束相对时间、退出码、HTTP 状态、错误码、Request ID、结果数量和脚本版本。不要保存 Secret、Token、完整签名、Cookie、SSO 刷新材料或响应中的敏感业务字段。
阿里云多数 OpenAPI 把 RequestId 放在响应 JSON 顶层,ActionTrail 事件中的 requestId 可以把 CLI 结果与操作人、源 IP、地域和事件名关联起来。官方ActionTrail 介绍说明控制台、OpenAPI 和开发者工具行为都会进入管控事件;数据事件与长期投递需要单独配置,并可能产生 SLS 或 OSS 存储费用。
腾讯云 API 3.0 通常把 RequestId 放在 Response 内。请求如果没有抵达服务端,可能没有 Request ID;这与本地 profile 错误、DNS、代理或 TLS 失败相符。进入服务端后收到 AuthFailure、UnauthorizedOperation、限流或参数错误时,应保存 Response.Error.Code、Message 和 RequestId,再到操作审计 CloudAudit 按时间、身份、动作和请求标识关联。
华为云的 Request ID 常在响应头 X-Request-Id,不保证出现在业务 JSON。KooCLI 加 --debug 会显示请求 URL、HTTP 状态和 X-Request-Id;官方空响应判断说明也建议通过 debug 中的状态码确认无响应体操作是否成功。debug 可能同时暴露 endpoint、项目 ID、资源 ID 和请求参数,只能在受控日志中短时开启。华为云 CTS 审计记录包含 request_id,可用它关联终端输出与资源操作。
Request ID 不是幂等键,也不是授权凭证。相同脚本重试会产生新的 Request ID;创建类 API 是否幂等要看产品是否支持客户端 token。工单里提供 Request ID 时,同时给出产品、地域、动作、近似时间和错误码,单独一个 UUID 往往不足以定位跨地域请求。
从错误形态反推失败发生在哪一层
command not found 或版本命令语法错误发生在本地安装层。先用 where aliyun、where tccli、where hcloud 或 Unix 的 command -v 找实际二进制,再核对虚拟环境、PATH、CPU 架构和文件执行权限。系统中有两份 CLI 时,版本输出必须和解析路径一起记录。
unknown profile、secretId is invalid、配置项不存在发生在本地凭证解析层。检查传入的 profile 名、HOME/USERPROFILE、配置文件权限和冲突环境变量。不要运行会把所有凭证明文或密文结构打印出来的全量命令后直接贴到群聊。TCCLI 的 .credential 和 .configure 必须成对检查;KooCLI 用 configure test 验证格式;阿里云用 configure get 只读取非敏感字段。
签名错误、Token 无效或凭证过期说明请求已进入认证层。核对系统时钟、临时凭证三元组是否完整、会话是否到期、AK/SK 是否来自同一批次、代理是否改写 Host,以及 endpoint 与签名地域是否一致。轮换时要原子替换整组临时凭证,不能只更新 Token。
403、UnauthorizedOperation、Forbidden.NoPermission 属于授权层。先运行身份探针确认调用者,再对照目标 API 的授权动作、角色会话策略、资源条件和项目作用域。不要立即授予管理员策略。能列地域但不能列实例,说明基础身份有效而产品权限缺失;能列实例但不能看标签,说明标签 API 可能需要独立动作;角色能扮演但资源操作被拒绝,说明信任策略成功、角色权限或会话策略仍有限制。
空列表属于最容易误诊的作用域层。依次核对账号、角色、region、project/resource group、endpoint、分页游标、标签过滤和资源状态。先去掉一个过滤条件而不是去掉全部保护;查询一个已知资源 ID 仍为空,再查控制台同账号同地域。华为云尤其要区分 project ID、domain ID 与 enterprise project ID;腾讯云项目过滤只影响支持该字段的产品;阿里云资源组过滤不能推断其他产品也使用相同分组。
429 或限流发生在容量层。读取响应中的限流信息与官方产品 API 限额,使用指数退避、随机抖动和分页,禁止多进程同时全量扫描每个地域。超时发生时先判断请求是否可能已被服务端接受;对写操作不能盲重试,必须用查询或幂等 token 确认中间状态。
配置清理和资源回滚是两件事
删除本地 profile 只会移除客户端找到凭证的路径,不会吊销服务端 AK、终止 SSO session、撤销角色会话,也不会删除云资源。反过来,释放云资源也不会清掉 shell history、CI secret、下载的配置备份和审计副本。离场流程必须分别处理本地、身份和资源三条生命周期。
# 先确认名称,再删除指定 profile;不要整目录递归清空
aliyun configure list
aliyun configure delete --profile PROFILE_ALIYUN_DEV_RO
tccli configure get region --profile PROFILE_TENCENT_DEV_RO
tccli configure remove --profile PROFILE_TENCENT_DEV_RO
tccli sso logout
hcloud configure show --cli-profile=PROFILE_HUAWEI_DEV_RO
hcloud configure delete --cli-profile=PROFILE_HUAWEI_DEV_RO
hcloud configure test若长期 AK 曾经落盘或进入日志,先在 RAM/CAM/IAM 服务端禁用或删除该密钥,再清理本地副本,并查询审计记录确认泄漏窗口内是否有异常调用。临时凭证过期不能替代泄漏响应;有效期内仍可被使用,SSO refresh token 还可能换取新会话。
资源回滚遵循“库存快照、归属断言、依赖检查、停用观察、删除、反查、账单确认”。先用只读角色生成目标 region/project 的库存,要求每个候选资源同时满足:资源 ID 在本次任务清单;owner 和 environment 标签匹配;expires-at 已到期;没有生产依赖;创建来源与审计事件可追踪。然后切换独立的 cleanup 角色,只允许对应产品的停止或删除动作。删除命令必须从当前 CLI 的帮助生成并填入 RESOURCE_ID_PLACEHOLDER,不能接受空变量、名称模糊匹配或“所有无标签资源”。
执行前至少运行这些帮助与查询入口:
aliyun ecs delete-instance --help
aliyun ecs describe-instances --profile PROFILE_ALIYUN_CLEANUP --region cn-hangzhou
tccli cvm TerminateInstances help
tccli cvm DescribeInstances --profile PROFILE_TENCENT_CLEANUP --region ap-guangzhou --Limit 10
hcloud ECS DeleteServers --help
hcloud ECS ListServersDetails --help删除后的成功标准不是命令退出 0,而是目标资源反查为不存在、关联磁盘/EIP/快照/负载均衡/安全组规则没有成为孤儿、自动续费或保留策略已关闭、费用明细不再增长,并能在 ActionTrail、CloudAudit 或 CTS 中找到写操作。包年包月退订、按量实例删除、快照和公网 IP 释放有不同计费后果,必须按具体产品文档处理;无法恢复的数据资源先做经批准的备份与恢复演练。
三套控制面的架构边界
云 CLI 适合可重复、可审查、参数明确的控制面操作:查询身份、列地域和项目、盘点少量资源、生成参数骨架、调用经过批准的 API。它不是跨云资源模型。把 aliyun/tccli/hcloud 包在同一个 cloud delete 函数里,只统一了入口,没有统一三家的身份、项目、异步状态、幂等、错误码和删除语义。
当脚本开始维护依赖图、状态文件、变更计划和漂移检测时,应评估 Terraform、OpenTofu 或厂商 IaC 服务,而不是继续堆 CLI 命令。即便采用 IaC,CLI 仍适合身份探针、只读核验、导入前盘点和故障诊断,但资源期望状态应由状态管理工具承担。
控制台适合首次探索、可视化依赖和高风险动作的人工确认;CLI 适合重复执行与证据采集;SDK 适合长期服务集成、类型化重试和自定义工作流;IaC 适合声明式生命周期。选择标准不是“哪一个更高级”,而是谁拥有状态、如何恢复、能否审计、并发冲突如何处理。
地域也不是单纯的字符串。它影响资源可用性、endpoint、网络时延、数据驻留、价格和审计落点。每次新增地域先查厂商当前地域与 endpoint 页面,再验证目标服务和规格确实可用;不要因为 CLI 接受一个 region 字符串就认为资源能创建。华为云项目与地域经常成对,阿里云和腾讯云的部分服务则是全局服务,强行给所有命令拼接 region 也可能选择错误 endpoint。
凭证、日志和响应数据都按敏感资产处理
长期 AK/SK、临时 AK/SK、SecurityToken、SSO refresh token、角色会话缓存和签名请求都属于凭证。账号 ID、project/domain ID、角色 ARN、资源 ID、内网地址、标签、endpoint 与 Request ID 未必能单独授权,却能帮助攻击者绘制资产和身份关系,也应按内部数据管理。
命令行直接传 Secret 会进入 shell history、进程列表、CI 日志和终端录屏。优先使用 SSO、实例角色、OIDC、委托或短期环境注入;配置文件仅作为开发机受控退路,限制文件 ACL,禁止同步到网盘,禁止进入镜像层。环境变量也不是保险箱,它们可能被子进程、崩溃报告和调试任务读取。CI 应通过云工作负载身份换取短期凭证,并让 secret masking 只承担最后一道保护。
--debug、set -x、PowerShell transcript、HTTP 代理抓包和 SDK wire log 都可能打印签名头、Token 或资源响应。调试前关闭 shell 回显,使用只读短会话,输出写入受控临时目录;结束后吊销会话并按保留策略删除。脱敏不能只替换 secret 字段,还要处理 URL 查询、Authorization、Cookie、账号与项目 ID、内网地址和对象签名 URL。
证据目录不进入 Git,不作为公开 CI artifact,不通过工单附件长期散发。需要共享时生成最小摘要:工具版本、脱敏主体、动作、地域项目、错误码、Request ID 和相对时间。原始 debug 日志由少数排障人员按需访问,并设置自动过期和下载审计。
API 容量和云资源费用要在脚本上线前估算
CLI 本身只是调用入口,费用来自被调用产品、创建的资源、日志与审计投递、对象存储、网络流量和 API 请求计量。只读查询通常不会创建计算实例,但某些数据面列表、日志检索、对象请求或跨公网下载可能计量;写命令可能立即创建按量资源、磁盘、快照、公网 IP、负载均衡与日志存储。价格、免费额度、可售区域和计费项会变化,执行前使用阿里云价格计算器、腾讯云定价中心和华为云价格计算器按目标账号、地域、规格和计费模式重新估算。
库存脚本的容量可以先用一个简单模型:
daily_api_calls = accounts × regions × products × pages × runs_per_day
daily_evidence = calls × average_summary_size + failures × average_debug_size
retained_storage = daily_evidence × retention_days × replica_factor若有 20 个账号、10 个地域、15 个产品、平均 8 页,每小时扫描一次,调用量已经不是“几条查询命令”。并发扫描会撞产品 API 限流,失败重试又会放大调用数和审计日志量。先按账号和地域分片,设置最大并发、分页上限、随机抖动和全局超时;只在清单变化时保存资源摘要,Request ID 与计数长期保留,原始响应短期保留。
资源成本模型至少包含计算时长、系统盘与数据盘、快照、对象容量、请求次数、日志写入与索引、外网出流量、跨地域复制、IP/带宽、备份和税费。停止实例不一定停止磁盘、快照和 IP 计费,删除实例也不一定删除所有依赖。给测试资源强制写 owner、environment、expires-at、cost-center 标签,按日生成“即将到期、无 owner、费用增长异常、清理失败”的清单,并把预算告警发给真正能处理的 owner。
成本优化不能变成无审查自动删除。预算超限先冻结新增写权限、通知 owner、生成依赖清单,再按批准策略停用和清理。对数据库、对象存储、密钥、快照和日志,恢复成本往往高于短期资源费,删除门槛应高于无状态计算实例。
长期治理让 profile 可退出、权限可收回、证据可复查
团队台账为每个云目标记录 provider、账号或 domain、profile 命名规则、身份来源、角色、允许 region/project、权限策略、资源 owner、成本中心、审批人、审计入口、凭证最长有效期、CLI 与插件基线、最后验证结果和退出日期。真实账号与项目映射放在受控配置系统,仓库只保留 schema 和占位示例。
profile 命名应表达提供商、环境、权限级别和身份方式,例如 PROFILE_TENCENT_STAGING_RO_SSO,不要只用 default、test、admin。生产 profile 不设为活动默认项,写权限 profile 不与只读 profile 共享名称;终端提示符可以显示当前 profile 与 region,但提示符只是提醒,脚本仍需远程身份断言。
版本升级先经过四类回归:版本和帮助可运行;隔离 HOME 不读取个人配置;无凭证按预期拒绝;测试账号只读身份、项目和资源查询返回可解析 JSON 与 Request ID。阿里云还要验证产品插件;TCCLI 要验证 Python 与 SDK 依赖;KooCLI 要验证隐私声明、在线元数据和 profile 加密格式。任何输出结构变化都先修解析器,再推广升级。
权限每个周期复核一次:删除无人使用的长期 AK,收紧可扮演角色列表,移除离职人员与过期 CI 身份,检查跨账号信任和项目授权,确认只读脚本没有获得写权限。用反向实验验证越权确实失败,而不是只看策略文本。审计服务要确认目标产品已接入、保留期满足调查需求、投递存储可读且自动过期;审计中断应告警,不能等事故后才发现没有记录。
项目下线时,先停止定时任务和写入入口,盘点并清理资源,验证费用停止增长,再撤销角色和工作负载身份,吊销 AK/SSO 会话,删除本地 profile、CI secret、缓存与受控证据副本,最后保留不含凭证的最小审计摘要。至此,开发者才能回答每一次 CLI 调用由谁发起、落在哪个账号地域项目、为何被允许、影响了什么、花费如何、怎样回滚,以及离场后还剩下什么。
