如何解决 CloudFormation 中的模板验证或模板格式错误?
我想验证 AWS CloudFormation 模板以确保没有语法错误。
简短描述
请根据收到的错误消息从下列解决方案中选择一种:
- 对于“JSON not well-formed”或“YAML not well-formed”错误,请参阅验证模板语法部分。
- 对于“Unresolved resource dependencies [XXXXXXXX] in the Resources block of the template”错误,请参阅验证逻辑 ID 和参数部分。
- 对于“Unrecognized parameter type: XXXXXXXX”或“Invalid template parameter property 'XXXXXXXX'”错误,请参阅验证参数定义部分。
- 对于“Every Condition member must be a string”错误,请参阅确认已将“Conditions”指定为字符串部分。
- 对于“Unrecognized resource types: [XXXXXXXX]”错误,请参阅验证资源类型的可用性部分。
- 对于“The [environmental resource] 'XXXXXXXX' does not exist”错误,请参阅验证资源是否位于堆栈外,或验证同一堆栈中资源的依赖关系部分。
- 对于“Invalid template property or properties [XXXXXXXX]”错误,请参阅验证模板属性部分。
- 对于“Invalid policy syntax”或“MalformedPolicy”错误,请参阅验证 IAM 策略相关资源的策略语法部分。
解决方法
如果在运行 AWS 命令行界面(AWS CLI)命令时收到错误,请参阅排查 AWS CLI 错误。此外,确保您使用的是最新版本的 AWS CLI。
验证模板语法
要正确遵循 CloudFormation 模板中的 JSON 或 YAML 语法,请考虑以下几点:
- 使用 AWS CloudFormation Designer 创建堆栈。
- 使用文本编辑器或 AWS CLI 模板验证器等命令行工具验证 JSON 语法。
- 使用 aws cloudformation validate-template 命令验证 YAML 语法。
- 使用 GitHub 网站上的 AWS CloudFormation linter 验证 JSON 或 YAML 模板。
验证逻辑 ID 和参数
请确认您的模板中定义了资源逻辑 ID 和参数。
在以下 JSON 和 YAML 模板中,test 被引用为 ImageId 的属性。但是,这两个模板都不包含名为 test 的资源逻辑 ID 或参数。这些模板会返回以下错误: “Unresolved resource dependencies [test] in the Resources block of the template.” 有关资源定义及其语法的更多信息,请参阅资源。
示例 JSON(不正确):
{ "Resources" : { "EC2Instance01" : { "Type" : "AWS::EC2::Instance", "Properties" : { "ImageId" : {"Ref": "test"} } } } }
示例 YAML(不正确):
Resources: EC2Instance01: Type: AWS::EC2::Instance Properties: ImageId: !Ref test
要解决此问题,请添加名为 test 的资源逻辑 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
验证参数定义
- 将 Type 设置为以下任一支持的属性:
- String、Number、List 或 CommaDelimitedList
- AWS 特定的参数类型
- SSM 参数类型
- 在 CloudFormation 模板中,验证参数是否仅包含以下允许的属性。有关允许的属性的更多信息,请参阅属性。
- 在 CloudFormation 模板中,确认 Parameters 部分不包含任何内置函数。
在以下 JSON 和 YAML 模板示例中,ParameterC 的默认值具有内置函数 Fn::Sub。这个内置函数会导致验证错误: “Every Default member must be a string.”
示例 JSON(不正确):
{ "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" } } } } }
示例 YAML(不正确):
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
确认已将“Conditions”指定为字符串
在 CloudFormation 模板中,将 Conditions 指定为字符串。
以下示例 JSON 和 YAML 模板将资源 EC2RouteA 中的条件指定为一系列字符串,而不是单个字符串。这些模板会导致以下验证错误: “Every Condition member must be a string.”
示例 JSON(不正确):
{ "Conditions": { "ConditionA": { "Fn::Not": [ { "Fn::Equals": [ "", "Sample" ] } ] }, "ConditionB": { "Fn::Not": [ { "Fn::Equals": [ "", "Sample" ] } ] } }, "Resources": { "EC2RouteA": { "Type": "AWS::EC2::Route", "Condition": [ "ConditionA", "ConditionB" ], "Properties": { ... } } } }
示例 YAML(不正确):
Conditions: ConditionA: !Not - !Equals - '' - Sample ConditionB: !Not - !Equals - '' - Sample Resources: EC2RouteA: Type: 'AWS::EC2::Route' Condition: - ConditionA - ConditionB Properties:
要解决此错误,请将 ConditionAandB 添加到模板的 Conditions 部分,然后将 ConditionAandB 用作 EC2RouteA 资源的条件。请参阅以下 JSON 和 YAML 模板示例。
示例 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:
验证资源类型的可用性
1.验证您的资源在您的 AWS 区域可用。
并非所有资源类型在每个 AWS 区域都可用。如果模板中存在对您的 AWS 区域不可用的资源类型,会导致以下错误: “Unrecognized resource types: [XXXXXXXX].”
2.如果您的模板包含任何无服务器资源,则应包含一个转换声明。请参阅以下 JSON 和 YAML 模板示例。
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" } } } }
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'
验证资源是否位于堆栈外,或验证同一堆栈中资源的依赖关系
如果您将某资源或 Amazon 资源名称(ARN)硬编码为位于 CloudFormation 堆栈之外的堆栈资源,请验证以下内容:
- 资源名称或 ARN 正确无误。
- 该资源确实存在。
- 该资源与堆栈位于同一 AWS 区域中。注意某些资源接受跨 AWS 区域或账户的属性。
例如,在以下情况下,堆栈中指定安全组(sg-1234567890)的 AWS::EC2::Instance 资源会失败:
- 该安全组不存在。
- 堆栈的 AWS 区域中没有该安全组。
因此,您会收到错误消息: “The sg-1234567890 does not exist.” 请参阅以下示例:
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.>
验证模板属性
在 CloudFormation 模板中仅使用允许的模板属性。
以下示例 JSON 和 YAML 模板将存储桶资源的层级设置为与 Resources 部分的层级相同。此设置会返回以下错误: “Template validation error: Invalid template property or properties [Bucket].” 当 CloudFormation 模板验证器将存储桶资源视为部分层级规范时,会引发此错误。不允许将部分层级规范作为模板属性。
示例 JSON(不正确):
{ "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" } } }
示例 YAML(不正确):
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
要解决此问题,请更正相关格式,在 Resources 部分内指定存储桶资源。请参阅以下格式正确的 JSON 和 YAML 示例模板。
示例 JSON(正确):
{ "Resources": { "WaitCondition": { "Type": "AWS::CloudFormation::WaitCondition" }, "Bucket": { "Type": "AWS::S3::Bucket", "Properties": { "Name": "BucketName" } } } }
示例 YAML(正确):
Resources: WaitCondition: Type: 'AWS::CloudFormation::WaitCondition' Bucket: Type: 'AWS::S3::Bucket' Properties: Name: BucketName
验证 IAM 策略相关资源的策略语法
如果要在资源属性中创建 Identity and Access Management(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> 替换为您选择的服务名称。将 <APIaction> 替换为所选服务的 API 操作。有关详细信息,请参阅 IAM JSON policy。
将您的 JSON 策略文档与 YAML 格式集成
您可能希望将 JSON 策略文档与 YAML 格式模板相集成,用于配置 CloudFormation。为此,您需要根据模板修改文档。
集成后,策略元素与下图类似:
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: <...>