Terraforming Azure 2.

Table of Contents
Continuing from the previous post, here is the next part of the series.
Cost considerations #
Before we start to madly creating resources, let’s take a look at the cost.
In my case I have decided to manage budgeting and cost viewing via Terraform as well. Admittedly, during the process there were a few snags, and I was close to giving it up, but eventually I got to a state with which I and managemed are mutually satisfied.
A little inspiration #
I will be honest, writing a module that handles the consumption reports from scratch was something I started - and got to relatively working state on budgets…on cost views a little less so - but eventually I shamelesly took “inspiration” from this repository. So big thank you for the Gravicore Team! (not related / know the company by the way)
The only change that I did, is ensuring we use up-to-date providers, as the modules seem to be a bit outdated.
Use the modules now #
Right, so now that I have this module not too far from the deploymnent, and configured providers
and backend
(see previous post), I also added a module to help me with conforming Azure naming conventions:
module "naming" {
source = "Azure/naming/azurerm"
}
What this module does is sufficiently explained here
Variables #
The variables I have created when using the module are as follows:
#------------------------------------------------------------------------------
# Azure Subscription IDs
# These variables define the subscription IDs for different
# parts of the BCMG platform architecture
#------------------------------------------------------------------------------
variable "platform_con_subscription_id" {
type = string
description = "Subscription ID for BCMG Platform Core Connectivity resources"
default = "00000000-0000-0000-0000-000000000000"
}
variable "platform_mgmt_subscription_id" {
type = string
description = "Subscription ID for BCMG Platform Management resources"
default = "00000000-0000-0000-0000-000000000000"
}
variable "platform_id_subscription_id" {
type = string
description = "Subscription ID for BCMG Platform Identity resources"
default = "00000000-0000-0000-0000-000000000000"
}
variable "landingzone_Empirics_subscription_id" {
type = string
description = "Subscription ID for BCMG Empirics landing zone resources"
default = "00000000-0000-0000-0000-000000000000"
}
#------------------------------------------------------------------------------
# Location and Environment Settings
# These variables control where resources are deployed and
# in which environment context
#------------------------------------------------------------------------------
variable "location" {
type = string
description = "Primary Azure region where resources will be deployed"
default = "northeurope"
}
variable "location_short" {
type = string
description = "Short code for Azure region, used in resource naming conventions"
default = "ne"
}
variable "environment" {
type = string
description = "Deployment environment (dev, test, prod, etc.) - affects resource configuration and naming"
default = "prod"
}
#------------------------------------------------------------------------------
# Resource Tagging
# Standardized tags applied to all resources for governance,
# cost tracking, and resource organization
#------------------------------------------------------------------------------
variable "tags" {
type = map(string)
description = "Map of tags to be applied to all resources created by this configuration"
default = {
DomainName = "bcmg.com"
Domain = "BCMG"
ManagedBy = "Terraform"
}
}
#------------------------------------------------------------------------------
# Cost Management Settings
# Configuration for Azure Cost Management alerts and reports
#------------------------------------------------------------------------------
variable "cost_management_recipient_emails" {
type = list(string)
description = "List of email addresses to receive Azure cost management notifications and reports"
default = ["admin@example.com", "finance@example.com"]
}
variable "cost_management_sender_email" {
type = string
description = "Email address used as the sender for Azure cost management notifications"
default = "azure-noreply@example.com"
}
variable "cost_management_provider" {
type = string
description = "Name of the Cost Management resource provider to register - refer to https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-services-resource-providers for other providers"
default = "Microsoft.CostManagementExports"
}
#------------------------------------------------------------------------------
# Budget Configuration
# Settings for consumption budgets across subscriptions
#------------------------------------------------------------------------------
variable "budget_amount" {
type = number
description = "Default budget amount in currency of the billing account"
default = 200
}
variable "budget_time_period_start" {
type = string
description = "Start date for budget time period in ISO 8601 format"
default = "2025-03-01T00:00:00Z"
}
variable "budget_time_period_end" {
type = string
description = "End date for budget time period in ISO 8601 format"
default = "2026-03-01T00:00:00Z"
}
#------------------------------------------------------------------------------
# Budget Notification Thresholds
# Threshold settings for budget alerts
#------------------------------------------------------------------------------
variable "budget_actual_threshold" {
type = number
description = "Threshold percentage for actual budget consumption alerts"
default = 80
}
variable "budget_forecast_threshold" {
type = number
description = "Threshold percentage for forecasted budget consumption alerts"
default = 90
}
#------------------------------------------------------------------------------
# Cost Management Report Configuration
# Settings for cost management reports and scheduling
#------------------------------------------------------------------------------
variable "report_chart_type" {
type = string
description = "Chart type for cost management views"
default = "StackedColumn"
}
variable "report_granularity" {
type = string
description = "Data granularity for cost management reports"
default = "Daily"
}
variable "report_weekly_schedule" {
type = list(string)
description = "Days of the week for weekly cost reports"
default = ["Monday", "Friday"]
}
variable "report_weekly_hour" {
type = number
description = "Hour of the day to send weekly reports (0-23)"
default = 8
}
variable "report_monthly_hour" {
type = number
description = "Hour of the day to send monthly reports (0-23)"
default = 23
}
variable "report_monthly_day" {
type = number
description = "Day of the month to send monthly reports (1-31)"
default = 30
}
#------------------------------------------------------------------------------
# Resource Group Configuration
# Resource group names for different workloads
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# Resource Group Configuration
# Resource group names for different workloads
#------------------------------------------------------------------------------
variable "resource_group_names" {
type = map(string)
description = "Map of resource group names for different workloads"
default = {
connectivity = "rg-connectivity",
identity = "rg-identity",
management = "rg-management",
empirics = "rg-empirics"
}
}
#------------------------------------------------------------------------------
# Cost Management Export Configuration
# Settings for export storage and export jobs
#------------------------------------------------------------------------------
variable "export_storage_account_tier" {
type = string
description = "Storage account tier for cost management exports"
default = "Standard"
}
variable "export_storage_replication_type" {
type = string
description = "Storage replication type for cost management exports"
default = "LRS"
}
variable "export_container_access_type" {
type = string
description = "Access type for the export storage container"
default = "container"
}
variable "export_recurrence_type" {
type = string
description = "Recurrence type for cost management exports"
default = "Monthly"
}
#? note: https://learn.microsoft.com/en-us/azure/cost-management-billing/cost-management-billing-faq#when-does-azure-finalize-or-close-the-billing-cycle-of-a-closed-month
variable "export_start_date" {
type = string
description = "Exact start date for cost management exports in format YYYY-MM-DDT00:00:00Z. If provided, this takes precedence over export_start_offset."
default = ""
}
#? note: https://learn.microsoft.com/en-us/azure/cost-management-billing/cost-management-billing-faq#when-does-azure-finalize-or-close-the-billing-cycle-of-a-closed-month
variable "export_end_date" {
type = string
description = "Exact end date for cost management exports in format YYYY-MM-DDT00:00:00Z. If provided, this takes precedence over export_end_offset."
default = ""
}
variable "export_start_offset" {
type = string
description = "Time offset for export period start date (e.g., '24h' for tomorrow)"
default = "24h"
}
variable "export_end_offset" {
type = string
description = "Time offset for export period end date (e.g., '8760h' for one year)"
default = "8760h"
}
variable "export_file_format" {
type = string
description = "File format for cost management exports"
default = "Csv"
}
variable "export_data_type" {
type = string
description = "Data type for cost management exports"
default = "ActualCost"
}
variable "export_time_frame" {
type = string
description = "Time frame for cost management exports"
default = "TheLastBillingMonth"
}
While some has default values, others are set to empty strings. This is because the values will be set by the terraform.tfvars
file. (In the repository there is a template that is meant to be copied, filled and renamed to terraform.tfvars
.)
Deployment code #
Now for the deployment currently I have two files:
- this one to create the neccesary exports:
/* -------------------------------------------------------------------------- */
/* Subsciptions to process */
/* -------------------------------------------------------------------------- */
locals {
subscriptions = {
management = {
id = "/subscriptions/${var.platform_mgmt_subscription_id}"
}
connectivity = {
id = "/subscriptions/${var.platform_con_subscription_id}"
}
identity = {
id = "/subscriptions/${var.platform_id_subscription_id}"
}
empirics = {
id = "/subscriptions/${var.landingzone_Empirics_subscription_id}"
}
}
}
/* -------------------------------------------------------------------------- */
/* Export storage */
/* -------------------------------------------------------------------------- */
resource "azurerm_storage_account" "export" {
provider = azurerm.management
name = replace("${module.naming.storage_account.name}-exports-00-all-${var.environment}-${var.location_short}", "-", "")
resource_group_name = local.cost_consumption_configs.management.resource_group_name
location = var.location
account_tier = var.export_storage_account_tier
account_replication_type = var.export_storage_replication_type
tags = var.tags
}
resource "azurerm_storage_container" "export" {
provider = azurerm.management
name = "${module.naming.storage_container.name}-exports-00-all-${var.environment}-${var.location_short}"
storage_account_id = azurerm_storage_account.export.id
container_access_type = var.export_container_access_type
# Note: Storage containers don't support tags
}
/* -------------------------------------------------------------------------- */
/* Neccesary registration */
/* -------------------------------------------------------------------------- */
/* ----------------------------- Cost Management ---------------------------- */
resource "azurerm_resource_provider_registration" "management" {
provider = azurerm.management
name = var.cost_management_provider
# Note: Resource provider registrations don't support tags
}
resource "azurerm_resource_provider_registration" "connectivity" {
provider = azurerm.connectivity
name = var.cost_management_provider
}
resource "azurerm_resource_provider_registration" "identity" {
provider = azurerm.identity
name = var.cost_management_provider
}
resource "azurerm_resource_provider_registration" "empirics" {
provider = azurerm.lz_empirics
name = var.cost_management_provider
}
/* -------------------------------------------------------------------------- */
/* Export definitions */
/* -------------------------------------------------------------------------- */
locals {
# Determine start date based on whether an exact date is provided or an offset should be used
export_start_date = var.export_start_date != "" ? var.export_start_date : "${formatdate("YYYY-MM-DD", timeadd(timestamp(), var.export_start_offset))}T00:00:00Z"
# Determine end date based on whether an exact date is provided or an offset should be used
export_end_date = var.export_end_date != "" ? var.export_end_date : "${formatdate("YYYY-MM-DD", timeadd(timestamp(), var.export_end_offset))}T00:00:00Z"
}
/* ----------------------------------------- Use `az costmanagement export list --scope "/subscriptions/< subscription ID >"` to verify if export is created ---------------------------------------- */
resource "azurerm_subscription_cost_management_export" "all_subscriptions" {
for_each = local.subscriptions
provider = azurerm.management
name = "cost-export-${each.key}-${var.environment}-${var.location_short}"
subscription_id = each.value.id
recurrence_type = var.export_recurrence_type
recurrence_period_start_date = local.export_start_date
recurrence_period_end_date = local.export_end_date
file_format = var.export_file_format
export_data_storage_location {
container_id = azurerm_storage_container.export.id
root_folder_path = "/root/${each.key}/"
}
export_data_options {
type = var.export_data_type
time_frame = var.export_time_frame
}
depends_on = [
azurerm_resource_provider_registration.connectivity,
azurerm_resource_provider_registration.identity,
azurerm_resource_provider_registration.empirics,
azurerm_resource_provider_registration.management
]
lifecycle {
ignore_changes = [
#! if you want to modify these, `taint` the resource
export_data_storage_location.0.root_folder_path
# We're no longer ignoring date changes since they're now dynamic
]
}
}
- and this one to create the reports and budgets
##? Notable: cost reports must be scheduled at least one day ahead (won't start the same day!)
##? https://learn.microsoft.com/en-us/azure/cost-management-billing/costs/tutorial-export-acm-data?tabs=azure-portal#export-schedule
/* -------------------------------------------------------------------------- */
/* Configurations */
/* -------------------------------------------------------------------------- */
locals {
cost_consumption_configs = {
connectivity = {
name = "conn-consumption"
resource_group_name = var.resource_group_names.connectivity
/* -------------------------------------------------------------------------- */
/* Subscription consumption budget configuration */
/* -------------------------------------------------------------------------- */
subscription_consumption_budget = {
"cbs-connectivity-01-conn-${var.environment}-${var.location_short}" = {
name = "cbs-connectivity-01-conn-${var.environment}-${var.location_short}"
amount = var.budget_amount
time_period = {
start_date = var.budget_time_period_start
}
notifications = [
{
threshold = var.budget_actual_threshold
threshold_type = "Actual" # Options: "Actual", "Forecasted"
operator = "GreaterThan" # Options: "GreaterThan", "LessThan", "EqualTo"
contact_emails = var.cost_management_recipient_emails
},
{
threshold = var.budget_forecast_threshold
threshold_type = "Forecasted"
operator = "GreaterThan"
contact_emails = var.cost_management_recipient_emails
}
]
}
}
/* -------------------------------------------------------------------------- */
/* Cost anomaly alert configuration */
/* -------------------------------------------------------------------------- */
azurerm_cost_anomaly_alert = {
name = "caa-connectivity-01-conn-${var.environment}-${var.location_short}"
display_name = "Connectivity Cost Anomaly Alert"
email_subject = "Connectivity Cost Anomaly Alert"
email_addresses = var.cost_management_recipient_emails
}
/* -------------------------------------------------------------------------- */
/* Cost management view configuration */
/* -------------------------------------------------------------------------- */
subscription_cost_management_view = {
"cmv-connectivity-01-mtd-${var.environment}-${var.location_short}" = {
name = "cmv-connectivity-01-mtd-${var.environment}-${var.location_short}"
display_name = "MTD - Connectivity Cost Management View"
chart_type = var.report_chart_type
accumulated = false
report_type = "Usage" # Options: "Usage", "ActualCost"
timeframe = "MonthToDate" # Options: "MonthToDate", "WeekToDate", "YearToDate"
dataset = {
granularity = var.report_granularity
aggregation = [
{
name = "cost"
column_name = "Cost"
}
]
grouping = [
{
name = "Product"
type = "Dimension"
}
]
}
pivot = [
{
name = "ServiceName"
function = "Sum"
column_name = "ServiceName"
type = "Dimension"
},
{
name = "ResourceLocation"
function = "Sum"
column_name = "ResourceLocation"
type = "Dimension"
},
{
name = "ResourceGroupName"
function = "Sum"
column_name = "ResourceGroupName"
type = "Dimension"
}
]
}
}
/* -------------------------------------------------------------------------- */
/* Scheduled action for cost management reports */
/* -------------------------------------------------------------------------- */
cost_management_scheduled_action = {
"cmsa-connectivity-01-weekly-${var.environment}-${var.location_short}" = {
name = "cmsa-connectivity-01-weekly-${var.environment}-${var.location_short}"
display_name = "WEEKLY - Connectivity Scheduled Action"
view_identifier = "cmv-connectivity-01-mtd-${var.environment}-${var.location_short}"
email_address_sender = var.cost_management_sender_email
email_subject = "Scheduled AZURE cost report - Connectivity"
email_addresses = var.cost_management_recipient_emails
frequency = "Weekly"
start_date = var.budget_time_period_start
end_date = var.budget_time_period_end
hour_of_day = var.report_weekly_hour
days_of_week = var.report_weekly_schedule
}
}
},
identity = {
name = "ide-consumption"
resource_group_name = var.resource_group_names.identity
subscription_consumption_budget = {
"cbs-identity-01-ide-${var.environment}-${var.location_short}" = {
name = "cbs-identity-01-ide-${var.environment}-${var.location_short}"
amount = var.budget_amount
time_period = {
start_date = var.budget_time_period_start
}
notifications = [
{
threshold = var.budget_actual_threshold
threshold_type = "Actual"
operator = "GreaterThan"
contact_emails = var.cost_management_recipient_emails
},
{
threshold = var.budget_forecast_threshold
threshold_type = "Forecasted"
operator = "GreaterThan"
contact_emails = var.cost_management_recipient_emails
}
]
}
}
azurerm_cost_anomaly_alert = {
name = "caa-identity-01-ide-${var.environment}-${var.location_short}"
display_name = "Identity Cost Anomaly Alert"
email_subject = "Identity Cost Anomaly Alert"
email_addresses = var.cost_management_recipient_emails
}
subscription_cost_management_view = {
"cmv-identity-01-mtd-${var.environment}-${var.location_short}" = {
name = "cmv-identity-01-mtd-${var.environment}-${var.location_short}"
display_name = "MTD - Identity Cost Management View"
chart_type = var.report_chart_type
accumulated = false
report_type = "Usage"
timeframe = "MonthToDate"
dataset = {
granularity = var.report_granularity
aggregation = [
{
name = "cost"
column_name = "Cost"
}
]
grouping = [
{
name = "Product"
type = "Dimension"
}
]
}
pivot = [
{
name = "ServiceName"
function = "Sum"
column_name = "ServiceName"
type = "Dimension"
},
{
name = "ResourceLocation"
function = "Sum"
column_name = "ResourceLocation"
type = "Dimension"
},
{
name = "ResourceGroupName"
function = "Sum"
column_name = "ResourceGroupName"
type = "Dimension"
}
]
}
}
cost_management_scheduled_action = {
"cmsa-identity-01-weekly-${var.environment}-${var.location_short}" = {
name = "cmsa-identity-01-weekly-${var.environment}-${var.location_short}"
display_name = "WEEKLY - Identity Scheduled Action"
view_identifier = "cmv-identity-01-mtd-${var.environment}-${var.location_short}"
email_address_sender = var.cost_management_sender_email
email_subject = "Scheduled AZURE cost report - Identity"
email_addresses = var.cost_management_recipient_emails
frequency = "Weekly"
start_date = var.budget_time_period_start
end_date = var.budget_time_period_end
hour_of_day = var.report_weekly_hour
days_of_week = var.report_weekly_schedule
}
}
},
empirics = {
name = "emp-consumption"
resource_group_name = var.resource_group_names.empirics
subscription_consumption_budget = {
"cbs-empirics-01-emp-${var.environment}-${var.location_short}" = {
name = "cbs-empirics-01-emp-${var.environment}-${var.location_short}"
amount = var.budget_amount
time_period = {
start_date = var.budget_time_period_start
}
notifications = [
{
threshold = var.budget_actual_threshold
threshold_type = "Actual"
operator = "GreaterThan"
contact_emails = var.cost_management_recipient_emails
},
{
threshold = var.budget_forecast_threshold
threshold_type = "Forecasted"
operator = "GreaterThan"
contact_emails = var.cost_management_recipient_emails
}
]
}
}
azurerm_cost_anomaly_alert = {
name = "caa-empirics-01-emp-${var.environment}-${var.location_short}"
display_name = "Empirics Cost Anomaly Alert"
email_subject = "Empirics Cost Anomaly Alert"
email_addresses = var.cost_management_recipient_emails
}
subscription_cost_management_view = {
"cmv-empirics-01-mtd-${var.environment}-${var.location_short}" = {
name = "cmv-empirics-01-mtd-${var.environment}-${var.location_short}"
display_name = "MTD - Empirics Cost Management View"
chart_type = var.report_chart_type
accumulated = false
report_type = "Usage"
timeframe = "MonthToDate"
dataset = {
granularity = var.report_granularity
aggregation = [
{
name = "cost"
column_name = "Cost"
}
]
grouping = [
{
name = "Product"
type = "Dimension"
}
]
}
pivot = [
{
name = "ServiceName"
function = "Sum"
column_name = "ServiceName"
type = "Dimension"
},
{
name = "ResourceLocation"
function = "Sum"
column_name = "ResourceLocation"
type = "Dimension"
},
{
name = "ResourceGroupName"
function = "Sum"
column_name = "ResourceGroupName"
type = "Dimension"
}
]
}
}
cost_management_scheduled_action = {
"cmsa-empirics-01-weekly-${var.environment}-${var.location_short}" = {
name = "cmsa-empirics-01-weekly-${var.environment}-${var.location_short}"
display_name = "WEEKLY - Empirics Scheduled Action"
view_identifier = "cmv-empirics-01-mtd-${var.environment}-${var.location_short}"
email_address_sender = var.cost_management_sender_email
email_subject = "Scheduled AZURE cost report - Empirics"
email_addresses = var.cost_management_recipient_emails
frequency = "Weekly"
start_date = var.budget_time_period_start
end_date = var.budget_time_period_end
hour_of_day = var.report_weekly_hour
days_of_week = var.report_weekly_schedule
}
}
},
management = {
name = "mgmt-consumption"
resource_group_name = var.resource_group_names.management
subscription_consumption_budget = {
"cbs-management-01-mgmt-${var.environment}-${var.location_short}" = {
name = "cbs-management-01-mgmt-${var.environment}-${var.location_short}"
amount = var.budget_amount
time_period = {
start_date = var.budget_time_period_start
}
notifications = [
{
threshold = var.budget_actual_threshold
threshold_type = "Actual"
operator = "GreaterThan"
contact_emails = var.cost_management_recipient_emails
},
{
threshold = var.budget_forecast_threshold
threshold_type = "Forecasted"
operator = "GreaterThan"
contact_emails = var.cost_management_recipient_emails
}
]
}
}
azurerm_cost_anomaly_alert = {
name = "caa-management-01-mgmt-${var.environment}-${var.location_short}"
display_name = "Management Cost Anomaly Alert"
email_subject = "Management Cost Anomaly Alert"
email_addresses = var.cost_management_recipient_emails
}
subscription_cost_management_view = {
"cmv-management-01-mtd-${var.environment}-${var.location_short}" = {
name = "cmv-management-01-mtd-${var.environment}-${var.location_short}"
display_name = "MTD - Management Cost Management View"
chart_type = var.report_chart_type
accumulated = false
report_type = "Usage"
timeframe = "MonthToDate"
dataset = {
granularity = var.report_granularity
aggregation = [
{
name = "cost"
column_name = "Cost"
}
]
grouping = [
{
name = "Product"
type = "Dimension"
}
]
}
pivot = [
{
name = "ServiceName"
function = "Sum"
column_name = "ServiceName"
type = "Dimension"
},
{
name = "ResourceLocation"
function = "Sum"
column_name = "ResourceLocation"
type = "Dimension"
},
{
name = "ResourceGroupName"
function = "Sum"
column_name = "ResourceGroupName"
type = "Dimension"
}
]
}
}
cost_management_scheduled_action = {
"cmsa-management-01-weekly-${var.environment}-${var.location_short}" = {
name = "cmsa-management-01-weekly-${var.environment}-${var.location_short}"
display_name = "WEEKLY - Management Scheduled Action"
view_identifier = "cmv-management-01-mtd-${var.environment}-${var.location_short}"
email_address_sender = var.cost_management_sender_email
email_subject = "Scheduled AZURE cost report - Management"
email_addresses = var.cost_management_recipient_emails
frequency = "Weekly"
start_date = var.budget_time_period_start
end_date = var.budget_time_period_end
hour_of_day = var.report_weekly_hour
days_of_week = var.report_weekly_schedule
}
}
}
}
}
/* -------------------------------------------------------------------------- */
/* Module calls */
/* -------------------------------------------------------------------------- */
module "azurerm_consumption_connectivity" {
source = "git::https://github.com/fabricesemti80/modules-tf-azure-infrastructure.git//tf-cost-management?ref=dev"
providers = {
azurerm = azurerm.connectivity
}
name = local.cost_consumption_configs.connectivity.name
resource_group_name = local.cost_consumption_configs.connectivity.resource_group_name
environment_prefix = var.environment
subscription_consumption_budget = local.cost_consumption_configs.connectivity.subscription_consumption_budget
azurerm_cost_anomaly_alert = local.cost_consumption_configs.connectivity.azurerm_cost_anomaly_alert
subscription_cost_management_view = local.cost_consumption_configs.connectivity.subscription_cost_management_view
cost_management_scheduled_action = local.cost_consumption_configs.connectivity.cost_management_scheduled_action
tags = merge(var.tags, {
CreationTimeUTC = timestamp(),
Environment = "PROD"
})
}
module "azurerm_consumption_identity" {
source = "git::https://github.com/fabricesemti80/modules-tf-azure-infrastructure.git//tf-cost-management?ref=dev"
providers = {
azurerm = azurerm.identity
}
name = local.cost_consumption_configs.identity.name
resource_group_name = local.cost_consumption_configs.identity.resource_group_name
environment_prefix = var.environment
subscription_consumption_budget = local.cost_consumption_configs.identity.subscription_consumption_budget
azurerm_cost_anomaly_alert = local.cost_consumption_configs.identity.azurerm_cost_anomaly_alert
subscription_cost_management_view = local.cost_consumption_configs.identity.subscription_cost_management_view
cost_management_scheduled_action = local.cost_consumption_configs.identity.cost_management_scheduled_action
tags = merge(var.tags, {
CreationTimeUTC = timestamp(),
Environment = "PROD"
})
}
module "azurerm_consumption_empirics" {
source = "git::https://github.com/fabricesemti80/modules-tf-azure-infrastructure.git//tf-cost-management?ref=dev"
providers = {
azurerm = azurerm.lz_empirics
}
name = local.cost_consumption_configs.empirics.name
resource_group_name = local.cost_consumption_configs.empirics.resource_group_name
environment_prefix = var.environment
subscription_consumption_budget = local.cost_consumption_configs.empirics.subscription_consumption_budget
azurerm_cost_anomaly_alert = local.cost_consumption_configs.empirics.azurerm_cost_anomaly_alert
subscription_cost_management_view = local.cost_consumption_configs.empirics.subscription_cost_management_view
cost_management_scheduled_action = local.cost_consumption_configs.empirics.cost_management_scheduled_action
tags = merge(var.tags, {
CreationTimeUTC = timestamp(),
Environment = "PROD"
})
}
module "azurerm_consumption_management" {
source = "git::https://github.com/fabricesemti80/modules-tf-azure-infrastructure.git//tf-cost-management?ref=dev"
providers = {
azurerm = azurerm.management
}
name = local.cost_consumption_configs.management.name
resource_group_name = local.cost_consumption_configs.management.resource_group_name
environment_prefix = var.environment
subscription_consumption_budget = local.cost_consumption_configs.management.subscription_consumption_budget
azurerm_cost_anomaly_alert = local.cost_consumption_configs.management.azurerm_cost_anomaly_alert
subscription_cost_management_view = local.cost_consumption_configs.management.subscription_cost_management_view
cost_management_scheduled_action = local.cost_consumption_configs.management.cost_management_scheduled_action
tags = merge(var.tags, {
CreationTimeUTC = timestamp(),
Environment = "PROD"
})
}
Without getting lost in the details too much, what we get from this is cost management view for all the subscriptions, similar to this:
(link to these are periodically sent to the relevant teams)…
…and periodic exports…
…stored in a blob storage
We take care of building the storage account (in one of the subscriptions) and the container inside of this, that will contain the exports from all the subscriptions in the scope. We also create periodic - in my case, weekly - reports to show the month-to-date usage and help management keeping an eye on Azure cost vs budget.
The exports of course are more usaefull for the teams interested in details and invoices.
Code #
To be continued #