AWS tag policies do not require tags (2026)

Akal Cloud Updated 11 min read

Quick answer

A tag policy does not require a tag. AWS states that untagged resources are not evaluated for compliance at all, so a tag policy governs capitalization and allowed values on tags that already exist. Enforcement mode is opt-in and covers 343 of the 1,493 resource types AWS lists, with rds:db among the gaps. Blocking an untagged create needs an SCP using aws:RequestTag and aws:TagKeys, and the tag still has to be activated for cost allocation before it reaches the bill.

An AWS Organizations tag policy does not require a tag. It governs what a tag key may look like once a resource is already tagged, and AWS says so in one line: "Untagged resources or tags that aren't defined in the tag policy aren't evaluated for compliance with the tag policy." Enforcement mode is real, but it is opt-in and partial. Counting AWS's own table of supported resource types gives 1,493 distinct types, of which 343 support enforcement and 1,148 can only be reported on.

What does an AWS Organizations tag policy actually enforce?

Capitalization and allowed values, on tags that already exist. The tag policies overview defines the scope precisely: "In a tag policy, you specify tagging rules applicable to resources when they are tagged." A policy names a tag key with the capitalization you want, optionally lists acceptable values, and optionally opts into enforcement for named resource types. This is the basic syntax, quoted from the tag policy syntax page:

{
    "tags": {
        "costcenter": {
            "tag_key": {
                "@@assign": "CostCenter"
            },
            "tag_value": {
                "@@assign": [
                    "100",
                    "200",
                    "300*"
                ]
            },
            "enforced_for": {
                "@@assign": [
                    "secretsmanager:ALL_SUPPORTED"
                ]
            }
        }
    }
}

Two defaults in that syntax do more damage than anything else in the feature. The first: "If the tag policy doesn't specify a tag value for a tag key, any value (including no value at all) is considered compliant." A policy that names only a key therefore passes an empty string. The second: "If case treatment isn't defined, lowercase is the default case treatment for tag keys." Write a policy that omits tag_key and you have quietly standardized your organization on costcenter, not CostCenter, which is not the key most teams think they are reporting on.

Can a tag policy stop an untagged resource from being created?

No, and AWS states it in an Important block on the enforcement page: "Basic compliance rules do not enforce tag compliance on resources that are created without tags. This capability does not enforce missing tag keys. You cannot use this capability to ensure that required or mandatory tag keys are configured at resource creation." The same paragraph hands the job to another service: "Use SCPs to prevent IAM users and roles in target accounts from creating certain resource types if the request doesn't include the specified tags."

The reporting side has the matching hole. The tagging compliance report "includes only resources that have had at least one user-defined tag at any point in their lifecycle", and, again in an Important block, "Untagged resources don't appear as non-compliant in results." A tag policy compliance score of 100% is therefore compatible with an account full of untagged EC2 instances. AWS's own answer on that page is a different service: run AWS Resource Explorer with the special tag:none filter, which comes with a caveat worth reading twice: "The tag:none filter applies to only tags that are created by the user. Tags that are generated and maintained by AWS are exempt from this filter and still appear in the results."

There is a second capability, "Required tag key", and its own field name gives the game away: in a policy it is written report_required_tag_for. Enforcement for it does not happen in the control plane at all. It happens in your pipeline, through the infrastructure-as-code integration, which offers "Warn mode: Allows deployments to proceed but generates warnings when required tags are missing" and "Fail mode: Blocks deployments that are missing required tags". It is not organization-wide either: "you must activate the AWS::TagPolicies::TaggingComplianceValidator hook in every AWS account and Region where you want to enforce required tagging compliance", and the Terraform path needs a provider bump, since "you need to update your Terraform AWS Provider to 6.22.0 or above and enable tag policy validation in your provider configuration". The CloudFormation side is narrower still, because "This hook only functions as a StackHook. It has no effect when used as a resource hook." Anything created by a console click, a raw API call or a service acting on your behalf never passes through that check.

Which AWS resource types support tag policy enforcement?

Fewer than a quarter of them. AWS publishes the list as one long table on the services and resource types that support enforcement page, with a Yes or No in four columns per row and no totals anywhere. We parsed it: 1,598 rows, of which 94 are ALL_SUPPORTED wildcard pseudo-rows rather than resource types. That leaves 1,504 named rows, and collapsing 11 duplicate listings (the same resource type listed once per CloudFormation alias, agreeing on every column) gives 1,493 distinct resource types across 317 services.

