terraform-provider-aws 数据源解析:aws_billing_service_account 与 AWS 账单服务账号权限配置
2026/9/17 21:25:18 网站建设 项目流程

terraform-provider-aws 数据源解析:aws_billing_service_account 与 AWS 账单服务账号权限配置

【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws

本指南以 terraform-provider-aws 中aws_billing_service_account数据源为主题,讲解如何通过该数据源获取 AWS Billing and Cost Management 服务账号的 Account ID 与 ARN,并将其用于 S3 存储桶策略,以授权 AWS 写入计费日志。阅读完成后,你将掌握该数据源的使用方法、无参数调用的设计原理,以及它在 S3 计费日志归档场景中的完整落地配置。

数据源是什么:一个无需 AWS API 调用的静态账号查询

aws_billing_service_account是 terraform-provider-aws 提供的一个特殊数据源:它不向任何 AWS API 发起请求,也不依赖任何参数,而是直接返回 AWS 官方公布的 Billing and Cost Management 服务账号信息。

在 AWS 的计费架构中,当你为 S3 存储桶开启计费日志(Billing Reports / Cost & Usage Report)写入时,写日志的"服务账号"是一个 AWS 官方维护的固定账号,而非你的个人账号。要在 S3 存储桶策略中授权该账号写入,就需要在策略的Principal中引用这个固定账号的 ARN。该数据源存在的意义,就是避免你在 Terraform 配置中硬编码这一串官方账号 ID。

根据官方文档,其核心用途描述为:

使用此数据源获取 AWS Billing and Cost Management 服务账号的 Account ID,用于在 S3 存储桶策略中放行该账号。

对应文档:website/docs/d/billing_service_account.html.markdown。

示例用法:为 S3 计费日志桶授权 AWS 账单服务账号

以下是官方文档给出的完整示例,它展示了从创建存储桶、设置 ACL,到用aws_iam_policy_document构造桶策略、再挂载策略的完整链路:

data "aws_billing_service_account" "main" {} resource "aws_s3_bucket" "billing_logs" { bucket = "my-billing-tf-test-bucket" } resource "aws_s3_bucket_acl" "billing_logs_acl" { bucket = aws_s3_bucket.billing_logs.id acl = "private" } data "aws_iam_policy_document" "allow_billing_logging" { statement { effect = "Allow" principals { type = "AWS" identifiers = [data.aws_billing_service_account.main.arn] } actions = [ "s3:GetBucketAcl", "s3:GetBucketPolicy", ] resources = [aws_s3_bucket.billing_logs.arn] } statement { effect = "Allow" principals { type = "AWS" identifiers = [data.aws_billing_service_account.main.arn] } actions = ["s3:PutObject"] resources = ["${aws_s3_bucket.billing_logs.arn}/*"] } } resource "aws_s3_bucket_policy" "allow_billing_logging" { bucket = aws_s3_bucket.billing_logs.id policy = data.aws_iam_policy_document.allow_billing_logging.json }

