跳至内容

如何解决 CloudFormation 中的模板验证或模板格式错误?

5 分钟阅读
0

我想验证 AWS CloudFormation 模板以确保没有语法错误。

解决方法

**注意:**如果您在运行 AWS 命令行界面 (AWS CLI) 命令时收到错误,请参阅 AWS CLI 错误故障排除。此外,请确保您使用的是最新版本的 AWS CLI

根据您收到的错误消息完成以下任务。

"JSON not well-formed" 或 "YAML not well-formed" 错误

如果您未正确格式化 CloudFormation 模板,则会收到以下错误消息之一:

"JSON not well-formed"

"YAML not well-formed"

请务必遵循 CloudFormation 模板中的 JSON 或 YAML 语法最佳实践。要解决此错误,请执行以下操作:

"Unresolved resource dependencies [XXXXXXXX] in the Resources block of the template" 错误

如果您的 CloudFormation 模板未指定资源逻辑 ID 或参数,则会收到以下错误消息:

"Unresolved resource dependencies [test] in the Resources block of the template."。

要解决此错误,请指定资源逻辑 ID。或者,创建一个名为 test 的参数,其引用返回 ImageId 值。以下 JSON 和 YAML 模板示例包含一个名为 test 的参数,其值为 ImageId

JSON 示例:

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

YAML 示例:

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

"Unrecognized parameter type: XXXXXXXX" 或 "Invalid template parameter property 'XXXXXXXX'" 错误

如果您的 JSON 和 YAML 模板将 ParameterC 的默认值作为内置函数 Fn::Sub 包含在内,则会收到以下错误消息:

"Every Default member must be a string."

参数不支持内置函数。使用 Fn::Sub 函数指定 ParameterAParameterB 的值。要解决此错误,请移除 ParameterC

要移除 CloudFormation 模板中的 ParameterC,请完成以下步骤:

  1. 类型设置为以下支持的属性之一:字符串数字列表CommaDelimitedList
  2. 验证参数是否仅包含允许的属性
  3. 确认参数部分不包含任何内置函数

JSON 示例:

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

YAML 示例:

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

"Every Condition member must be a string" 错误

您的 JSON 和 YAML 模板可能将资源 EC2RouteA 中的条件指定为一系列字符串,而不是单个字符串。如果是,您会收到以下错误消息:

"Every Condition member must be a string."

要解决此错误,请将 ConditionAandB 添加到模板的条件部分。然后,使用 ConditionAandB 作为 EC2RouteA 资源的条件。

JSON 示例:

{
  "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": {
        ...
      }
    }
  }
}

YAML 示例:

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:

"Unrecognized resource types: [XXXXXXXX]" 错误

并非所有资源类型在每个 AWS 区域都可用。如果您的模板包含在您的区域中不可用的资源类型,则会收到以下错误消息:

"Unrecognized resource types: [XXXXXXXX]."

要解决此错误,请验证您的资源是否在您的区域可用。如果您的模板包含任何无服务器资源,则应包含一个转换声明。

JSON 示例:

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

YAML 示例:

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

"The [environmental resource] 'XXXXXXXX' does not exist" 错误

如果堆栈中的 AWS::EC2::Instance 资源指定了安全组,您会收到以下错误消息:

"The sg-1234567890 does not exist."

如果安全组不存在或堆栈所在区域中不存在安全组,则堆栈将失败。要解决此错误,请将 SecurityGroupIDs 添加到您的模板中。

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

如果您将资源或 Amazon 资源名称 (ARN) 硬编码为位于 CloudFormation 堆栈之外的堆栈资源,请验证以下内容:

  • 资源名称或 ARN 正确无误。
  • 该资源确实存在。
  • 该资源与堆栈位于同一 区域中。某些资源接受跨区域或跨账户的属性。

"Invalid template property or properties [XXXXXXXX]" 错误

如果您将存储桶资源设置为与 JSON 和 YAML 模板中的资源部分相同的层级,则会收到以下错误消息:

"Template validation error: Invalid template property or properties [Bucket]."

当 CloudFormation 模板验证器将存储桶资源识别为部分层级规范时,就会出现此错误。不允许将部分层级规范作为模板属性。最佳做法是在 CloudFormation 模板中仅使用允许的模板属性

要解决此错误,请在资源部分中指定存储桶资源。

JSON 示例:

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

**注意:**请将 BucketName 替换为您的存储桶名称。

YAML 示例:

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

**注意:**请将 BucketName 替换为您的存储桶名称。

"Invalid policy syntax" 或 "MalformedPolicy" 错误

当您创建身份策略、资源策略、服务控制策略或资源控制策略时,验证分为两个步骤。这些步骤包括 AWS Identity and Access Management (IAM) 验证和 CloudFormation 验证。

要验证策略,请创建您的策略,然后运行以下 AWS CLI 命令 validate-policy

➜  aws accessanalyzer validate-policy --policy-document file://policy-document.json --policy-type IDENTITY_POLICY

**注意:**请将 policy-document.json 替换为 JSON 文件的文件路径。

如果您运行 AWS CLI 命令 validate-policy,则会收到 "Invalid policy syntax" 或 "MalformedPolicy" 错误消息。要解决此问题,请将操作更改为 s3:DeleteObject,然后再次运行该命令。

JSON 示例:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyObjectDeletionForAllExceptRolePrefix",
      "Effect": "Deny",
      "Action": [
        "s3:DeleteObject",
        "s3:DeleteObjectVersion",
        "s3:PutLifecycleConfiguration"
      ],
      "Resource": ["arn:aws:s3:::BUCKET_NAME/*"]
    }
  ]
}

**注意:**请将 BUCKET_NAME 替换为您的存储桶名称。

将经过验证的策略添加到您的 CloudFormation 模板中,并指定参数或资源。

如果子函数引用的参数不在模板中,则会收到以下错误消息:

"An error occurred (ValidationError) when calling the ValidateTemplate operation: Template format error: Unresolved resource dependencies [Bucket] in the Resources block of the template"

要解决此错误,请将模板中的资源更新为 arn:aws:s3:::${BucketName}/*

JSON 示例:

{
  "Parameters": {
    "BucketName": {
      "Type": "String"
    },
    "RoleName": {
      "Type": "String"
    }
  },
  "Resources": {
    "ManagedPolicy": {
      "Type": "AWS::IAM::ManagedPolicy",
      "Properties": {
        "Roles": [
          {
            "Ref": "RoleName"
          }
        ],
        "PolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Sid": "DenyObjectDeletionForAllExceptRolePrefix",
              "Effect": "Deny",
              "Action": [
                "s3:DeleteObject",
                "s3:DeleteObjectVersion",
                "s3:PutLifecycleConfiguration"
              ],
              "Resource": [
                {
                  "Fn::Sub": "arn:aws:s3:::${BucketName}/*"
                }
              ]
            }
          ]
        }
      }
    }
  }
}

**注意:**请将 BucketName 替换为您的存储桶名称。

手动验证 IAM 策略相关资源的策略语法

要手动验证策略是否有效,请使用以下策略模板:

{  
    "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": "<...>"  
                            }  
                        }  
                    ]  
                }  
            }  
        }  
    }  
}

**注意:**请将 service 替换为您的服务名称,并将 API_action 替换为适用于您所选服务的 API 操作。有关详细信息,请参阅 IAM JSON 策略元素参考

将您的 JSON 策略文档与 YAML 格式模板集成

如果您将 JSON 策略文档与用于预置 CloudFormation 的 YAML 格式模板集成,则可以更改该文档在模板中的显示方式。这样可以避免 YAML 和 JSON 混合块。集成后,策略元素与以下示例模板类似:

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

**注意:**请将 IamPolicyName 替换为您的 IAM 策略名称。