Skip to main content

Configuring Cost Reporting with Terraform

The following terraform will create a s3 bucket and configure cost reporting for the account.

Creates the following resources:

  • s3 bucket for storage of billing logs
  • s3 bucket policy to allow billing service to write logs
  • iam role and policy to allow external AWS service (CloudCtrl) to read from s3 bucket
  • cost reporting definition
main.tf

locals {
prefix = "aws-cost-reporting"

tags = {
Environment = "dev"
Customer = "acme corp"
}
}

data "aws_caller_identity" "current" {}
data "aws_billing_service_account" "main" {}

resource "aws_s3_bucket" "cloudctrl" {
bucket = "${local.prefix}-cloudctrl"

tags = local.tags
}

data "aws_iam_policy_document" "billing" {
statement {
effect = "Allow"

principals {
type = "AWS"
identifiers = [data.aws_billing_service_account.main.arn]
}

actions = [
"s3:GetBucketAcl",
"s3:GetBucketPolicy",
]

resources = [aws_s3_bucket.cloudctrl.arn]
}

statement {
effect = "Allow"

principals {
type = "AWS"
identifiers = [data.aws_billing_service_account.main.arn]
}

actions = ["s3:PutObject"]
resources = ["${aws_s3_bucket.cloudctrl.arn}/*"]
}
}

resource "aws_s3_bucket_policy" "billing" {
bucket = aws_s3_bucket.cloudctrl.id
policy = data.aws_iam_policy_document.billing.json
}

resource "aws_iam_policy" "cloudctrl" {
name = "${local.prefix}-cloudctrl"
description = "Policy for cloudctrl user"

policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Action = [
"s3:GetObject",
"s3:ListBucket",
"s3:GetObjectAttributes",
"s3:GetBucketLocation"
],
Resource = [
"${aws_s3_bucket.cloudctrl.arn}",
"${aws_s3_bucket.cloudctrl.arn}/*"
]
},
{
Effect = "Allow",
Action = [
"ec2:DescribeInstances",
"s3:ListAllMyBuckets",
"compute-optimizer:GetEC2InstanceRecommendations",
"compute-optimizer:GetEnrollmentStatus",
"cloudwatch:GetMetricStatistics"
],
Resource = "*"
}
]
})

tags = local.tags
}

resource "aws_iam_role" "cloudctrl" {
name = "${local.prefix}-cloudctrl"

assume_role_policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Action = "sts:AssumeRole",
Effect = "Allow",
Principal = {
AWS = "arn:aws:iam::058552127514:root"
},
Condition = {
StringEquals = {
"sts:ExternalId" = data.aws_caller_identity.current.account_id
}
}
},
]
})

tags = local.tags
}

resource "aws_iam_role_policy_attachment" "cloudctrl" {
role = aws_iam_role.cloudctrl.name
policy_arn = aws_iam_policy.cloudctrl.arn
}

# resource "aws_ce_cost_allocation_tag" "environment" {
# tag_key = "Environment"
# status = "Active"
# }

# resource "aws_ce_cost_allocation_tag" "customer" {
# tag_key = "Customer"
# status = "Active"
# }

resource "aws_cur_report_definition" "cloudctrl" {
provider = aws.virginia

report_name = "${local.prefix}-cloudctrl"
s3_prefix = "cloudctrl"
time_unit = "HOURLY"
format = "textORcsv"
compression = "ZIP"
additional_schema_elements = ["RESOURCES", "SPLIT_COST_ALLOCATION_DATA"]
report_versioning = "OVERWRITE_REPORT"
s3_bucket = aws_s3_bucket.cloudctrl.bucket
s3_region = aws_s3_bucket.cloudctrl.region
}