Azure 59: Standardized resource tagging — `terraform-common/azure/tags`
easy⏱ 5 mincourseazure
Required tags
Every Lythia resource MUST carry: owner (team email, e.g. shop@lithia.com), costCenter (e.g. SHOP-001), environment (dev|test|uat|prod), system (logical product, e.g. shop, ecommerce, incentives), and managedBy (terraform for IaC-managed resources, manual strongly discouraged). Optional but encouraged: service, confidentiality, dataClassification.
module "tags" {
source = "git::...terraform-common//azure/tags?ref=main"
owner = "shop@lithia.com"
cost_center = "SHOP-001"
environment = "prod"
system = "shop"
managed_by = "terraform"
}
# every resource:
resource "azurerm_storage_account" "eds" {
...
tags = module.tags.tags
}
Azure Policy enforces presence
A policy assignment at the management-group level denies create/update of resources whose tags don't include the required keys. The policy doesn't care about values; that's the IaC review's job. Once enforced, a terraform apply that forgets to pass tags = module.tags.tags fails with RequestDisallowedByPolicy. The signal is immediate, fixing-the-bad-resource cost is zero.
policyRule:
if:
allOf:
- field: tags.owner
exists: 'false'
- field: tags.costCenter
exists: 'false'
then:
effect: deny
Cost reporting follows tags
Azure Cost Management's 'group by tag' uses these tags directly. Group by: system answers 'what does shop cost?'. Group by: environment answers 'what is uat costing us?'. Without tagging, you fall back to resource group, which mixes systems whenever a team uses one RG for multiple products.
Build merger + policy check
Write tagsFor({owner, costCenter, environment, system}) returning a normalised map with the required keys plus managedBy = 'terraform'. Reject if owner doesn't match *@lithia.com, if costCenter doesn't match [A-Z]+-\\d{3}, or if environment isn't allowed. Write checkCompliance(tags) returning { ok, missing }. Log a clean tag set and try to set tags via an environment override (allowed) and a forbidden override (denied).
Don't store secrets in tags
Tags are visible to anyone with Reader on the resource. Some teams have stored API endpoints or admin emails 'for convenience'. Don't. Tags are for organisation and cost, not configuration. Use Key Vault for anything sensitive.
Quiz: why deny + not append?
Q: Azure Policy supports append — automatically adding missing tags. Why does Lythia use deny instead? A: Auditability. append would silently fix the missing tag, hiding the IaC mistake. deny forces the engineer to fix Terraform, which lives in git and is reviewed. Append is fine for greenfield setups; deny is correct for a stack where every change should be tracked.