这段配置中有两个值得注意的细节:

  • 第一个 statement:授权账单服务账号对存储桶本身执行s3:GetBucketAcls3:GetBucketPolicy,这是 AWS 写日志前读取桶配置所必需的最小权限;
  • 第二个 statement:授权s3:PutObject写入桶内的对象,资源为arn/*(桶下所有对象),这是实际写入计费日志对象所需的权限。

两条语句的Principal都引用了data.aws_billing_service_account.main.arn,从而避免了硬编码官方账号 ARN。

Argument Reference:零参数设计

该数据源不支持任何参数

This data source does not support any arguments.

这与它的实现方式直接相关。查看源码 internal/service/billing/billing_service_account_data_source.go,其 Schema 中仅定义了两个计算属性(Computed: true),没有Optional的入参:

response.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ names.AttrARN: schema.StringAttribute{ Computed: true, }, names.AttrID: schema.StringAttribute{ Optional: true, Computed: true, }, }, }

声明数据源时甚至不需要写data "aws_billing_service_account" "main" {}之外的任何配置块。

Attribute Reference:id 与 arn

数据源导出以下属性:

属性说明
idAWS 账单服务账号的 Account ID
arnAWS 账单服务账号的 ARN

在源码实现中,这两个值的来源非常清晰。Read方法内直接硬编码了官方服务账号 ID,并通过全局 ARN 构造方法生成 ARN:

// See http://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/billing-getting-started.html#step-2 const serviceAccountID = "386209384616" data.ARN = fwflex.StringValueToFrameworkLegacy(ctx, d.Meta().GlobalARNWithAccount(ctx, "iam", serviceAccountID, "root")) data.ID = fwflex.StringValueToFrameworkLegacy(ctx, serviceAccountID)

也就是说:

  • id固定返回386209384616
  • arnGlobalARNWithAccount构造,服务名为iam、账号 ID 为386209384616、资源为root,得到形如arn:aws:iam::386209384616:root的全局 ARN。

GlobalARNWithAccount定义在 internal/conns/awsclient.go,其底层通过arn.ARN结构体拼接出无 Region、指定账号 ID的 ARN:

// GlobalARNWithAccount returns a global (no Region) ARN for the specified service namespace, resource and account ID. func (c *AWSClient) GlobalARNWithAccount(ctx context.Context, service, accountID, resource string) string { return c.arn(ctx, service, "", accountID, resource) }

arn方法则负责填充 Partition、Service、Region、AccountID、Resource 五个字段并调用.String()序列化(见 internal/conns/awsclient.go)。因此该 ARN 会随 Provider 配置的分区(如awsaws-cnaws-us-gov)自动适配,这也是它比硬编码字符串更健壮的原因之一。

源码层面的实现细节

基于 Terraform Plugin Framework 实现

从源码结构看,该数据源是基于terraform-plugin-framework实现的新一代数据源。文件头部的生成器注释与注册逻辑可以佐证:

// @FrameworkDataSource("aws_billing_service_account", name="Service Account") func newServiceAccountDataSource(context.Context) (datasource.DataSourceWithConfigure, error) { d := &billingServiceAccountDataSource{} return d, nil }

其注册信息位于 internal/service/billing/service_package_gen.go,注意其中Region: inttypes.ResourceRegionDisabled()的标记——这表示该数据源与 Region 无关(全局资源),因为账单服务账号在全球范围内是同一个固定账号,不随调用 Region 变化。

不发起任何 AWS API 调用

Read方法内没有创建任何 AWS 服务客户端,也没有调用List*/Get*之类的 API,而是直接向 State 写入常量值。这也是文档中"零参数、无 API 依赖"设计的直接体现。与同包内需要调用 Billing API 的aws_billing_views数据源(见 internal/service/billing/views_data_source.go 中d.Meta().BillingClient(ctx)的用法)相比,aws_billing_service_account是一个纯本地计算的数据源,运行时不会产生任何计费或网络开销。

测试用例对输出的约束

该数据源的行为由接受测试严格锁定。测试文件 internal/service/billing/billing_service_account_data_source_test.go 中:

func TestAccBillingServiceAccountDataSource_basic(t *testing.T) { ctx := acctest.Context(t) dataSourceName := "data.aws_billing_service_account.test" billingAccountID := "386209384616" ... Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(dataSourceName, names.AttrID, billingAccountID), acctest.CheckResourceAttrGlobalARNAccountID(dataSourceName, names.AttrARN, billingAccountID, "iam", "root"), ), ... }

测试明确断言:

  1. id必须等于386209384616
  2. arn必须是一个全局(无 Region)、账号 ID 为386209384616、服务为iam、资源为root的 ARN,即arn:aws:iam::386209384616:root

这为文章开头的结论提供了可验证的依据:如果你在配置中看到data.aws_billing_service_account.main.arn,它解析出来的就是 AWS 官方账单服务账号的 IAM root ARN。

实际使用注意事项

  1. 只能用于放行 AWS 账单服务:该账号是 AWS 官方用于写计费日志的专用账号,不能把它当作自己的 AWS 账号使用,也不要试图用它做资源授权以外的操作。
  2. 配合aws_iam_policy_document使用更佳:示例中先构造aws_iam_policy_document再通过aws_s3_bucket_policy挂载,避免手写 JSON 策略字符串,也便于把arn作为变量直接引用。
  3. 权限最小化:官方示例给出了读桶属性(s3:GetBucketAcls3:GetBucketPolicy)与写对象(s3:PutObject)两组权限,实际生产环境建议仅开启确实需要的动作。
  4. 无需 provider 的 AWS 凭证也能 plan:由于该数据源不调用 API,即使本地凭证权限有限,terraform plan阶段也能正常解析出arnid

总结

aws_billing_service_account是 terraform-provider-aws 中一个"小而精"的全局数据源:零参数、零 API 调用,通过 internal/service/billing/billing_service_account_data_source.go 中硬编码的官方账号 ID386209384616与全局 ARN 构造逻辑,稳定输出idarn两个属性,专门服务于 S3 计费日志桶的策略授权场景。理解它的实现方式,也有助于举一反三:凡是这类"官方固定账号/固定标识"的查询需求,都可以参考此模式,用常量输出 + 全局 ARN 构造的方式在 Provider 中实现,从而避免用户在配置中硬编码魔法数字。

【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询