terraform,

Reusing templates in Terraform

Sep 12, 2021 · 2 mins read · Post a comment

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.