'How to pass a list of AZs from Terraform to a CloudFormation template?
I have a CloudFormation template that defines this parameter:
"AvailabilityZones" : {
"Description" : "List of Availability Zones used ... ",
"Type" : "List<AWS::EC2::AvailabilityZone::Name>"
},
I invoke the CF template like this:
resource "aws_cloudformation_stack" "xxx" {
name = "xxx-stack"
template_body = file("../cloudformation/xxx_CloudFormation_template_2.1.1.json")
parameters = {
VpcId = aws_vpc.xxxvpc.id
SubnetCidrBlock = var.aws_vpc_cidr
AvailabilityZones = var.aws_azs
InstanceType = "m5.4xlarge"
ExternalNet = "0.0.0.0/0"
....
}
on_failure = "DELETE"
}
Where:
variable "aws_azs" {
default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
I get the error:
Inappropriate value for attribute "parameters": element "AvailabilityZones": string required.
I have tried many variations on this theme, but I can't see how to pass a list of AZs to the CF template from TF.
I am also more than a little puzzled by the assertion that a string is required in the error message, as the parameter type in the CF template is defined as a list.
Any ideas please?
Solution 1:[1]
I would prefer to use the templatefile function instead of the file you are using in the template_body field. You can pass variables there and fill the template with passed variables with nice template engine. You can use variables, functions, statements and loops there.
Example is here https://www.terraform.io/docs/language/functions/templatefile.html
Your example
resource "aws_cloudformation_stack" "xxx" {
....
template_body = templatefile("../cloudformation/xxx_CloudFormation_template_2.1.1.json", {
aws_azs = var. aws_azs
})
....
}
and your cf file:
"AvailabilityZones" : {
"Description" : "List of Availability Zones used ${join(',', aws_azs)} ",
"Type" : "List<AWS::EC2::AvailabilityZone::Name>"
},
Solution 2:[2]
To pass a list of values from Terraform to CloudFormation you will need to join them as a comma separated list.
TL;DR
resource "aws_cloudformation_stack" "this" {
...
parameters = {
AvailabilityZones = join(",", ["us-east-1a", "us-east-1b", "us-east-1c"])
}
}
Explanation
To pass lists of things to a CloudFormation template you will have to either pass a native construct or a comma separated list of values.
https://aws.amazon.com/premiumsupport/knowledge-center/multiple-values-list-parameter-cli/
Consider we have a CloudFormation template cfn-template.yml that requires us to pass a list of AZs as parameter:
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
AvailabilityZones:
Description: List of Availability Zones used ...
Type: "List<AWS::EC2::AvailabilityZone::Name>"
Resources:
NullResource: # CF needs at least 1 resource, so we hand it a dummy
Type: "AWS::CloudFormation::WaitConditionHandle"
Outputs:
PassedAvailabilityZones:
Description: The AZs passed into the cfn template from Terraform.
Value: !Join [ ",", !Ref AvailabilityZones ]
In your terraform we will need to create a comma separated string of these values and pass them in the parameter block.
variable "aws_azs" {
type = list(string)
default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
resource "aws_cloudformation_stack" "this" {
name = "test-pass-azs"
parameters = {
AvailabilityZones = join(",", var.aws_azs)
}
template_body = file("./cfn-template.yml")
}
terraform {
required_version = "~> 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Niels |
