Introduction
In version 3.38.0 and later of the Terraform AWS Provider, a default_tags argument is available in the provider configuration block. This argument allows for tagging of all resources that currently support the tags argument. It is intended as an alternative to the repetitive nature of applying the same tags repeatedly across all resources.
Fix to Known Issues
Version 5.0.0 of the provider introduced several fixes to the issues identified below. Please follow the upgrade guide and check if upgrading the provider to version 5+ avoids these issues.
Known Issues
There are several issues to avoid when using both default_tags at the provider level and tags at the resource level.
1. Exactly identical default_tags and tags arguments produce the error: 
Error: "tags" are identical to those in the "default_tags" configuration block of the provider: please de-duplicate and try again
Example configuration that produces the above error:
provider "aws" { default_tags { tags = { Name = "Example" } } } resource "aws_vpc" "example" { tags = { Name = "Example" } }
This issue is reported in GitHub Issue #19204. This provider will not allow fully matching tags in both of these argument blocks.
2. Partially identical default_tags and tags arguments cause a planned update change when there is no change to either argument
Example configuration that produces this issue:
provider "aws" { default_tags { tags = { Match1 = "A"
Match2 = "B"
NoMatch = "X" } } } resource "aws_vpc" "example" { tags = { Match1 = "A"
Match2 = "B"
NoMatch = "Y" } }
After initial terraform apply, all subsequent plans will result in a "perpetual diff". Running terraform plan again on the example configuration shows a update to the matching tags Match1 and Match2 even though there hasn't been any change to these tags:
# aws_vpc.example will be updated in-place
~ resource "aws_vpc" "example" {
...
~ tags = {
+ "Match1" = "A"
+ "Match2" = "B"
# (1 unchanged element hidden)
}
# (28 unchanged attributes hidden)
This is a known issue also discussed in the comments of issue #19204. The provider does not gracefully handle identical tags in default_tags and tags.
3. There is no way to exclude resources from default_tags
This is noted in the documentation for default_tags. Tags from default_tags can only be overridden, not excluded, in individual resources.
Cause
The concept of "global" tagging was a design implemented by the default_tags feature of the Terraform AWS Provider. There is no corresponding concept in AWS, and there is no property in AWS API responses that exposes whether tags were created at a global or a resource level for a given resource. This results in a difficulty deciding how to categorize tag data that has not been fully resolved. Further discussion can be found on GitHub here.
Workarounds
The primary recommendation is to not use identical tags in both default_tags at the provider level and tags at the resource level. Resource-level tags should only be used to override global tags or to apply tags specific to that resource.
If your configuration already contains a combination of identical and unique tags across resources and in the default_tags block, there are multiple options for avoiding the perpetual diff scenario:
- Remove particular 
tagsfrom individual resources if they are not overriding thedefault_tags. - Remove particular 
default_tagsfor thosetagswhich all resources already define. - 
Stop using 
default_tagsentirely and configuretagsdirectly in resources. - Stop using 
default_tagsentirely and implement this behavior using variables and the merge function in each resource, e.g.: 
locals {
common_tags = {
tag1 = "A"
tag2 = "B"
tag3 = "C" }
...
}
resource "aws_instance" "vm" {
...
tags = merge(local.common_tags, var.override_tags)
}