Skip to content

Instantly share code, notes, and snippets.

@jgrumboe
Last active August 27, 2021 10:01
Show Gist options
  • Save jgrumboe/cc64d9a5a231441361e2790821229ec6 to your computer and use it in GitHub Desktop.
Save jgrumboe/cc64d9a5a231441361e2790821229ec6 to your computer and use it in GitHub Desktop.
Terraform aws_cloudformation_stack static template_url reapply

Terraform aws_cloudformation_stack

The terraform aws_cloudformation_stack resource is capable to use a template_url as input. That's fine, if you like to apply some vendor CloudFormation stack, e.g. Prismacloud Read Only Role (https://docs.paloaltonetworks.com/prisma/prisma-cloud/prisma-cloud-admin/connect-your-cloud-platform-to-prisma-cloud/onboard-your-aws-account/update-an-onboarded-aws-account.html)

Since the URL, in the Prismacloud example https://s3.amazonaws.com/redlock-public/cft/rl-read-only.template, is a static URL Terraform wouldn't see any changes here and you would end up with never applied updates of the template hosted on S3. Unfortunately the aws_cloudformation_stack resource has no logic to "reapply/reload" the CF stack in some reoccuring interval. 😞

Trick CF stack with URL query string

AWS S3 allows you to append a query string to an S3 URL. Normally this is used to generate presigned URLs for authorized up- or downloads. 💡

One can use this to append a pattern to the static URL given as template_url, which will trigger a reapply of the CF stack the next time you run tf apply. ✔️

The following code will generate a date-timestamp which changes once a month and appends it to your static S3 URL:

locals {
  timestamp = formatdate("YYYY-MM", timestamp())
}

resource "aws_cloudformation_stack" "prisma_cloud" {
  name         = "genesis-aws-accounts-prisma-cloud"
  template_url = "https://redlock-public.s3.amazonaws.com/cft/rl-read-only.template?${local.timestamp}" # Adding timestamp will trigger a reload of the stack from S3
  capabilities = ["CAPABILITY_NAMED_IAM"]

  # Parameters and lifecycle specific for Prismacloud integration use case
  parameters = {
    ExternalID = uuid()
  }

  lifecycle {
    ignore_changes = [parameters["ExternalID"]]
  }
}

So each time tf apply is run it will generate a new timestamp appended to the S3 URL. This pseudo query string will be ignored by S3 and will still response with the normal payload of the S3 object.

Each month it will reapply the CF stack. If the payload is the same nothing will happen on CF side. On the other side, if the vendor has updated the S3 object, the updates will get applied to your CF stack. 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment