Part 2: Validating AWS Tags with Terraform
Note: this is a continuation of Basics of AWS Tags & Terraform with S3. If you’d like to skip it, you can obtain the starter code repository on Github here as this is written to be followed along.
In Part 1: Basics of AWS Tags & Terraform with S3 blog post, we saw that adding tags to resources is fairly straightforward. Using tag blocks is trivial, but very repetitive, and utilizing default_tags
allows us to specify tags for entire deployments. Those methods work well, but how do we go about validating those tags? What if someone spells a tag incorrectly, misses the capitalization, or just forgets the tag altogether? That’s where tag validation comes into play!
Refactor our Terraform Deployment into Modules
First, let’s refactor our deployment. This will give us more flexibility over the tags and other attributes that are assigned to our modules.
Create main.tf
within a new directory called s3-bucket
Within s3-bucket/main.tf
, add the following code (and remove the same resources from the original main.tf
). Notice the tags
attribute is now defined as var.tags
, which we haven’t initialized yet. We have also modified the bucket
attribute to create a prefix dynamically based on the definition of the team
tag.
1
2
3
4
5
6
7
8
resource "random_id" "s3_id" {
byte_length = 2
}
resource "aws_s3_bucket" "team-bucket" {
bucket = "${var.tags["team"]}-bucket-${random_id.s3_id.dec}"
tags = var.tags
}
Replace the existing buckets in main.tf with module references
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module "finance-bucket" {
count = 1
source = "./s3-bucket"
tags = {
team = "finance"
service = "s3"
}
}
module "dev-bucket" {
count = 1
source = "./s3-bucket"
tags = {
team = "devops"
service = "s3"
}
After you’ve added the code, run a terraform init
to re-initialize the deployment for the new modules.
AWS Tags Validation
Now, what we want to do is validate that each resource has the team
and service
tags. We already know they all have the env
tag because it’s a default, but the other resources are up to the engineers to tag. Let’s utilize terraform console
and some Terraform functions to see how we can validate that these tags exist.
Let’s create a variables.tf
file in our root directory and add the following code:
1
2
3
4
5
6
7
variable "tags" {
type = map
validation {
condition = alltrue([for t in ["team", "service"] : contains(keys(var.tags), t)])
error_message = "Please include tags for team and service."
}
}
Now that this has been created, let’s access terraform console
and run a few commands that will help us understand how the validation condition above works.
First, since we’re trying to validate that the keys in our tags, “team” and “service”, exist, let’s use the keys()
Terraform function on our tags block:
1
2
3
4
5
> keys({service = "s3", team = "devops"})
[
"service",
"team",
]
Perfect! Now we have our keys. The next step is to confirm that they are both included. To do this, let’s first see how we would validate that one of our keys is included. We’ll validate that the “service” key is included in a list by using the contains()
Terraform function:
1
2
> contains(["service", "team"], "service")
true
Excellent, so we’ve validated that one of our keys exists, so let’s use a Terraform Loop to validate this. I’ll do this in stages so you can see the steps:
First, we’ll run a basic for loop to see our keys:
1
2
3
4
5
6
> [for t in ["env", "team", "dev"] : t]
[
"env",
"team",
"dev",
]
Then, we’ll use the contains()
function to test each item in the loop:
1
2
3
4
5
6
> [for t in ["env", "team", "service"] : contains(keys({env = "dev", team = "Finance", service = "S3"}), t)]
[
true,
true,
true,
]
Finally, we can utilize the alltrue()
function to get one true
value:
1
2
> alltrue([for t in ["env", "team", "service"] : contains(keys({env = "dev", team = "Finance", service = "S3"}), t)])
true
Awesome! We can now use this function to validate our tags.
Go ahead and exit the Terraform Console and then run a terraform apply -auto-approve
.
Assuming that went well, (it should have), let’s now see if we can break it!
Comment out the “service” tag of dev-bucket
:
1
2
3
4
5
6
7
8
module "dev-bucket" {
count = 1
source = "./s3-bucket"
tags = {
team = "devops"
# service = "s3"
}
}
Run another terraform apply -auto-approve
:
1
2
3
4
5
6
7
8
9
10
11
│ Error: Invalid value for variable
│
│ on main.tf line 35, in module "dev-bucket":
│ 35: tags = {
│ 36: team = "devops"
│ 37: service = "s3"
│ 38: }
│
│ Please specify the team and service tags.
│
│ This was checked by the validation rule at s3-bucket/variables.tf:3,5-15.
Boom! That worked exactly as we had hoped! You can also try misspelling each tag, changing caps, whatever you want. Everything should be caught properly!
Conclusion
Alright, so that’s all for this installment, go ahead and run a terraform destroy -auto-approve
and join me on the next one as we dive deeper into this deployment and create more robust tag validation code!
Manage, track, and report your AWS spending in seconds — not hours
CloudForecast’s focused daily AWS cost monitoring reports to help busy engineering teams understand their AWS costs, rapidly respond to any overspends, and promote opportunities to save costs.
Monitor & Manage AWS Cost in Seconds — Not Hours
CloudForecast makes the tedious work of AWS cost monitoring less tedious.
More from CloudForecast
AWS cost management is easy with CloudForecast
We would love to learn more about the problems you are facing around AWS cost. Connect with us directly and we’ll schedule a time to chat!