How do I resolve template validation or template format errors in CloudFormation?

9 minute read
0

I want to validate my AWS CloudFormation template to make sure I don’t have syntax errors.

Short description

Choose one of the following solutions based on the error message that you receive:

  • For "JSON not well-formed" or "YAML not well-formed" errors, see the Validate template syntax section.
  • For "Unresolved resource dependencies [XXXXXXXX] in the Resources block of the template" errors, see the Validate logical IDs and parameters section.
  • For "Unrecognized parameter type: XXXXXXXX" or "Invalid template parameter property 'XXXXXXXX'" errors, see the Validate parameter definitions section.
  • For "Every Condition member must be a string" errors, see the Confirm that Conditions is specified as a string section.
  • For "Unrecognized resource types: [XXXXXXXX]" errors, see the Verify the availability of your resource type section.
  • For "The [environmental resource] 'XXXXXXXX' does not exist" errors, see the Verify that your resource exists outside the stack, or validate dependencies for resources in the same stack section.
  • For "Invalid template property or properties [XXXXXXXX]" errors, see the Verify template properties section.
  • For "Invalid policy syntax" or "MalformedPolicy" errors, see the Verify policy syntax for any IAM policy related resources section.

Resolution

If you receive errors when you run AWS Command Line Interface (AWS CLI) commands, then see Troubleshoot AWS CLI errors. Also, make sure that you're using the most recent AWS CLI version.

Validate template syntax

To follow proper JSON or YAML syntax in your CloudFormation template, consider the following:

Validate logical IDs and parameters

Confirm that resource logical IDs and parameters are defined in your template.

In the following JSON and YAML templates, test is referenced for the ImageId property. However, neither template includes a resource logical ID nor a parameter named test. These templates return the following error: "Unresolved resource dependencies [test] in the Resources block of the template." For more information on resource definitions and their syntax, see Resources.

Example JSON (incorrect):

{
  "Resources" : {
    "EC2Instance01" : {
      "Type" : "AWS::EC2::Instance",
      "Properties" : {
        "ImageId" : {"Ref": "test"}
      }
    }
  }
}

Example YAML (incorrect):

Resources:
  EC2Instance01:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref test

To resolve this issue, add a resource logical ID that's named test. Or, create a parameter that's named test where the reference returns the ImageId value. The following example JSON and YAML templates include a parameter with the name test and ImageId as the value.

Example JSON (correct):

{
  "Parameters": {
     "test": {
         "Type": "String",
         "Default": "ami-xxx"
       }
  },
  "Resources" : {
    "EC2Instance01" : {
      "Type" : "AWS::EC2::Instance",
      "Properties" : {
        "ImageId" : {"Ref": "test"}
      }
    }
  }
}

Example YAML (correct):

Parameters:
  test:
    Type: String
    Default: ami-xxx
Resources:
  EC2Instance01:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: !Ref test

Validate parameter definitions

  1. Set Type to one of the following supported properties:
  2. In your CloudFormation template, verify that the parameters include only the following permitted properties. For more information on permitted properties, see Properties.
  3. In your CloudFormation template, confirm that the Parameters section doesn't contain any intrinsic functions.

In the following example JSON and YAML templates, the default value for ParameterC has the intrinsic function Fn::Sub. This intrinsic function causes the validation error: "Every Default member must be a string."

Example JSON (incorrect):

{
  "Parameters": {
    "ParameterA": {
      "Type": "String",
      "Default": "abc"
    },
    "ParameterB": {
      "Type": "String",
      "Default": "def"
    },
    "ParameterC": {
      "Type": "String",
      "Default": {
        "Fn::Sub": "${ParameterA}-${ParameterB}"
      }
    }
  },
  "Resources": {
    "MyS3Bucket": {
      "Type": "AWS::S3::Bucket",
      "Properties": {
        "BucketName": {
          "Ref": "ParameterC"
        }
      }
    }
  }
}

Example YAML (incorrect):

Parameters:
 ParameterA:
  Type: String
  Default: abc
 ParameterB:
  Type: String
  Default: def
 ParameterC:
  Type: String
  Default: !Sub '${ParameterA}-${ParameterB}'
Resources:
 MyS3Bucket:
  Type: 'AWS::S3::Bucket'
  Properties:
   BucketName: !Ref ParameterC

Confirm that Conditions is specified as a string

In your CloudFormation template, specify Conditions as a string.

The following example JSON and YAML templates specify the condition in the resource EC2RouteA as a list of strings instead of a single string. These templates result in the following validation error: "Every Condition member must be a string."

Example JSON (incorrect):

{
  "Conditions": {
    "ConditionA": {
      "Fn::Not": [
        {
          "Fn::Equals": [
            "",
            "Sample"
          ]
        }
      ]
    },
    "ConditionB": {
      "Fn::Not": [
        {
          "Fn::Equals": [
            "",
            "Sample"
          ]
        }
      ]
    }
  },
  "Resources": {
    "EC2RouteA": {
      "Type": "AWS::EC2::Route",
      "Condition": [
        "ConditionA",
        "ConditionB"
      ],
      "Properties": {
       ...
      }
    }
  }
}

Example YAML (incorrect):

Conditions:
 ConditionA: !Not 
  - !Equals 
   - ''
   - Sample
 ConditionB: !Not 
  - !Equals 
   - ''
   - Sample
Resources:
  EC2RouteA:
  Type: 'AWS::EC2::Route'
  Condition:
   - ConditionA
   - ConditionB
  Properties:

To resolve this error, add ConditionAandB to the Conditions section of your template, and then use ConditionAandB as the condition for the EC2RouteA resource. See the following example JSON and YAML templates.

Example JSON (correct):

{
  "Conditions": {
    "ConditionA": {
      "Fn::Not": [
        {
          "Fn::Equals": [
            "",
            "Sample"
          ]
        }
      ]
    },
    "ConditionB": {
      "Fn::Not": [
        {
          "Fn::Equals": [
            "",
            "Sample"
          ]
        }
      ]
    },
    "ConditionAandB": {
      "Fn::And": [
        {
          "Condition": "ConditionA"
        },
        {
          "Condition": "ConditionB"
        }
      ]
    }
  },
  "Resources": {
    "EC2RouteA": {
      "Type": "AWS::EC2::Route",
      "Condition": "ConditionAandB",
      "Properties": {
        ...
      }
    }
  }
}

Example YAML (correct):

Conditions:
  ConditionA:
    Fn::Not:
    - Fn::Equals:
      - ''
      - Sample
  ConditionB:
    Fn::Not:
    - Fn::Equals:
      - ''
      - Sample
  ConditionAandB:
    Fn::And:
    - Condition: ConditionA
    - Condition: ConditionB
Resources:
  EC2RouteA:
    Type: AWS::EC2::Route
    Condition: ConditionAandB
    Properties:

Verify the availability of your resource type

1. Verify that your resource is available in your AWS Region.

Not all resource types are available in every AWS Region. Templates that include resource types that aren't available in your AWS Region result in the following error: "Unrecognized resource types: [XXXXXXXX]."

2. If your template consists of any serverless resources, then include a Transform declaration. See the following example JSON and YAML templates.

Example JSON:

{
    "Transform": "AWS::Serverless-2016-10-31", #Please make sure to include this.
    "Resources": {
        "MyServerlessFunctionLogicalID": {
            "Type": "AWS::Serverless::Function",
            "Properties": {
                "Handler": "index.handler",
                "Runtime": "nodejs8.10",
                "CodeUri": "s3://testBucket/mySourceCode.zip"
            }
        }
   }
}

Example YAML:

Transform: AWS::Serverless-2016-10-31 #Please make sure to include this.
Resources:
  MyServerlessFunctionLogicalID:
    Type: AWS::Serverless::Function
    Properties:
      Handler: index.handler
      Runtime: nodejs8.10
      CodeUri: 's3://testBucket/mySourceCode.zip'

Verify that your resource exists outside the stack, or validate dependencies for resources in the same stack

If you're hardcoding a resource or Amazon Resource Name (ARN) into one of your stack's resources for one that's outside of the CloudFormation stack, then verify the following:

  • The resource name or ARN is correct.
  • The resource exists.
  • The resource exists in the same AWS Region as the stack. Consider that some resources accept properties across AWS Regions or accounts.

For example, an AWS::EC2::Instance resource in your stack that specifies a security group (sg-1234567890) fails if:

  • The security group doesn't exist.
  • The security group doesn't exist in the stack's AWS Region.

As a result, you receive the error message: "The sg-1234567890 does not exist." See the following example:

LinuxInstance:
    Type: AWS::EC2::Instance
    Properties:
      SubnetId: !Ref ServerSubnetID 
      KeyName: !Ref EC2KeyPairName
      SecurityGroupIds: sg-1234567890 #<This resource must exist and be in the same AWS Region as the stack.>

Verify template properties

Use only permitted template properties in your CloudFormation template.

The following example JSON and YAML templates set the bucket resource on the same level as the Resources section. This returns the following error: "Template validation error: Invalid template property or properties [Bucket]." This error is caused when the CloudFormation template validator sees the bucket resource as a section-level specification. A section-level specification isn't allowed as a template property.

Example JSON (incorrect):

{
  "Resources": {
    "WaitCondition": {
      "Type": "AWS::CloudFormation::WaitCondition"
    }
  },  #<There is an extra '}' causing the Resources section to be closed off after the WaitCondition resource.>
  "Bucket": {
    "Type": "AWS::S3::Bucket",
    "Properties": {
      "Name": "BucketName"
    }
  }
}

Example YAML (incorrect):

Resources:
  WaitCondition:
    Type: AWS::CloudFormation::WaitCondition
Bucket: # <The spacing for the entire Bucket resource is incorrect and needs to be shifted 2 spaces to the right.>
  Type: AWS::S3::Bucket
  Properties:
    Name: BucketName

To resolve this issue, correct the formatting so that the bucket resource is specified inside the Resources section. See the following example JSON and YAML templates that are correctly formatted.

Example JSON (correct):

{
  "Resources": {
    "WaitCondition": {
      "Type": "AWS::CloudFormation::WaitCondition"
    },
    "Bucket": {
      "Type": "AWS::S3::Bucket",
      "Properties": {
        "Name": "BucketName"
      }
    }
  }
}

Example YAML (correct):

Resources:
  WaitCondition:
    Type: 'AWS::CloudFormation::WaitCondition'
  Bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
      Name: BucketName

Verify policy syntax for any IAM policy-related resources

If you're creating an Identity and Access Management (IAM) policy resource or related configuration in your resource properties, verify that the policy is valid with this structure base.

{  
    "Resources": {  
        "Policy": {  
            "Type": "AWS::IAM::Policy",  
            "Properties": {  
                "PolicyName": "IamPolicyName",  
                "PolicyDocument": {  
                    "Version": "2012-10-17",  
                    "Statement": [  
                        {  
                            "Effect": "effect",  
                            "Action": [  
                                "<service>:<API_action>",  
                                "<...>"  
                            ],  
                            "Resource": "desiredResourceARN",  
                            "Condition": {  
                                "ConditionConfiguration": {  
                                    "conditionKey": [  
                                        "values"  
                                    ]  
                                },  
                                "ConditionConfiguration2": "<...>"  
                            }  
                        }  
                    ]  
                }  
            }  
        }  
    }  
}

Note: Replace <service> with a service name of your choice. Replace <APIaction> with the API action for your selected service. For more information, see IAM JSON policy.

Integrate your JSON policy document with a YAML format

You might want to integrate a JSON policy document with a YAML format template for provisioning CloudFormation. This requires you to change how the document appears in the template.

After integration, the policy elements look similar to what's shown below:

Resources:  
  Policy:  
    Type: 'AWS::IAM::Policy'  
    Properties:  
      PolicyName: IamPolicyName  
      PolicyDocument:  
        Version: 2012-10-17  
        Statement:  
          - Effect: effect  
            Action:  
              - '<service>:<API_action>'  
              - <...>  
            Resource: desiredResourceARN  
            Condition:  
              ConditionConfiguration:  
                conditionKey:  
                  - values  
              ConditionConfiguration2: <...>
AWS OFFICIAL
AWS OFFICIALUpdated 2 months ago
No comments