With guidance from a previous SO post, I am trying to pass two parameters created in my Terraform template into a CloudFormation template as parameters:
My Terraform (0.13.5) code:
resource "aws_cloudformation_stack" "cloudwatch-synthetics-canary" {
provider = aws.primary
name = "cloudwatch-synthetics"
parameters = {
CloudWatchSyntheticsRole = aws_iam_role.cloudwatch_synthetics_role.arn,
ResultsBucket = aws_s3_bucket.results_bucket.arn
}
template_body = file("${path.module}/cloudwatch_canary.yml")
}
resource "aws_iam_role" "cloudwatch_synthetics_role" {
provider = aws.primary
name = "CloudWatchSyntheticsRole"
description = "Allows Cloudwatch Lambda to operate in this account."
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowLambdaAssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
POLICY
}
resource "aws_iam_policy" "cloudwatch_synthetics_role_policy" {
provider = aws.primary
name = "CloudWatchSyntheticsRolePolicy"
path = "/"
description = "Addtional allowances for the synthetics role"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
# --- SNIPPED FOR BREVITY ---
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "cloudwatch_synthetics_role_policy_attachment" {
provider = aws.primary
role = aws_iam_role.cloudwatch_synthetics_role.name
policy_arn = aws_iam_policy.cloudwatch_synthetics_role_policy.arn
}
My CloudFormation code:
Parameters:
CanaryName:
Type: String
Default: my-canary
MaxLength: 21
HostName:
Type: String
Default: api.myhost.net
MaxLength: 128
Path:
Type: String
Default: /v1/status
MaxLength: 256
Port:
Type: Number
Default: 443
CloudWatchSyntheticsRole:
Type: AWS::IAM::Role
ResultsBucket:
Type: AWS::S3::Bucket
...
Resources:
ExecutionRoleArn:
Fn::GetAtt:
- CloudWatchSyntheticsRole
- Arn # <-- TRIED WITH AND WITHOUT THIS
In Terraform.io, the error is as follows:
Error: Creating CloudFormation stack failed: ValidationError: Template error: instance of Fn::GetAtt references undefined resource CloudWatchSyntheticsRole
status code: 400, request id: 694c...
I tried making the types in the CFT as Strings, but that didn't seem to work, either. The Fn::GetAtt: also had '- Arn' below the CloudwatchSyntheticsRole to refer to the Arn, but since I'm passing that in directly, I tried removing it.
I feel like I'm close, but missing something and just need some help from some fresh eyes.
It looks like the solution, found by a co-worker of mine is pretty simple:
Make sure ALL CFT variables are in Terraform and pass any default values through Terraform as literals to Cloudformation
Remove all default parameters from CloudFormation, but still keep the Name and Type of variable at a minimum. Other constraints like 'MaxLength' are ok, too.
Example:
Terraform.tf:
resource "aws_cloudformation_stack" "cloudwatch-synthetics-canary" {
provider = aws.primary
name = "cloudwatch-synthetics"
parameters = {
CanaryName = "my-canary",
HostName = "api.server.net",
Path = "/v1/status",
Port = 443,
RoleArn = aws_iam_role.cloudwatch_synthetics_role.arn,
S3Location = "s3://${aws_s3_bucket.results_bucket.id}"
}
template_body = file("${path.module}/cloudwatch_canary.yml")
}
Cloudformation.yml:
Parameters:
CanaryName:
Type: String
MaxLength: 21
HostName:
Type: String
MaxLength: 128
Path:
Type: String
MaxLength: 256
Port:
Type: Number
RoleArn:
Type: String
S3Location:
Type: String
MaxLength: 1024