Skip to content

Tagging Standard

Every resource and resource group carries a fixed set of eleven tags. Together they answer who owns a resource, what it is for, how it was built and who pays for it. Terraform modules apply the tags automatically, and Azure Policy checks for them.

Status: tags applied by Terraform, policy is audit-only

The platform's Terraform modules apply all eleven tags. The policy that checks them, psa-tags-enforce-001, runs with effect: Audit and enforcementMode: DoNotEnforce. It reports missing tags but does not block untagged resources. Some older documents, including the repository's CLAUDE.md, describe this as "enforced Deny". That is not the current state.


The tags

Tag Meaning Example
Environment Lifecycle stage prod, dev, sandbox
WorkloadOwner The business team that owns the workload platform-team, web-team
PlatformOwner The team that runs the platform. Always the same value. platform-team
Workload The workload or service the resource belongs to mkdocs, monitoring
ManagedBy How the resource is managed. Always Terraform. terraform
LastChangedBy Who or what last changed the resource. Set by CI. the pipeline or user identity
LastChangedDate When it was last changed ISO date
IaCModule The Terraform module that created it terraform-azurerm-log-analytics-workspace
IaCModuleVersion That module's version v1.0.0
IaCRepo The repository that deployed it the GitLab project path
FinOpsId The cost allocation key. A random UUID created once per subscription by subscription vending, which never changes. 3f2a… (a UUID)

LastChangedBy and LastChangedDate replaced the earlier CreatedBy and CreatedDate. A "created" tag is only accurate if it is fixed at true creation, which isn't possible for resources that existed before the standard.


How tags are applied

  • Terraform modules add them. Each resource module sets the provenance tags (IaCModule, IaCModuleVersion, IaCRepo, ManagedBy). The deployment supplies the ownership and cost tags.
  • CI sets LastChangedBy through TF_VAR_last_changed_by.
  • Resources created outside Terraform won't have them. This is intended. A missing ManagedBy = terraform tag is the quickest way to spot something created by hand.

How tags are checked

The psa-tags-enforce-001 assignment uses the custom initiative Tags - Enforcement (psd-tags-Enforcement). It has two checks per tag, one for resource groups and one for resources, and applies at mg-intermediate-root with no exclusions.

To make it blocking, follow the ADR-0001 promotion path: set the effect to Deny and the enforcementMode to Default in a separate MR. Two things to be aware of first:

  • Updates are blocked too. Deny blocks any update to an existing untagged resource until the tags are added. Fix the existing non-compliant resources first.
  • There is no inheritance. The initiative doesn't copy tags from a resource group to its resources. Every resource must be tagged directly.

Lesson from a past incident

In an earlier change, a new audit-only tag set was added by editing the existing enforcing assignment instead of adding a separate one. That silently removed the Deny enforcement. It was only noticed during a manual tag review. Add new policy behaviour as a new assignment or child node. Never repurpose one that is already enforcing.