Skip to content

IAmFrench/terraform-azurerm-billing-export

Repository files navigation

Microsoft Azure Billing export Terraform Module

Terraform module witch creates billing export on Azure.

FOCUS v1.0 billing export for Azure now available!

This module will create a storage account for Azure billing exports.

What is FOCUS™?

The FinOps Cost and Usage Specification (FOCUS™) is an open-source specification that defines clear requirements for cloud vendors to produce consistent cost and usage datasets.

Supported by the FinOps Foundation, FOCUS™ aims to reduce complexity for FinOps Practitioners so they can drive data-driven decision-making and maximize the business value of cloud, while making their skills more transferable across clouds, tools, and organizations.

Learn more about FOCUS in this FinOps Foundation Insights article.

Usage

Detailed examples are available under the ./examples directory.

Create a FOCUS export for a billing account with a new resource group, storage account and container
module "azurerm_billing_export" {
  source = "IAmFrench/billing-export/azurerm"

  version = "<version>" # change this to your desired version, https://www.terraform.io/language/expressions/version-constraints

  create_resource_group   = true
  resource_group_name     = "rg-focus-export-001"
  resource_group_location = "Switzerland North"

  create_storage_account = true
  storage_account_name   = "billingexportokjdlksa"

  create_storage_container = true
  storage_container_name   = "focus"

  export_type    = "FOCUS"
  export_version = "1.0r2"

  export_scope_and_id = {
    scope = "billing-account"
    id    = "123456789"
  }

  export_start_date    = local.export_start_date
  export_creation_date = "2024-10-16"
  export_end_date      = "2050-01-01"

  enable_backfill = true

  export_directory = "billing_account_123456789"

  export_name = "focus-export-for-billing-account-123456789"
}
Create a FOCUS export for a billing account with an existing resource group, storage account and container
module "azurerm_billing_export" {
  source = "IAmFrench/billing-export/azurerm"

  version = "<version>" # change this to your desired version, https://www.terraform.io/language/expressions/version-constraints

  create_resource_group   = false
  resource_group_name     = "rg-focus-export-001"
  resource_group_location = "Switzerland North"

  create_storage_account = false
  storage_account_name   = "billingexportokjdlksa"

  create_storage_container = false
  storage_container_name   = "focus"

  export_type    = "FOCUS"
  export_version = "1.0r2"

  export_scope_and_id = {
    scope = "billing-account"
    id    = "123456789"
  }

  export_start_date    = local.export_start_date
  export_creation_date = "2024-10-16"
  export_end_date      = "2050-01-01"

  enable_backfill = true

  export_directory = "billing_account_123456789"

  export_name = "focus-export-for-billing-account-123456789"
}
Create a FOCUS export for a subcription with a existing resource group but new storage account and container
module "azurerm_billing_export" {
  source = "IAmFrench/billing-export/azurerm"

  version = "<version>" # change this to your desired version, https://www.terraform.io/language/expressions/version-constraints

  create_resource_group   = false
  resource_group_name     = "rg-focus-export-001"
  resource_group_location = "Switzerland North"

  create_storage_account = true
  storage_account_name   = "billingexportzfcxfd"

  create_storage_container = true
  storage_container_name   = "focus"

  export_type    = "FOCUS"
  export_version = "1.0r2"

  export_scope_and_id = {
    scope = "subscription"
    id    = "12345-uuid-6789"
  }

  export_start_date    = local.export_start_date
  export_creation_date = "2024-10-16"
  export_end_date      = "2050-01-01"

  enable_backfill = true

  export_directory = "subscription_12345-uuid-6789"

  export_name = "focus-export-for-subscription-12345-uuid-6789"
}

Roadmap & Features

  • FOCUS 1.0 & 1.0r2 export (Improved export experience)
  • Subscription export (export_scope_and_id = subscription)
  • Billing Account export (export_scope_and_id = billing-account)
  • Automatic backfill from export_start_date to export's creation date (export_creation_date)
  • Retry implementation (if we hit the rate limit 429 Too Many Requests)

Limitations

  • Id of backfill jobs is not returned by the microsoft API on job submission, therefore returned id is incorrect

Common errors

FocusCost is not supported

