CSP Azure Offer 无法通过 API 获取月度账单信息
结论
这些错误并非来自同一个权限问题,而是混淆了三类边界:
- Azure 订阅所属的 Microsoft Entra Tenant;
- Azure RBAC 与 Billing RBAC;
- EA、CSP/MPA、MCA 等不同类型的 Billing Account。
CSP Azure Offer 即使挂在名为“Enterprise Account”的下级账户中,也不会因此变成 Enterprise Agreement(EA)计费账户。API 判断的是后台商业协议和 billingAccount 的实际类型,而不是门户中的显示名称或组织层级。
因此:
- 查询某个订阅的成本时,Access Token 必须由该订阅关联的 Tenant 签发,并且调用方需要在订阅范围获得成本读取权限。
Balances - Get By Billing Account、EA Enrollment 和 EA Billing Role Assignment 相关接口,只适用于其明确支持的 EA 计费范围,不能直接用于 CSP/MPA 账户。- 如果要查询 CSP 客户订阅的 Azure 使用成本,可优先使用 Azure Cost Management Query,在订阅范围发起查询。
- 如果要查询合作伙伴收到的月度账单、发票总额、税费、信用额度或 reconciliation 明细,通常应使用 Partner Center 对应的 Billing/Reconciliation API,而不是将 Azure Consumption 的 EA 接口当作 CSP 发票接口。
三个错误分别表示什么
InvalidAuthenticationTokenTenant
错误信息已经说明了原因:
The access token is from the wrong issuer
'https://sts.windows.net/AAAAA/'.
It must match the tenant
'https://sts.windows.net/AAAAAA/'
associated with this subscription.
当前 Token 由 Tenant AAAAA 签发,而被查询的 Azure Subscription 关联到 Tenant AAAAAA。Azure Resource Manager 会校验 Token 的 iss 或 tid,Billing Owner 身份无法绕过这项校验。
需要使用错误信息指定的 Tenant 获取 Token:
https://login.microsoftonline.com/AAAAAA/oauth2/v2.0/token
Token 的资源范围应为 Azure Resource Manager:
https://management.azure.com/.default
例如,使用客户端凭据获取 Token:
curl -X POST \
"https://login.microsoftonline.com/AAAAAA/oauth2/v2.0/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "client_id={client-id}" \
--data-urlencode "client_secret={client-secret}" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "scope=https://management.azure.com/.default"
这里的 AAAAAA 必须是订阅实际所属的 Tenant ID,不能使用合作伙伴主 Tenant、登录时默认选择的 Tenant,也不能使用某个上级账户所在的 Tenant。
可以检查 Token 中的 tid 和 iss,再与错误信息要求的 Tenant 对照。如果订阅刚刚发生 Tenant 转移,还需等待后台信息同步。
No billing period information found for the specified Enrollments
请求中的 Billing Account 被解释为:
Enrollments:XXXX:YYYYYY
这表示当前调用采用了 EA Enrollment 计费模型,但服务未在该 Enrollment 下找到适用的 Billing Period。常见原因有:
- 该账户实际不是 EA Enrollment;
- 使用了门户显示编号,而不是 API 返回的 Billing Account ID;
- 混用了 Enrollment、Department、Account、Subscription 等范围;
- 当前身份没有该 EA Enrollment 的计费访问权限;
- 将 CSP 账户误当成 EA Billing Account;
- 查询周期不属于该 Enrollment,或该范围内没有可返回的账期数据。
对于 CSP Azure Offer,不能根据“Enterprise Account 是 CSP Account 的子账户”就认定它属于 EA。应先读取 Billing Account 元数据,确认其协议类型。
例如:
GET https://management.azure.com/providers/Microsoft.Billing/billingAccounts?api-version={supported-api-version}
Authorization: Bearer {access-token}
判断时应查看响应中的 agreementType、accountType 或对应属性。具体字段会随 Billing API 版本和协议类型变化,应以所选 API 版本的响应模型为准。
如果返回的是 Microsoft Partner Agreement、Microsoft Customer Agreement 或其他非 EA 类型,就不能通过 Enrollments:... 形式的 EA 范围调用该接口。
PUT operation is currently supported only on EA billing accounts
这个错误表示,该 PUT 操作只支持在 EA Billing Account 上分配角色,而当前 URL 指向的 Billing Account 并非 EA。
增加一个 Billing Owner 权限不能解决这个问题。即使当前用户在门户中显示为 Billing Owner,也不能在 CSP/MPA Billing Account 上调用仅支持 EA 的 Billing Role Assignment API。
应先识别账户类型,再使用该协议对应的授权方式:
| 查询范围 | 常用权限体系 |
|---|---|
| Azure Subscription | Azure RBAC |
| Resource Group | Azure RBAC |
| EA Enrollment/Billing Account | EA Billing RBAC |
| MCA Billing Account/Profile/Invoice Section | MCA Billing RBAC |
| CSP/MPA 合作伙伴计费 | Partner Center 权限及对应 API |
| CSP 客户的 Azure Subscription 成本 | 客户 Tenant 身份、委派访问和 Azure RBAC |
Azure RBAC 和 Billing RBAC 是两套不同的权限体系。拥有 Billing Owner 并不代表拥有订阅资源范围的 Microsoft.CostManagement/query/action 权限。同样,拥有 Subscription Owner 也不一定能够读取合作伙伴级发票。
推荐的解决路径
1. 确认订阅所属 Tenant
先确认目标 Subscription 的 Tenant ID。后续所有订阅范围的 Cost Management 请求,都应使用该 Tenant 签发的 Token。
服务主体也必须存在于该 Tenant 中。在 CSP 场景下,可以通过以下方式实现:
- 在客户 Tenant 中创建服务主体;
- 通过合作伙伴委派关系访问客户 Tenant;
- 使用符合当前 CSP 管理模型的 GDAP 等委派机制。
只在合作伙伴 Tenant 中创建应用注册,并不意味着该服务主体自动拥有客户订阅的访问权限。
2. 在订阅范围授予 Azure RBAC 权限
如果只需读取成本,可以在目标订阅上授予以下内置角色:
Cost Management Reader
根据具体 API 和资源查询要求,也可能需要:
Reader
角色分配范围示例:
/subscriptions/{subscription-id}
授权对象应当是实际用于获取 Token 的用户或服务主体。
客户是否开启成本可见性、合作伙伴的计价策略以及 CSP Offer 本身的限制,也可能影响可见数据。Azure Cost Management 返回的成本视图不一定与合作伙伴最终发票金额相同。
3. 在订阅范围调用 Cost Management Query
查询月度实际成本时,可以使用订阅 Scope:
POST https://management.azure.com/subscriptions/{subscription-id}/providers/Microsoft.CostManagement/query?api-version={supported-api-version}
Authorization: Bearer {access-token}
Content-Type: application/json
请求体示例:
{
"type": "ActualCost",
"timeframe": "Custom",
"timePeriod": {
"from": "2026-08-01T00:00:00Z",
"to": "2026-08-31T23:59:59Z"
},
"dataset": {
"granularity": "Monthly",
"aggregation": {
"totalCost": {
"name": "PreTaxCost",
"function": "Sum"
}
}
}
}
完整调用示例:
curl -X POST \
"https://management.azure.com/subscriptions/{subscription-id}/providers/Microsoft.CostManagement/query?api-version={supported-api-version}" \
-H "Authorization: Bearer {access-token}" \
-H "Content-Type: application/json" \
-d '{
"type": "ActualCost",
"timeframe": "Custom",
"timePeriod": {
"from": "2026-08-01T00:00:00Z",
"to": "2026-08-31T23:59:59Z"
},
"dataset": {
"granularity": "Monthly",
"aggregation": {
"totalCost": {
"name": "PreTaxCost",
"function": "Sum"
}
}
}
}'
api-version 应选择 Cost Management Query 文档当前列出的受支持版本,不要直接照搬其他 Billing 或 Consumption API 的版本。
如果仍然返回 401 或 403,请按顺序检查:
- Token 的
tid是否与订阅 Tenant ID 相同; - Token 的 audience 是否为
https://management.azure.com/; - URL 中的 Subscription ID 是否正确;
- 用户或服务主体是否在订阅范围拥有 Cost Management 读取权限;
- CSP 客户的成本可见性是否已经开启;
- 新分配的角色是否已经完成传播。
4. 不要用 EA Balances API 查询 CSP 月度发票
Balances - Get By Billing Account 只面向特定的 Billing Account 模型,其返回结果也不等同于所有协议类型下的“每月费用”。Balance、Usage Cost、Invoice 和 Reconciliation 是不同的数据对象。
应根据所需数据选择接口:
- Azure 资源消耗成本:使用 Cost Management Query 或适用的 Usage Details API;
- 合作伙伴向客户提供的费用视图:使用 CSP 支持的成本管理范围,并确认成本可见性;
- 微软向 CSP 合作伙伴出具的发票、税费、抵扣和月度 reconciliation:使用 Partner Center 的 Billing/Reconciliation 能力;
- EA Enrollment 的余额或账期:确认 Billing Account 确实属于 EA 后,再使用 EA Consumption/Billing API。
关于 Billing Account 类型
配置权限前,应先查明实际协议:
EA → Enterprise Agreement
MCA → Microsoft Customer Agreement
MPA → Microsoft Partner Agreement
CSP → 合作伙伴销售和管理关系;其后台计费通常不能按 EA Enrollment 处理
门户中显示“Enterprise Account”“Billing Owner”或类似名称,并不能证明协议是 EA。尤其在 CSP 场景中,组织结构中的父子关系与 Azure Billing API 的协议模型并不是一回事。
如果在 Billing Accounts 列表中找不到预期账户,也不能直接判断该账户不存在。另一种可能是,当前身份没有该计费范围的读取权限。此时应请组织的计费管理员或 CSP 管理员确认实际协议、Billing Account ID 和可用角色。
Cost Management 数据与月度账单的差异
Cost Management Query 返回的是成本管理数据,可能受到以下因素影响:
- 数据刷新延迟;
- 未结算用量;
- 预留实例和 Savings Plan 分摊;
- Marketplace 项目;
- Credits、Refunds 和 Adjustments;
- 税费;
- CSP 合作伙伴加价或折扣;
- Billing Currency 与 Pricing Currency;
- 实际成本与摊销成本的选择。
因此,不能默认将 Cost Management 的汇总值视为最终发票应付金额。进行财务对账时,应分别获取 Cost Management 的使用成本和 Partner Center 的 Invoice/Reconciliation 数据,再按照 Subscription ID、Charge Type、Billing Period 和 Currency 等字段核对。
处理顺序可以归纳为:先使用目标订阅所属的 Tenant 获取 Token,在订阅范围配置 Azure RBAC,然后通过 Cost Management Query 查询月度成本。只有通过 API 元数据确认账户属于 EA 后,才能使用 EA Enrollment、Balances 和仅支持 EA 的 Billing Role Assignment 操作。CSP 的正式月度发票和 reconciliation 数据应通过 Partner Center 对应接口获取。
备注:内容仅供参考。
