Skip to content

CloudFormation Code in Terraform

Updated: at 01:00 AM

CloudFormation in Terraform resource

aws_cloudformation_stack provides a CloudFormation Stack resource. It serves as a bridge from Terraform into CloudFormation, which can be used either as an aid for migration from CloudFormation to Terraform or to make use of some of CloudFormation’s features that Terraform doesn’t currently handle, such as rolling deployments of new instances into an ASG.

These features together allow you to effectively mix CloudFormation and Terraform in a single system in different combinations, whether it’s as a temporary measure while migrating or permanently in situations where a hybrid solution is desired.

Example as file

resource "aws_cloudformation_stack" "wafv2" {
  name          = "federated-gw-wafv2"
  template_body = file("${path.module}/waf.yml")
}

Example with JSON

Or you can use full json like this:

resource "aws_cloudformation_stack" "wafv2" {
  name = "federated-gw-wafv2"
  template_body = <<EOF
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "WebACL": {
      "Type": "AWS::WAFv2::WebACL",
      "Properties": {
        "Name": "federated-gw-wafv2",
        "Scope": "REGIONAL",
        "Description": "Federated Gateway WAFv2",
        "DefaultAction": {
          "Allow": {}
        },
        "VisibilityConfig": {
          "SampledRequestsEnabled": true,
          "CloudWatchMetricsEnabled": true,
          "MetricName": "federated-gw-wafv2"
        },
        "Rules": [{
            "Name": "federated-gw-wafv2-authorizer-custom-header-protection",
            "Priority": 0,
            "Statement": {
              "OrStatement": {
                "Statements": [{
                    "SizeConstraintStatement": {
                      "FieldToMatch": {
                        "SingleHeader": {
                          "Name": "x-pets"
                        }
                      },
                      "ComparisonOperator": "GE",
                      "Size": 0,
                      "TextTransformations": [{
                        "Priority": 0,
                        "Type": "NONE"
                      }]
                    }
                  },
                  {
                    "SizeConstraintStatement": {
                      "FieldToMatch": {
                        "SingleHeader": {
                          "Name": "x-groups"
                        }
                      },
                      "ComparisonOperator": "GE",
                      "Size": 0,
                      "TextTransformations": [{
                        "Priority": 0,
                        "Type": "NONE"
                      }]
                    }
                  },
                  {
                    "SizeConstraintStatement": {
                      "FieldToMatch": {
                        "SingleHeader": {
                          "Name": "x-user-id"
                        }
                      },
                      "ComparisonOperator": "GE",
                      "Size": 0,
                      "TextTransformations": [{
                        "Priority": 0,
                        "Type": "NONE"
                      }]
                    }
                  },
                  {
                    "SizeConstraintStatement": {
                      "FieldToMatch": {
                        "SingleHeader": {
                          "Name": "x-api-key"
                        }
                      },
                      "ComparisonOperator": "GE",
                      "Size": 0,
                      "TextTransformations": [{
                        "Priority": 0,
                        "Type": "NONE"
                      }]
                    }
                  }
                ]
              }
            },
            "Action": {
              "Block": {}
            },
            "VisibilityConfig": {
              "SampledRequestsEnabled": true,
              "CloudWatchMetricsEnabled": true,
              "MetricName": "RSC-AuthorizerHeaderProtection"
            }
          },
          {
            "Name": "federated-gw-wafv2-managed-rules-sqli",
            "Priority": 1,
            "Statement": {
              "ManagedRuleGroupStatement": {
                "VendorName": "AWS",
                "Name": "AWSManagedRulesSQLiRuleSet",
                "ExcludedRules": []
              }
            },
            "OverrideAction": {
              "None": {}
            },
            "VisibilityConfig": {
              "SampledRequestsEnabled": true,
              "CloudWatchMetricsEnabled": true,
              "MetricName": "AWS-AWSManagedRulesSQLiRuleSet"
            }
          },
          {
            "Name": "federated-gw-wafv2-managed-rules-linux",
            "Priority": 2,
            "Statement": {
              "ManagedRuleGroupStatement": {
                "VendorName": "AWS",
                "Name": "AWSManagedRulesLinuxRuleSet",
                "ExcludedRules": []
              }
            },
            "OverrideAction": {
              "None": {}
            },
            "VisibilityConfig": {
              "SampledRequestsEnabled": true,
              "CloudWatchMetricsEnabled": true,
              "MetricName": "AWS-AWSManagedRulesLinuxRuleSet"
            }
          },
          {
            "Name": "federated-gw-wafv2-managed-rules-bad-input",
            "Priority": 3,
            "Statement": {
              "ManagedRuleGroupStatement": {
                "VendorName": "AWS",
                "Name": "AWSManagedRulesKnownBadInputsRuleSet",
                "ExcludedRules": []
              }
            },
            "OverrideAction": {
              "None": {}
            },
            "VisibilityConfig": {
              "SampledRequestsEnabled": true,
              "CloudWatchMetricsEnabled": true,
              "MetricName": "AWS-AWSManagedRulesKnownBadInputsRuleSet"
            }
          }
        ]
      }
    }
  },
  "Outputs": {
    "wafname": {
      "Value": {
        "Ref": "WebACL"
      }
    }
  }
}
EOF
}

resource "aws_cloudformation_stack" "wafv2association" {
  name = "wafv2association"
  depends_on = [aws_cloudformation_stack.wafv2, aws_api_gateway_rest_api.federated_api]

  template_body = <<EOF
{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "WafAssociation": {
      "Type": "AWS::WAFv2::WebACLAssociation",
      "Properties": {
        "ResourceArn": "${local.federated_apigw_arn}",
        "WebACLArn": "arn:aws:wafv2:${var.region}:${var.account_id}:regional/webacl/${local.wafv2.name}/${local.wafv2.id}"
      }
    }
  }
}
EOF
}