Counted from AWS's supported-resource-types tableResource typesShare
Distinct resource types listed1,493100%
Basic compliance rules, reporting mode1,49199.9%
Basic compliance rules, enforcement mode34323.0%
Required tag key, enforce for IaC65043.5%
Reportable but not enforceable1,14876.9%

By service the split is starker. Of the 317 services in the table, 103 have at least one resource type you can enforce on, and 214 have none: you can report on them and nothing more. The per-type detail is where a tagging standard meets reality, because the gaps are not in obscure services.

Resource typeReporting modeEnforcement modeEnforce for IaC
ec2:instanceYesYesYes
ec2:volumeYesYesYes
ec2:natgatewayYesYesYes
s3:bucketYesYesYes
rds:dbYesNoYes
rds:clusterYesNoYes
lambda:functionYesYesYes
eks:clusterYesYesYes
dynamodb:tableYesYesYes
elasticloadbalancing:loadbalancerYesYesYes

A database instance is not enforceable. rds:db and rds:cluster both carry Yes for reporting and No for enforcement mode, so the tag policy that blocks a mistyped CostCenter value on an EC2 instance will let the same mistake through on the RDS instance beside it. AWS states the constraint without quantifying it: "You can only enforce compliance with tag policies on supported resource types", and the wildcard does not rescue you, because "You can't use a wildcard to specify all services, or to specify a resource type across all services." AWS also warns that turning enforcement on has blast radius of its own: "If you enable enforcement, the tag policy prevents resources from being tagged and may block dynamic scaling and provisioning." These counts move as AWS adds services, so the table is the authority, not the totals.

How do you require a tag at creation time with an SCP?

With the aws:RequestTag and aws:TagKeys global condition keys, which inspect the tags in the request rather than the tags on the resource. The global condition key reference is clear about what each one sees: aws:RequestTag is "included in the request context when tag key-value pairs are passed in the request", and aws:TagKeys is "included in the request context if the operation supports passing tags in the request". This is the pattern, quoted verbatim from controlling access to AWS resources using tags. It is an identity-based policy in AWS's example, not an SCP, but the condition block is the part an SCP reuses:

{
    "Version":"2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": "ec2:CreateTags",
        "Resource": "arn:aws:ec2:*:*:instance/*",
        "Condition": {
            "StringEquals": {
                "aws:RequestTag/environment": [
                    "preprod",
                    "production"
                ]
            },
            "ForAllValues:StringEquals": {"aws:TagKeys": "environment"}
        }
    }
}

The piece that turns a value restriction into a tag requirement is the Null operator. AWS's second example on that page uses it and explains why: "The Null condition ensures that the condition evaluates to false if there are no tags in the request." The condition operator reference gives the semantics to invert for a Deny: "Use a Null condition operator to check if a condition key is absent at the time of authorization."

Two details decide whether such a policy works. First, tagging on create is often a separate action from creating, so the policy has to name both. AWS spells this out for snapshots: "to limit tags when someone creates an Amazon EC2 snapshot, you must include the ec2:CreateSnapshot creation action and the ec2:CreateTags tagging action in the policy." Second, an SCP has exemptions that a tag policy does not: "SCPs don't affect users or roles in the management account", and you cannot use one to restrict "Any action performed using permissions that are attached to a service-linked role". Remember too that "an SCP never grants permissions", so the guardrail only narrows what an identity policy already allows. Organizations no longer prints tagging SCP examples in the user guide at all: its SCP examples page now points at a GitHub repository that "contains example policies to get started or mature your usage of AWS SCPs".

Why does an SCP requiring CostCenter accept costcenter?

Because tags are case sensitive and the condition keys that police them are not. The Tagging AWS Resources guide is unambiguous: "Tag keys are case sensitive." The IAM condition key reference says the opposite about matching, in the same words reversed: "Tag keys are not case-sensitive." Values behave the other way round again, since "Values in these tag key/value pairs are case-sensitive."

