Hi all 
I try to enforce mandatory tags for an AWS automation project.
I see lots of examples targeting specific resources, but with the very large number of resources on AWS provider, is there a way to filter on all resources ?
I tried with tfconfig.findAllResources () but without success. My idea is to check if “Name” and “Owner” tags are set.
Any ideas ?
Thanks for help.
++
Hi @opsrom,
I wrote the tfconfig-functions.findAllResources()
and all the other common functions in the third-generation example under https://github.com/hashicorp/terraform-guides/tree/master/governance/third-generation.
I recommand using the tfplan-functions Sentinel module which uses the tfplan/v2 import instead of the tfconfig-functions Sentinel module that uses the tfconfig/v2 import. The tfplan/v2 module will actually provide actual values set on tags of resources.
While the tfplan-functions module does not include a function that finds all resources from a specific provider, you could easily define one inside your Sentinel policy or in your own Sentinel module that would look like this:
find_resources_by_provider = func(provider) {
resources = filter tfplan.resource_changes as address, rc {
rc.provider_name is provider and
rc.mode is "managed" and
(rc.change.actions contains "create" or rc.change.actions contains "update")
}
return resources
}
I will even add that function to the tfplan-functions module and a similar function to the tfstate-functions module.
You can then use that function in a policy similar to https://github.com/hashicorp/terraform-guides/blob/master/governance/third-generation/aws/enforce-mandatory-tags.sentinel, using a line like allAWSResources = plan.find_resources_by_provider("aws")
.
But be aware that some AWS resources use the tags
attribute differently than most other AWS resources. In particular, the aws_autoscaling_group resource uses it differently.
So, for your use case, you probably need to use a custom function like this:
find_aws_resources_with_standard_tags = func() {
resources = filter tfplan.resource_changes as address, rc {
rc.provider_name is "aws" and
rc.type not in ["aws_autoscaling_group"] and
rc.mode is "managed" and
(rc.change.actions contains "create" or rc.change.actions contains "update")
}
return resources
}
If you encountered other AWS resources that also did not use the tags
attribute in the standard way, you could add them to the list in that function.
Roger Berlind
A big thank you to you, I will try quickly 
Sorry I think I’m not yet enough stronger with Sentinel policy code, I have to work harder.
I try this :
# This policy uses the Sentinel tfplan/v2 import to require that
# all AWS ressources have all mandatory tags
import "tfplan-functions" as plan
mandatory_tags = ["Name", "Owner"]
find_aws_resources = func() {
resources = filter plan.resource_changes as address, rc {
rc.provider_name is "aws" and
rc.type is not in ["aws_autoscaling_group"] and
rc.mode is "managed" and
(rc.change.actions contains "create" or rc.change.actions contains "update")
}
return resources
}
resources = find_aws_resources()
violatingResources = plan.filter_attribute_not_contains_list(resources, "tags", mandatory_tags, true)
main = rule {
length(violatingResources["messages"]) is 0
}
What are my mistakes please ?
Thanks again.
Note that I accidentally included an extra is
in the line of the last function that checked whether rc.type
is not in the list that includes aws_autoscaling_group
. I edited the post to fix that.
Thanks 
Now I have :
# This policy uses the Sentinel tfplan/v2 import to require that
# all AWS ressources have all mandatory tags
import "tfplan-functions" as plan
mandatory_tags = ["Name", "Owner"]
find_aws_resources = func() {
resources = filter plan.resource_changes as address, rc {
rc.provider_name is "aws" and
rc.type not in ["aws_autoscaling_group"] and
rc.mode is "managed" and
(rc.change.actions contains "create" or rc.change.actions contains "update")
}
return resources
}
resources = find_aws_resources()
violatingResources = plan.filter_attribute_not_contains_list(resources, "tags", mandatory_tags, true)
main = rule {
length(violatingResources["messages"]) is 0
}
And policy check returns :
An error occurred: 1 error occurred:
- ./enforce-mandatory-tags.sentinel:9:22: unsupported type for looping: undefined
Any idea ?
Your function should use tfplan.resource_changes
instead of plan.resource_changes
.
it works perfectly !
A big thank-you 