Skip to main content
Your progress
0 of 4 lessons complete0%
T2 / M2.8 / L2 OF 4 / Engineer TIER / 9 min

Writing a tagging policy

Outcome

By the end of this lesson, you will be able to write a tagging policy from the five available source fields, judge whether a derived key is worth attributing on, and avoid the policies that look complete but attribute nothing.


TierEngineer
JTBD”Write a policy that actually splits my estate the way the cost conversation needs it split.”
PersonasPlatform Engineer · FinOps Lead
PrerequisitesM2.8.L1
Time9 minutes
Bloom verbWrite (Apply), Judge (Evaluate), Avoid (Apply)

1. Concept

A tagging policy is small by design: one tag key, and a rule for deriving its value. The editor is catalog-driven, at Settings → Policy → Tagging, and the whole surface area is the five source fields from L1.

Terminal window
provider aws | gcp | azure
region us-east-1, europe-west1, eastus, ...
type ec2, rds, gke-cluster, s3, ...
instance_type m5.large, db.r6g.xlarge, ...
name the resource's own name

That constraint is the design. A policy cannot call out to a CMDB, read an activity log, or look up an owner, so it cannot be quietly wrong in a way you would not notice. Everything it produces is inspectable from the resource row itself.

The one question that decides whether a policy is worth writing

Does the derived value identify a thing someone can be accountable for?

Terminal window
GOOD WHY
─────────────────────────────────────────────────────────────
name -> team prefix Names usually encode ownership
in an estate with any naming
convention at all
provider + region Useful when teams ARE split by
region, useless when they are not
type Good for workload-class
reporting; never for chargeback
BAD WHY
─────────────────────────────────────────────────────────────
provider alone Produces 1-3 values across the
whole estate. Attributes nothing.
instance_type A shape, not an owner. Nobody is
accountable for "m5.large".
region, in a single-region org One value. Same problem as
provider alone.

The failure mode is specific and worth naming: a policy that derives cleanly across 100% of the estate and produces three distinct values. Coverage goes green, the Unattributed bucket empties, and the report is now less honest than the empty one it replaced, because it looks resolved.

Cardinality is the test

Before accepting anything from a new policy, look at how many distinct values it produced against how many owners you actually have.

Terminal window
DISTINCT VALUES vs REAL OWNERS
~1 value attributes nothing. Delete the policy.
Far fewer than owners partial. Useful only if the axis is
genuinely how spend is owned.
Roughly one per owner this is what you want.
Far more than owners the key is too granular to report on.
Usually a name-derived policy that
picked up an instance suffix.

Designing a name-derived policy

Name is the most useful of the five fields, because in most estates the name is the only place ownership got written down.

Terminal window
TYPICAL NAMING WHAT A POLICY CAN DERIVE
─────────────────────────────────────────────────────────────
payments-api-prod-03 payments (leading segment)
platform-eks-staging platform (leading segment)
db-analytics-01 analytics (second segment)
i-0a3f9c2b1d nothing usable. Cloud-generated
names carry no information.
BEFORE WRITING ONE:
sample 50 resource names. If more than a few are
cloud-generated ids, a name policy will produce a long
tail of junk values that you then have to leave pending.

Multiple policies coexist

Each policy owns one key, so several run side by side and a resource can carry several derived tags.

Terminal window
POLICY A key: cost-allocation from: provider + region
POLICY B key: workload-class from: type
POLICY C key: team from: name
A resource can be pending on B while accepted on A and C.
Accept and revoke are per key, never per resource.

That is also the fix for the analytics estate from L1: when region is the wrong axis for one part of the estate, you do not weaken the region policy. You add a second policy on a better axis and accept it where it fits.

What a policy cannot do

Worth stating plainly, because these are the four requests that come up:

Terminal window
"Derive team from the CloudTrail creator"
No. Ownership detection reads activity logs and is a
separate feature; it is not available to a policy.
"Derive environment from whether the resource has a schedule"
No. Policies see resource fields, not ZopNight state.
"Only apply to resources over $100/month"
No. There is no cost predicate in the policy language.
"Use a regex with a fallback chain"
Check the editor's current catalog before promising this
to anyone. The catalog is the source of truth for what
transformations are available, and it changes per release.

2. Demo

Two policies written against the same estate, one useful and one not:

Terminal window
ESTATE: 2,259 resources, 3 clouds, 6 regions, 11 owning teams
POLICY 1 (written first)
key: cloud-provider
derived from: provider
RESULT: derived on 2,259 (100% coverage)
distinct values: 3
VERDICT: deleted. 100% coverage, zero attribution.
It would have taken Unattributed to 0% while
telling the FinOps lead nothing they did not
already know from the provider filter.
POLICY 2 (the replacement)
key: team
derived from: name, leading segment
RESULT: derived on 1,904 (84% coverage)
distinct values: 14
11 match known teams 1,781 resources
3 are junk from generated 123 resources
names (i-0a3f, vol-88c1,
eksctl-)
ACTION: accepted the 11 real teams.
left the 3 junk values pending, permanently.
355 resources produced no value at all
(cloud-generated names).
VERDICT: kept. 79% of spend now attributed to a
named team; the remaining 21% is visibly
unattributed, which is the honest state.
THE COMPARISON THAT MATTERS
Policy 1: 100% coverage, 3 values, 0 real attribution
Policy 2: 84% coverage, 14 values, 11 real owners

Policy 1 is the trap. It scores better on every dashboard metric and is worth nothing.


3. Hands-on (6 min)

Design one policy for your own estate, on paper before touching the editor:

Terminal window
1. Sample 50 resource names from Resources. How many
carry a human-chosen prefix rather than a cloud-
generated id? ___/50
Under about 30? Skip the name axis entirely.
2. How many owning teams does your org actually have?
(The number you would put on a chargeback report.)
______
3. Pick your axis and predict the cardinality:
axis: ______________ predicted distinct values: ____
Within 2x of your answer to 2? Y / N
If N, this policy will not attribute. Pick again.
4. Write the key name. It has to survive a reorg, so
avoid anything containing a current team name.
key: ________________________________________
5. Create it, refresh, and compare actual distinct
values to your prediction: predicted ___ actual ___
A large gap means you do not know your naming
convention as well as you thought. Look at the
outliers before accepting anything.

4. Knowledge check

Q1

A policy derives cloud-provider from provider and reaches 100% of the estate with 3 distinct values. Tag coverage goes green. The right action:

A. Accept it. 100% coverage is the goal
B. Leave it pending forever
C. Delete it
D. Accept it and add a second policy

Show answer

Correct: C. Coverage measures whether a value exists, not whether it attributes anything. Three values across the whole estate identify nobody, and accepting it would empty the Unattributed bucket while making the report less honest than the gap it replaced. This is the central trap of derived tagging: the policies that are easiest to write score best on the coverage metric and attribute the least. Judge a policy by distinct values against real owners, never by coverage percentage.

Q2

Your estate has 11 owning teams. A name-derived policy produces 14 distinct values: 11 matching teams and 3 junk values from cloud-generated names. The best handling:

A. Accept all 14; the junk values are harmless
B. Delete the policy outright, because it is not 100% accurate
C. Rename the resources first
D. Accept the 11 real values and leave the 3 junk values pending

Show answer

Correct: D. Accept and revoke are per key and per value, so partial acceptance is the intended workflow, and the resources behind the junk values stay visibly unattributed rather than being attributed to a meaningless bucket. Partial acceptance is normal and correct. The 3 junk values staying pending is a feature: those resources show up as Unattributed, which is a true statement about them, and it points at a naming problem worth fixing at the source.

Q3

A FinOps lead asks for a policy that tags only resources costing more than $100 per month. The accurate response:

A. Write it with a cost predicate in the policy editor
B. Possible, but only for AWS
C. Not possible
D. Possible via the auto-tagger’s confidence threshold

Show answer

Correct: C. A policy derives its value from provider, region, type, instance_type and name only. There is no cost predicate, no metric input and no ZopNight state available to it, so any filtering by spend has to happen when reading the report, not when deriving the tag. D references the removed heuristic auto-tagger, which had confidence tiers; Smart Tags has neither confidence nor cost predicates. The constraint is deliberate: everything a policy produces is inspectable from the resource row itself.


5. Apply

Write your policy at Settings → Policy → Tagging, then check its cardinality on Smart Tags before accepting anything. Distinct values against real owners is the only measure that tells you whether the policy earns its place.


Glossary terms touched

Tagging policy · Derived tag · Cardinality · Tag taxonomy


Start with the bill.

Foundations takes about five hours. The first lesson is nine minutes.

Open curriculum. No login. No paywall. 290 lessons across 7 courses, three publicly verifiable credentials. Read it on the train, take the exam on a Saturday, list the credential on your résumé Monday.

5h median time to finish Foundations
0 logins, paywalls, or marketing forms
open curriculum, public credential verifier
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·