FocusCost is not supported
╷
│ Error: Failed to create/update resource
│
│   with module.azurerm_billing_export.azapi_resource.focus_export[0],
│   on ../../main.tf line 100, in resource "azapi_resource" "focus_export":
│  100: resource "azapi_resource" "focus_export" {
│
│ creating/updating Resource: (ResourceId
│ "/subscriptions/xxxx-xxxx-xxxx-xxxx/providers/Microsoft.CostManagement/exports/focus-export-for-subscription-xxxx-xxxx-xxxx-xxxx"
│ / Api Version "2023-07-01-preview"): PUT
│ https://management.azure.com/subscriptions/xxxx-xxxx-xxxx-xxxx/providers/Microsoft.CostManagement/exports/focus-export-for-subscription-xxxx-xxxx-xxxx-xxxx
│ --------------------------------------------------------------------------------
│ RESPONSE 400: 400 Bad Request
│ ERROR CODE: BadRequest
│ --------------------------------------------------------------------------------
│ {
│   "error": {
│     "code": "BadRequest",
│     "message": "Request properties validation failed: Export type: FocusCost is not supported for Agreement Type: WebDirect and Subscription."
│   }
│ }
│ --------------------------------------------------------------------------------
│
╵

Check if your subscription type is supported here: https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/tutorial-improved-exports#understand-data-types

Requirements

Name Version
terraform >= 1.1.0
azapi >= 2.0.0-beta, < 3.0
azurerm >= 3.113.0, < 5.0
time >= 0.12.1, < 1.0.0

Providers

Name Version
azapi >= 2.0.0-beta, < 3.0
azurerm >= 3.113.0, < 5.0
time >= 0.12.1, < 1.0.0

Modules

Name Source Version
months_to_backfill ./modules/months_to_backfill n/a

Resources

Name Type
azapi_resource.focus_export resource
azapi_resource_action.backfill_job resource
azurerm_resource_group.main resource
azurerm_storage_account.export resource
azurerm_storage_container.focus resource
time_static.export_creation_date resource
azurerm_resource_group.main data source
azurerm_storage_account.export data source
azurerm_storage_container.focus data source

Inputs

Name Description Type Default Required
create_resource_group Option to create or not the Resource Group for the billing export.

If set to false, this module will not create the resource group and will
instead lookup for a resource group with the name var.resource_group_name.

E.g.: true, false
bool false no
create_storage_account Option to create or not the storage account for the billing export.

If set to false, this module will not create the storage account.

E.g.: true, false
bool true no
create_storage_container Option to create or not the Storage Container for the billing export.

If set to false, this module will not create the storage Container and will
instead lookup for a storage container with var.storage_container_name in
the var.storage_account_name Storage Account.

Note: If var.create_storage_account is set to true, then this variable
MUST be set to true.

E.g.: true, false
bool true no
enable_backfill Option to enable or not a backfill for the export.

E.g.: true, false
bool false no
export_creation_date Creation date of the export.

E.g.: 2024-07-22
string n/a yes
export_directory Directory to place the billing export in.

Validation: Directory name cannot end with a forward slash(/) or dot(.)

E.g.: subscription_63aa77b3-5e14-4c6d-a895-27f9d8443e37 with
63aa77b3-5e14-4c6d-a895-27f9d8443e37 being the subscription id
string n/a yes
export_end_date End date of the export.

Validation: Date should be in the future and it must be the first day of the month.

E.g.: 2050-01-01
string "2050-01-01" no
export_name Name of the billing export.

Validation: Export name must be alphanumeric, without whitespace, and 3 to
64 characters in length.

E.g.: focus-export-for-sub-63aa77b3-5e14-4c6d-a895-27f9d8443e37 (57
characters)
string n/a yes
export_scope_and_id Scope and the corresponding id for the billing export.

Valid values for scope are:
- billing-account for an export at the billing account level (recommended)
- subscription for an export at the subscription level

E.g.:
{
scope = "billing-account"
id = "1234567890"
}
object({
scope = string
id = string
})
n/a yes
export_start_date Start date of the export.
You can go as far as 9 years in the past.

Validation: Date should be in the past and it must be the first day of the month.

E.g.: 2024-01-01
string "2020-01-01" no
export_type Version of the billing export.

Valid values:
- FOCUS for Cost and usage details (FOCUS),
- AMORTIZED for Cost and usage details (amortized),
- ACTUAL for Cost and usage details (usage only)

Learn more about export types: https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/tutorial-improved-exports#schedule-frequency

E.g.: FOCUS, AMORTIZED or ACTUAL
string n/a yes
export_version Version of the billing export. Should be use with export_type.

Valid values are:
- 1.0r2 & 1.0 for FOCUS
- 2023-12-01-preview for Cost and usage details (EA, MCA, MPA and CSP)
- 2019-11-01 for Cost and usage details (MOSA)

E.g.: 1.0r2, 1.0, 2023-12-01-preview, 2019-11-01
string n/a yes
resource_group_location Location of the Storage Account.

Note: if var.create_resource_group is set to true, then this variable MUST
be set.

E.g.: Switzerland North
string null no
resource_group_name Name of the resource group where the Storage account is located in.

E.g.: rg-finops-export-001
string n/a yes
storage_account_location Location of the Storage Account.

If null, the Storage Account will be created in the location linked to the resource group.

E.g.: Switzerland North
string null no
storage_account_name Name of the Storage Account.

The Storage Account will be created with this name if var.create_storage_account is true.

E.g.: billingexports
string n/a yes
storage_container_name Name of the Storage Container.

The Storage Container will be created with this name if var.create_storage_container is true.

E.g.: focus-v1.0
string n/a yes
tags Tags to apply to all created resources.

E.g.:
{
createdBy = "Terraform"
}
map(string)
{
"createdBy": "Terraform"
}
no

Outputs

Name Description
backfill_job_id List of Ids of backfill jobs.

E.g.:
[
"/providers/Microsoft.Billing/billingAccounts/123456789/providers/Microsoft.CostManagement/exports/focus-export-for-billing-account-123456789/Run/e8102b07-9d1e-4185-95fe-fe60d8d6ad5a",
"/providers/Microsoft.Billing/billingAccounts/123456789/providers/Microsoft.CostManagement/exports/focus-export-for-billing-account-123456789/Run/1089e775-8098-4d50-ae69-c22fd26ae7ef"
]
export_id Id of the export.

E.g.: /providers/Microsoft.Billing/billingAccounts/123456789/providers/Microsoft.CostManagement/exports/focus-export-for-billing-account-123456789
months_to_backfill List of months to backfill.

E.g.:
[
{
start = "2023-01-01T00:00:00Z"
end = "2023-01-31T00:00:00Z"
},
{
start = "2023-02-01T00:00:00Z"
end = "2023-02-28T00:00:00Z"
}
]