Azure Invoices - List By Billing Subscription 请求为何返回 404?
结论
这个 404 通常不是普通的 Azure RBAC 权限问题。更可能的原因是请求路径中的资源标识有误,或者当前计费账户类型不支持该接口。
需要检查以下几点:
billingSubscriptionName不是 Azure Subscription 的名称,通常也不是 Azure Subscription GUID。它应当是 Microsoft Billing 资源中 billing subscription 的name。billingAccountName必须使用 Billing API 返回的资源名称,不能使用门户中的账户显示名称,也不能使用未经确认的属性值。- 示例中的日期参数顺序有误:
periodStartDate=2022-06-30晚于periodEndDate=2022-06-01。 Invoices - List By Billing Subscription只适用于该 API 支持的计费协议类型。个人订阅、传统 Pay-As-You-Go 和部分 Enterprise Agreement 账户,即使订阅 Owner 拥有者权限,也未必能调用这个路径。- Azure Subscription 的 Owner 与计费范围中的 Billing Reader 属于两套不同的授权体系。计费权限必须授予到请求所指向的 billing account 或相应计费范围。
正确获取资源名称
不要根据门户中的显示名称拼接 URL。先通过 Billing API 列出当前用户可以访问的计费账户:
GET https://management.azure.com/providers/Microsoft.Billing/billingAccounts?api-version=2019-10-01-preview
Authorization: Bearer <access-token>
从响应中读取计费账户资源的 name:
{
"value": [
{
"id": "/providers/Microsoft.Billing/billingAccounts/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"name": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"type": "Microsoft.Billing/billingAccounts"
}
]
}
这里的 name 才是请求中的 billingAccountName。某些计费协议下的名称可能包含多个部分或特殊字符,应原样使用,并在构造 URL 时进行必要的 URL 编码。
接着列出该账户下的 billing subscriptions:
GET https://management.azure.com/providers/Microsoft.Billing/billingAccounts/{billingAccountName}/billingSubscriptions?api-version=2019-10-01-preview
Authorization: Bearer <access-token>
假设响应如下:
{
"value": [
{
"id": "/providers/Microsoft.Billing/billingAccounts/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/billingSubscriptions/yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"name": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"type": "Microsoft.Billing/billingAccounts/billingSubscriptions",
"properties": {
"displayName": "Production Subscription"
}
}
]
}
此时应使用顶层的:
name = yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
作为 billingSubscriptionName,不要使用:
properties.displayName
也不要直接认定它等于门户中的 Azure Subscription ID。即使这两个值在某种账户类型下恰好相同,仍应以 Billing API 返回的 name 为准。
修正日期参数
原请求中的日期顺序为:
periodEndDate=2022-06-01
periodStartDate=2022-06-30
开始日期晚于结束日期,应改为:
periodStartDate=2022-06-01
periodEndDate=2022-06-30
完整请求示例:
GET https://management.azure.com/providers/Microsoft.Billing/billingAccounts/{billingAccountName}/billingSubscriptions/{billingSubscriptionName}/invoices?api-version=2019-10-01-preview&periodStartDate=2022-06-01&periodEndDate=2022-06-30
Authorization: Bearer <access-token>
日期必须采用 YYYY-MM-DD 格式,并满足:
periodStartDate <= periodEndDate
查询区间还应覆盖已经产生发票的账期。如果日期正确,但区间内没有发票,正常结果通常是空集合。具体响应仍取决于账户类型和该预览版 API 的实现。
为什么 Owner 或 Billing Reader 仍可能返回 404
Azure Subscription Owner 主要控制订阅资源,例如虚拟机、网络和存储,不会自动获得计费账户数据的访问权限。
Billing Reader 也必须授予在正确的计费范围上。例如,请求路径访问的是:
/providers/Microsoft.Billing/billingAccounts/{billingAccountName}
调用者就必须能够访问这个 billing account 及其对应的 billing subscription。最直接的验证方法不是查看角色名称,而是执行前面的两个列表请求:
- 如果无法列出目标 billing account,说明登录租户、账户关系或计费权限不匹配。
- 如果能列出 billing account,却无法列出目标 billing subscription,可能是该资源不属于这个账户、使用了错误的标识,或者授权范围不足。
- 如果两者都能列出,就把响应中的
name原样填入发票请求。
部分 Azure Billing API 会在计费资源不存在或调用者不可见时返回 404,而不是明确的 403。因此,不能简单地把 404 理解为 URL 本身不存在。
检查计费协议类型
该路径不适用于所有 Azure 订阅。需要检查 billing account 响应中的协议类型,例如:
{
"properties": {
"agreementType": "MicrosoftCustomerAgreement"
}
}
Invoices - List By Billing Subscription 主要用于具有 billing subscription 层级的计费模型,例如 Microsoft Customer Agreement。具体支持范围应以所用 API 版本的官方说明为准。
如果账户采用其他协议,例如传统个人订阅或某些 Enterprise Agreement 结构,其资源层级可能是 enrollment account、billing profile 或 invoice section,而不是该接口要求的 billing subscription。这种情况下,不能只替换一个 ID 继续调用该接口,而应改用与实际计费协议和资源层级对应的 Invoices API。
建议的排查顺序
- 确认访问令牌所属 tenant 与计费账户所在 tenant 一致。
- 调用
billingAccounts列表接口,复制响应中的name。 - 调用该账户的
billingSubscriptions列表接口,复制目标对象的name。 - 检查 billing account 的
agreementType是否支持该操作。 - 确认 Billing Reader 等计费角色授予在正确的计费范围,而不只是在 Azure Subscription 上。
- 将日期调整为开始日期早于或等于结束日期。
- 使用已经确认的两个
name重新构造请求。不要使用门户显示名称,也不要自行认定 Azure Subscription ID 就是billingSubscriptionName。
这个请求至少有一个明确问题,即日期顺序错误。至于 404,更常见的原因是把 Azure Subscription ID 当成了 billingSubscriptionName,或者计费账户并不支持该接口要求的资源层级。
备注:内容仅供参考。