Read together, the two pages describe the exact failure mode. AWS names it directly: "AWS services that support tags might allow you to create multiple tag key names that differ only by case, such as tagging an Amazon EC2 instance with stack=production and Stack=test", and "Key names are not case sensitive in policy conditions." So an SCP demanding aws:RequestTag/CostCenter is satisfied by a request carrying costcenter. The guardrail passes. The bill then shows two separate tag keys, each needing its own activation, and the chargeback query that groups by one of them silently drops the other. That is the enforcement gap most often mistaken for a data problem in the billing console.

The fix is to use both mechanisms for the halves they each cover. AWS's own recommendation for the policy side is aws:TagKeys with ForAllValues, because it "stops users from including other keys, such as accidentally using Environment instead of environment". The tag policy side supplies the capitalization rule that an IAM condition cannot express. The enforcement page describes that option as treating CostCenter, costCenter and Costcenter as unique tag keys, which is the check no condition key will do for you.

What do AWS Config and the Resource Groups Tagging API catch that tag policies miss?

Everything that already exists, which is the majority of the problem on any account older than a week. The managed rule required-tags evaluates resources against a list of required keys, with two limits stated on the page: "You can check up to 6 tags at a time", and the rule is detective only, since "this rule does not prevent you from creating resources with incorrect tags". Its coverage is narrower than tag policies by an order of magnitude: the rule lists 30 resource types, against the 1,493 in the tag policy table, which is 2.0% of them. It is also not a free control: a broad recorder plus a required-tags rule is a real line item, and the meters are in what AWS Config costs.

For a point-in-time sweep instead of a continuous one, the Resource Groups Tagging API reads tags across services in one call, paginated: "A request can include up to 50 keys, and each key can include up to 20 values", and each page returns at most 100 resources, since "You can specify a minimum of 1 and a maximum value of 100". It answers which resources carry which tags. It does not answer what the untagged ones cost, which is a question only the billing data can settle.

Does enforcing a tag make it appear in your AWS bill?

No. Enforcement and billing are separate systems with separate switches. Activating user-defined cost allocation tags opens with the rule: "For tags to appear on your billing reports, you must activate them." A tag policy lives in AWS Organizations and is managed by whoever owns governance. Activation lives in the Billing and Cost Management console of the management account and is managed by whoever owns the bill. Nothing connects the two, so the common outcome is a perfectly enforced tag that produces no billing column at all.

The gap is not only organizational. Activation is not retroactive by default, and the recovery path has its own conditions, which is the subject of why cost allocation tags show up empty. For costs that no tag can reach, because they belong to a shared resource rather than a workload, cost categories with split charges are the allocation mechanism rather than more tagging. And if the tagged totals still do not agree with each other, the reconciliation is in why Cost Explorer and your CUR differ.

Which tag enforcement mechanism should you use for which job?

All three, for different halves of the problem. None of them covers the others.

MechanismBlocks an untagged create?What it does coverDocumented limit
Organizations tag policy No Allowed values and capitalization on tags that exist; compliance reporting 343 of 1,493 resource types support enforcement mode; untagged resources are never evaluated
Tag policy, required tag key with IaC In the pipeline only CloudFormation, Terraform and Pulumi deployments missing a required key Hook activated per account and per Region; console and raw API calls bypass it
SCP with aws:RequestTag and aws:TagKeys Yes Deny creates whose request carries no tag, or the wrong tag keys No effect in the management account or on service-linked roles; key matching ignores case
AWS Config required-tags No Continuous detection of existing resources missing required keys 30 resource types, up to 6 tag keys per rule, and it never blocks a create
Resource Explorer tag:none, Tagging API No Finding untagged resources, which compliance reports exclude by design Point-in-time inventory, and AWS-generated tags are exempt from the filter

A workable order follows from the limits rather than from preference. Write the tag policy first, in reporting mode, with tag_key set explicitly so the lowercase default cannot pick your standard for you. Add the SCP for the handful of create actions that account for most of the spend, because that is the only layer that refuses an untagged resource. Use Resource Explorer to find what is already untagged, since the compliance report will not show it. Activate the tag keys for cost allocation, in the management account, before anyone measures anything. Then turn on enforced_for for the resource types that support it, on one account first, because AWS's own warning about blocked scaling and provisioning is the failure mode that reaches production fastest.

Share LinkedIn X Hacker News Reddit

See this on your own bill

Akal Cloud connects in about two minutes and shows the same numbers against your real AWS accounts.

Get started on AWS Marketplace

Related reading