Working with Terraform and keeping the infrastructure code DRY has always been fun. If you’ve been deploying AWS S3 policies, or IAM policies, adding variables and making them reusable is part of the best practices. In Terraform, there are two things which could help us dynamically assign templates to resources, the template_file
data source and the templatefile
function. Let’s break them down by using an AWS IAM policy as example.
Prerequisites
- Terraform
AWS IAM policy example
Let’s say we got the following IAM policy that allows read-only access to an AWS S3 bucket:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": ["arn:aws:s3:::${bucket_name}"]
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": ["arn:aws:s3:::${bucket_name}/*"]
}
]
}
Save it under files/iam_policies/
as s3-read-only.json.tpl
.
template_file
template_file
is basically a data source that loads and renders templates from external files using the file
function.
Load, render the template, and create an IAM policy:
data "template_file" "s3_read_only" {
template = file("${path.module}/files/iam_policies/s3-read-only.json.tpl")
vars = {
bucket_name = aws_s3_bucket.devcoops_artifacts.id
}
}
resource "aws_iam_policy" "s3_read_only" {
name = "${var.infra_name}-s3-read-only"
policy = data.template_file.s3_read_only.rendered
}
Note(s): I’m assigning the bucket_name variable from the template as the value of the devcoops_artifacts
aws_s3_bucket resource.
templatefile
templatefile
is a built-in function that’s do the same thing as the data source above. So, why this one? For consistency. Terraform created the function in response to template_file
provider using its own template engine under the hood, which also being depended on the Terraform version the provider was compiled against, not the version you have installed.
resource "aws_iam_policy" "s3_read_only" {
name = "${var.infra_name}-s3-read-only"
policy = templatefile("${path.module}/files/iam_policies/s3-read-only.json.tpl", {
bucket_name = aws_s3_bucket.devcoops_artifacts.id
})
}
Note(s): Besides using different format templatefile(template_path, vars)
, templatefile function is implemented inline, as any other TF functions, meaning you don’t need to define extra code blocks.
Conclusion
So, which one is better to use?! Well, template_file
is kind of a legacy thing, so If you are using TF v0.12 and above, which I think you should, since HashiCorp released their TF v1.1.0 alpha version at the time being, the templatefile
function is a no-brainer.
Feel free to leave a comment below and if you find this tutorial useful, follow our official channel on Telegram.