How to share contents of resource across different modules

I have two modules which both build custom cloudfront response headers. I’d like to put the config of the modules into a separate file so that I can have the actual config consistent across both modules and only need to update the config in one place.

I originally have something like this:

resource "aws_cloudfront_response_headers_policy" "cloudfront_headers" {
  name        = "cloudfront_headers"

  custom_headers_config {
    items {
      header   = "Cache-Control"
      override = true
      value    = "no-cache, no-store, must-revalidate"
    }
  }
}

I’d like to put the contents of the custom_headers_config into a file in another directory and then refer to it, so I can also refer to it from a different module. I’ve tried the below, but it doesn’t work for me.

# in module.tf
data "local_file" "cache_headers_config" {
  filename = "${path.module}/../templates/cache-headers-config.txt"
}

resource "aws_cloudfront_response_headers_policy" "cloudfront_headers" {
  name        = "cloudfront_headers"

  custom_headers_config = data.local_file.cache_headers_config.content
}

# in cache-headers-config.txt
{
    items {
      header   = "Cache-Control"
      override = true
      value    = "no-cache, no-store, must-revalidate"
    }
}

Is there a way to put part of a resource in another file and refer to it?

Can you provide a bit more detail on how it doesn’t work? An error for example?

It looks like you’re storing JSON in a plan text file - you may want to use a formatting function to pass that to the resource block:

I’ve updated the custom headers file to json and using jsondecode. However The error message I’m getting is

Error: Unsupported argument

on module.tf line 8, in resource "aws_cloudfront_response_headers_policy" "cloudfront_cache_headers":
8:   custom_headers_config = jsondecode(data.local_file.custom_headers_config.content)

An argument named "custom_headers_config" is not expected here. Did you mean
to define a block of type "custom_headers_config"?

So it seems the putting security_headers_config = … make it think it’s an argument rather than a block.

However if I change it to:

security_headers_config { jsondecode(data.local_file.security_headers_config.content) }

It then gives an error of Error: Argument or block definition required

Thanks for your help. I ended up with a workable solution by taking a slightly different approach. Rather than generate the whole custom headers config as a variable, I put the expected block in the tf and just substituted the variables from the json where they’re needed. So the solution that works looks like this:

# in cache-headers-config.json
{
    "items" : {
      "header"   : "Cache-Control",
      "override" : true,
      "value"    : "no-cache, no-store, must-revalidate"
    }
}


# in cache_headers.tf
locals {
  cache_headers_config = jsondecode(file("${path.module}/../scripts/cache-headers-config.json"))
}

resource "aws_cloudfront_response_headers_policy" "cloudfront_custom_nocache" {
  name        = "cache_headers_policy"

  custom_headers_config {
    items {
      header = local.cache_headers_config.items.header
      override = local.cache_headers_config.items.override
      value = local.cache_headers_config.items.value
    }
  }
}
1 Like

:hammer::clap:t4: nailed it :clap:t4::hammer:

I’m always torn between writing JSON outside of TF so that I can check it against a schema, or defining variables in HCL which I then jsonencode and validate with Terraform itself. The important thing though is that your code is DRY :slight_smile: