Search code examples
parameter-passingterraformaws-cloudformationterraform-provider-aws

Problem passing parameters created in Terraform to CloudFormation


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.


Solution

  • It looks like the solution, found by a co-worker of mine is pretty simple:

    1. Make sure ALL CFT variables are in Terraform and pass any default values through Terraform as literals to Cloudformation

    2. 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