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.
| Tier | Engineer |
| JTBD | ”Write a policy that actually splits my estate the way the cost conversation needs it split.” |
| Personas | Platform Engineer · FinOps Lead |
| Prerequisites | M2.8.L1 |
| Time | 9 minutes |
| Bloom verb | Write (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.
provider aws | gcp | azureregion us-east-1, europe-west1, eastus, ...type ec2, rds, gke-cluster, s3, ...instance_type m5.large, db.r6g.xlarge, ...name the resource's own nameThat 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?
GOOD WHY─────────────────────────────────────────────────────────────name -> team prefix Names usually encode ownership in an estate with any naming convention at allprovider + region Useful when teams ARE split by region, useless when they are nottype 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.
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.
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.
POLICY A key: cost-allocation from: provider + regionPOLICY B key: workload-class from: typePOLICY 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:
"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:
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 ownersPolicy 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:
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.
Related lessons
- L1: What Smart Tags derive
- L3: Accept, revoke, apply to cloud (next)
- T5.M5.1.L2: The minimum viable tag set
- T5.M5.1.L5: Reorg-proof tagging
Glossary terms touched
Tagging policy · Derived tag · Cardinality · Tag taxonomy