How to Programmatically Tag Untagged AWS Resources
This article shows how to find and bulk-tag AWS resources that have no tags, programmatically at scale using the AWS CLI. Consistent tagging supports cost allocation, access control, automation, and operational grouping. The approach pairs AWS Resource Explorer (discovery) with the Resource Groups Tagging API (tagging).
Introduction
Organizations need AWS resources tagged for a consistent metadata standard — for example, applying a service or cost-center tag to support cost allocation, access control, or operational grouping. After an initial tagging effort, organizations often find resources that were never tagged at creation. For cost allocation specifically, this shows up as spend still attributed to untagged resources in Cost Explorer. At scale, this takes real effort on two fronts — discovery and volume: finding every untagged resource across regions and accounts, then tagging potentially thousands of them.
Approach Overview
For interactive tagging through console, you can use AWS Resource Explorer and Tag Editor. You can search, filter, and apply tags through GUI.
The article focuses on the programmatic (CLI) approach, which is more efficient when you need to tag thousands of resources, operate across multiple accounts, or automate tagging.
Resource Groups Tagging GetResources API only returns resources that already have at least one tag. You can use AWS Resource Explorer with tag:none query to find resources with no tags. Resource Groups Tagging TagResources API can then be used for tagging the resources. This article uses both APIs — resource-explorer-2 (discovery) and resourcegroupstaggingapi (tagging).
Note: Resource Explorer must be configured in your account before you can query it. See Setting up and configuring Resource Explorer.
The CLI Approach
This article uses service as the example tag key, but the same approach applies to any tag you need to apply at scale. The workflow is:
- Discover untagged resources with AWS Resource Explorer
- Apply the tags with the Resource Groups Tagging API
- Activate the tag for cost allocation and backfill historical data
- Prevent recurrence with governance controls
Note: The CLI commands below are examples to demonstrate the approach. You can adapt them into your own scripts, automation pipelines, or SDK-based tooling (Python/Boto3, etc.) as suits your environment.
Step 1 — Discover Untagged Resources with Resource Explorer
AWS Resource Explorer can find resources with no tags using the tag:none filter. The resourcetype.supports:tags filters for resources which support tagging.
Find all resources with no tags that support tagging (Discovery only):
aws resource-explorer-2 list-resources \ --filters FilterString="tag:none resourcetype.supports:tags" \ --region us-east-1 \ --output json | jq -r '.Resources[].Arn' > no-tags-discovery-only.csv
Review the no-tags-discovery-only.csv to see what's untagged across regions/accounts.
Find resources missing a specific key (they may have other tags, just not service):
aws resource-explorer-2 list-resources \ --filters FilterString="-tag.key:service" \ --region us-east-1 \ --output json | jq -r '.Resources[].Arn'
Narrow to specific resource types, region and account (e.g. volumes):
aws resource-explorer-2 list-resources \ --filters FilterString="tag:none resourcetype:ec2:volume region:us-east-1 accountid:123456789012" \ --region us-east-1 \ --output json | jq -r '.Resources[].Arn' > untagged.csv
Replace accountid with the appropriate value. Review the untagged.csv to confirm the resources are the ones you scoped for and expect to tag in next step.
Note: Point --region at the region that hosts your aggregator index — its Resource Explorer view spans all regions and includes tags. The region: and accountid: filters narrow results to one region and one account, matching the region-scoped tag-resources calls that follow. Scoping the query by resource type, region, and account helps with batching and gives you tighter control over the tagging process.
Step 2 — Apply the Tags
If every resource is getting the same tag value, you can batch up to 20 ARNs per API call. The TagResources API supports a maximum of 20 ARNs per call, and xargs -n 20 batches the ARNs accordingly:
cat untagged.csv | xargs -n 20 | while read -r arns; do aws resourcegroupstaggingapi tag-resources \ --region us-east-1 \ --resource-arn-list $arns \ --tags "service=MyApplication" \ --output json done
Replace MyApplication with the appropriate value.
Applying different values per resource: When resources need different values (e.g., mapping each resource to its owning team), you can export the untagged ARNs, open the CSV, and fill in the values in second column of CSV.
Updated CSV output should look like below (ARN + value):
"arn:aws:ec2:us-east-1:123456789012:volume/vol-abc","payments"
"arn:aws:ec2:us-east-1:123456789012:volume/vol-def","identity"
Then read each ARN and value per row and tag them individually (one API call per resource):
while IFS=, read -r arn value; do arn=$(echo "$arn" | tr -d '"') value=$(echo "$value" | tr -d '"') aws resourcegroupstaggingapi tag-resources \ --region us-east-1 \ --resource-arn-list "$arn" \ --tags "service=$value" \ --output json done < untagged.csv
Verify the tag was applied:
aws resourcegroupstaggingapi get-resources \ --region us-east-1 \ --tag-filters 'Key=service' \ --output json | jq -r ' .ResourceTagMappingList[] as $r | $r.Tags[] | select(.Key == "service") | [$r.ResourceARN, .Value] | @csv' > tagged-verify.csv
The resources with service tag will appear in GetResources output — confirming the tagging operation succeeded.
Step 3 — Activate the Tag for Cost Allocation
Activate the tag as a cost allocation tag in the management (payer) account under Billing and Cost Management → Cost allocation tags. It can take up to 24 hours to appear in Cost Explorer and the Cost and Usage Report (CUR). For the full process, see Activating user-defined cost allocation tags.
Note: Cost allocation tags apply only going forward. Resources you tag now (because they were previously untagged) will show under the tag from the tagging date onward — their earlier usage carried no tag and cannot be attributed retroactively. Cost allocation tag backfill only activates a tag for the resources that already carried it; it does not add tags to historical usage.
Step 4 — Prevent Recurrence
Tagging existing resources is reactive. To keep new resources compliant:
- Tag at creation via IaC (CloudFormation, Terraform, CDK) — the most durable fix. See Implementing and enforcing tagging for tagging resources at creation, and Enforce consistent tagging across IaC deployments with AWS Organizations Tag Policies for combining IaC with org-wide enforcement.
- Tag Policies (AWS Organizations) — enforce tag key casing and allowed values. Note that Tag Policies enforce the format of supplied tags but do not prevent resources from being created without tags.
- Service Control Policies (SCPs) — deny resource creation when a required tag key is missing. This is what closes the "created without any tags" gap.
- AWS Config
required-tagsrule detects resources missing required tags, with optional automated remediation via SSM Automation. See the required-tags managed rule.
Considerations
- API Limits:
TagResourcesandUntagResourcesare limited to 5 calls per second andGetResourcesto 15 calls per second. See Resource Groups and Tagging endpoints and quotas. Configure AWS CLI retries as needed. - Per-region, per-account: The APIs operate per-region and per-account. For multi-region or multi-account environments, extend these commands into your existing automation or scripting workflows as needed.
- Resource type support: Resource Explorer and the Tagging API support most, but not all, resource types. See supported resource types to confirm coverage.
- Free-form search: For deterministic results in automation, we used
--filtersabove. You can useresource-explorer-2 searchfor free-form text search.
Conclusion
AWS Resource Explorer and the Resource Groups Tagging API work together to tag resources programmatically at scale — Resource Explorer discovers resources, and the Tagging API applies tags in bulk with tag-resources. Once tags are applied and activated as cost allocation tags, you can track costs by tag in Cost Explorer and the Cost and Usage Report (CUR). Pair this with tagging at creation, Tag Policies, SCPs, and AWS Config rules so new resources stay compliant from creation.
- Topics
- Management & Governance
- Language
- English
Relevant content
asked 4 years ago
AWS OFFICIALUpdated 2 months ago