Attributes values filtering on All AWS resources

Hi all :wink:

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 :wink:

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 :wink:
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 :wink: