Cloudformation 模板验证错误?
Cloudformation Template validation error?
我收到跟随错误,但不知道它来自哪里,希望有人能提供帮助。
Template validation error: Template format error: Any Properties member must be a JSON object.
cloudformation 脚本
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The AWS CloudFormation template for this Serverless application's resources outside of Lambdas and Api Gateway",
"Resources": {
"KMSKey": {
"Type": "AWS::KMS::Key",
"Properties": {
"Description": "KMS Key Dev",
"Enabled": "True",
"EnableKeyRotation": "True",
"KeyPolicy": {
"Version": "2012-10-17",
"Id": "key-default-1",
"Statement": {
"Effect": "Allow",
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
}
}
}
},
"IamRoleLambda": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "*"
}
},
"IamPolicyLambda": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "dev-lambda",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:us-east-1:*"
},
{
"Effect": "Allow",
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": {
"Ref": "KMSKey"
}
},
{
"Effect": "Allow",
"Action": [
"ec2:CreateNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DetachNetworkInterface",
"ec2:DeleteNetworkInterface",
"elastiCache:*"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": [
"arn:aws:s3:::{domain.com}/",
"arn:aws:s3:::{domain.com}/Serverless/*"
]
}
]
},
"Roles": [
{
"Ref": "IamRoleLambda"
}
]
}
},
"RedisCluster": {
"Type": "AWS::ElastiCache::CacheCluster",
"Properties": {
"AutoMinorVersionUpgrade": "False",
"AZMode": "cross-az",
"CacheNodeType": "cache.m3.medium",
"VpcSecurityGroupIds": {
"Ref": "VpcSecurityGroup"
},
"ClusterName": "Dev",
"Engine": "redis",
"EngineVersion": "2.8",
"NumCacheNodes": "1",
"Tags": [
{
"Key": "CostCenter",
"Value": "0000000000000000"
},
{
"Key": "Application",
"Value": "Appname"
},
{
"Key": "Function",
"Value": "cache"
},
{
"Key": "Environment",
"Value": "dev"
}
]
}
},
"VpcSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "DEV VPC Security group form",
"SecurityGroupEgress": {
"Ref": "SecurityGroupEgress"
},
"SecurityGroupInress": {
"Ref": "SecurityGroupIngress"
},
"Tags": [
{
"Key": "CostCenter",
"Value": "0000000000000000"
},
{
"Key": "Application",
"Value": "Appname"
},
{
"Key": "Function",
"Value": "cache"
},
{
"Key": "Environment",
"Value": "dev"
}
],
"VpcId": "vpc-8c3113e2"
}
},
"SecurityGroupEgress": {
"Type": "AWS::EC2::SecurityGroupEgress",
"Properties": [
{
"CidrIp": "0.0.0.0/0",
"FromPort": "443",
"ToPort": "443",
"IpProtocol": "tcp"
},
{
"CidrIp": "0.0.0.0/0",
"FromPort": "80",
"ToPort": "80",
"IpProtocol": "tcp"
},
{
"DestinationSecurityGroupId": {
"Fn:GetAtt": [
"VpcSecurityGroup"
]
},
"FromPort": "6379",
"ToPort": "6379",
"IpProtocol": "tcp"
}
]
},
"SecurityGroupIngress": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": [
{
"CidrIp": "0.0.0.0/0",
"FromPort": "443",
"ToPort": "443",
"IpProtocol": "tcp"
},
{
"CidrIp": "0.0.0.0/0",
"FromPort": "80",
"ToPort": "80",
"IpProtocol": "tcp"
},
{
"DestinationSecurityGroupId": {
"Fn:GetAtt": [
"VpcSecurityGroup"
]
},
"FromPort": "6379",
"ToPort": "6379",
"IpProtocol": "tcp"
}
]
}
},
"Outputs": {
"IamRoleArnLambda": {
"Description": "ARN of the lambda IAM role",
"Value": {
"Fn::GetAtt": [
"IamRoleLambda",
"Arn"
]
}
}
}
}
错误说明 Properties 成员需要一个 JSON 对象。查看您的代码,您的两个 Properties 成员被定义为 JSON 数组。根本问题是 AWS::EC2::SecurityGroupIngress
and AWS::EC2::SecurityGroupEgress
资源定义了单个安全组规则,而您正试图在单个资源中定义多个规则。
我看到除了完全开放的端口 80 和 443 之外,您还试图为自定义端口 (6379) 自行引用安全组。如 documentation 中所述,这是使用 AWS::EC2::SecurityGroupEgress
和 AWS::EC2::SecurityGroupIngress
资源的正确用例:
Important
If you want to cross-reference two security groups in the ingress and egress rules of those security groups, use the AWS::EC2::SecurityGroupEgress
and AWS::EC2::SecurityGroupIngress
resources to define your rules. Do not use the embedded ingress and egress rules in the AWS::EC2::SecurityGroup
. If you do, it causes a circular dependency, which AWS CloudFormation doesn't allow.
要在不定义多个额外资源的情况下完成此操作,您可以保留完全开放的端口规则与资源内联(因为它们不会导致循环依赖),并且只需创建额外的 AWS::EC2::SecurityGroup[In|E]gress
资源您想要锁定到安全组的那些:
"VpcSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "DEV VPC Security group form",
"SecurityGroupEgress": [
{
"CidrIp": "0.0.0.0/0",
"FromPort": "443",
"ToPort": "443",
"IpProtocol": "tcp"
},
{
"CidrIp": "0.0.0.0/0",
"FromPort": "80",
"ToPort": "80",
"IpProtocol": "tcp"
}
],
"SecurityGroupIngress": [
{
"CidrIp": "0.0.0.0/0",
"FromPort": "443",
"ToPort": "443",
"IpProtocol": "tcp"
},
{
"CidrIp": "0.0.0.0/0",
"FromPort": "80",
"ToPort": "80",
"IpProtocol": "tcp"
}
],
"Tags": [
{
"Key": "CostCenter",
"Value": "0000000000000000"
},
{
"Key": "Application",
"Value": "Appname"
},
{
"Key": "Function",
"Value": "cache"
},
{
"Key": "Environment",
"Value": "dev"
}
],
"VpcId": "vpc-8c3113e2"
}
},
"SecurityGroupEgress": {
"Type": "AWS::EC2::SecurityGroupEgress",
"Properties": {
"DestinationSecurityGroupId": {
"Fn::GetAtt": [
"VpcSecurityGroup",
"GroupId"
]
},
"FromPort": "6379",
"ToPort": "6379",
"IpProtocol": "tcp"
}
},
"SecurityGroupIngress": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"SourceSecurityGroupId": {
"Fn::GetAtt": [
"VpcSecurityGroup",
"GroupId"
]
},
"FromPort": "6379",
"ToPort": "6379",
"IpProtocol": "tcp"
}
}
[...etc...]
您还需要确保注意 Fn::GetAtt 函数的拼写和语法,我已经在上面为您更正了。
我收到跟随错误,但不知道它来自哪里,希望有人能提供帮助。
Template validation error: Template format error: Any Properties member must be a JSON object.
cloudformation 脚本
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The AWS CloudFormation template for this Serverless application's resources outside of Lambdas and Api Gateway",
"Resources": {
"KMSKey": {
"Type": "AWS::KMS::Key",
"Properties": {
"Description": "KMS Key Dev",
"Enabled": "True",
"EnableKeyRotation": "True",
"KeyPolicy": {
"Version": "2012-10-17",
"Id": "key-default-1",
"Statement": {
"Effect": "Allow",
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
}
}
}
},
"IamRoleLambda": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "*"
}
},
"IamPolicyLambda": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "dev-lambda",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:us-east-1:*"
},
{
"Effect": "Allow",
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": {
"Ref": "KMSKey"
}
},
{
"Effect": "Allow",
"Action": [
"ec2:CreateNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DetachNetworkInterface",
"ec2:DeleteNetworkInterface",
"elastiCache:*"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": [
"arn:aws:s3:::{domain.com}/",
"arn:aws:s3:::{domain.com}/Serverless/*"
]
}
]
},
"Roles": [
{
"Ref": "IamRoleLambda"
}
]
}
},
"RedisCluster": {
"Type": "AWS::ElastiCache::CacheCluster",
"Properties": {
"AutoMinorVersionUpgrade": "False",
"AZMode": "cross-az",
"CacheNodeType": "cache.m3.medium",
"VpcSecurityGroupIds": {
"Ref": "VpcSecurityGroup"
},
"ClusterName": "Dev",
"Engine": "redis",
"EngineVersion": "2.8",
"NumCacheNodes": "1",
"Tags": [
{
"Key": "CostCenter",
"Value": "0000000000000000"
},
{
"Key": "Application",
"Value": "Appname"
},
{
"Key": "Function",
"Value": "cache"
},
{
"Key": "Environment",
"Value": "dev"
}
]
}
},
"VpcSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "DEV VPC Security group form",
"SecurityGroupEgress": {
"Ref": "SecurityGroupEgress"
},
"SecurityGroupInress": {
"Ref": "SecurityGroupIngress"
},
"Tags": [
{
"Key": "CostCenter",
"Value": "0000000000000000"
},
{
"Key": "Application",
"Value": "Appname"
},
{
"Key": "Function",
"Value": "cache"
},
{
"Key": "Environment",
"Value": "dev"
}
],
"VpcId": "vpc-8c3113e2"
}
},
"SecurityGroupEgress": {
"Type": "AWS::EC2::SecurityGroupEgress",
"Properties": [
{
"CidrIp": "0.0.0.0/0",
"FromPort": "443",
"ToPort": "443",
"IpProtocol": "tcp"
},
{
"CidrIp": "0.0.0.0/0",
"FromPort": "80",
"ToPort": "80",
"IpProtocol": "tcp"
},
{
"DestinationSecurityGroupId": {
"Fn:GetAtt": [
"VpcSecurityGroup"
]
},
"FromPort": "6379",
"ToPort": "6379",
"IpProtocol": "tcp"
}
]
},
"SecurityGroupIngress": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": [
{
"CidrIp": "0.0.0.0/0",
"FromPort": "443",
"ToPort": "443",
"IpProtocol": "tcp"
},
{
"CidrIp": "0.0.0.0/0",
"FromPort": "80",
"ToPort": "80",
"IpProtocol": "tcp"
},
{
"DestinationSecurityGroupId": {
"Fn:GetAtt": [
"VpcSecurityGroup"
]
},
"FromPort": "6379",
"ToPort": "6379",
"IpProtocol": "tcp"
}
]
}
},
"Outputs": {
"IamRoleArnLambda": {
"Description": "ARN of the lambda IAM role",
"Value": {
"Fn::GetAtt": [
"IamRoleLambda",
"Arn"
]
}
}
}
}
错误说明 Properties 成员需要一个 JSON 对象。查看您的代码,您的两个 Properties 成员被定义为 JSON 数组。根本问题是 AWS::EC2::SecurityGroupIngress
and AWS::EC2::SecurityGroupEgress
资源定义了单个安全组规则,而您正试图在单个资源中定义多个规则。
我看到除了完全开放的端口 80 和 443 之外,您还试图为自定义端口 (6379) 自行引用安全组。如 documentation 中所述,这是使用 AWS::EC2::SecurityGroupEgress
和 AWS::EC2::SecurityGroupIngress
资源的正确用例:
Important
If you want to cross-reference two security groups in the ingress and egress rules of those security groups, use the
AWS::EC2::SecurityGroupEgress
andAWS::EC2::SecurityGroupIngress
resources to define your rules. Do not use the embedded ingress and egress rules in theAWS::EC2::SecurityGroup
. If you do, it causes a circular dependency, which AWS CloudFormation doesn't allow.
要在不定义多个额外资源的情况下完成此操作,您可以保留完全开放的端口规则与资源内联(因为它们不会导致循环依赖),并且只需创建额外的 AWS::EC2::SecurityGroup[In|E]gress
资源您想要锁定到安全组的那些:
"VpcSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "DEV VPC Security group form",
"SecurityGroupEgress": [
{
"CidrIp": "0.0.0.0/0",
"FromPort": "443",
"ToPort": "443",
"IpProtocol": "tcp"
},
{
"CidrIp": "0.0.0.0/0",
"FromPort": "80",
"ToPort": "80",
"IpProtocol": "tcp"
}
],
"SecurityGroupIngress": [
{
"CidrIp": "0.0.0.0/0",
"FromPort": "443",
"ToPort": "443",
"IpProtocol": "tcp"
},
{
"CidrIp": "0.0.0.0/0",
"FromPort": "80",
"ToPort": "80",
"IpProtocol": "tcp"
}
],
"Tags": [
{
"Key": "CostCenter",
"Value": "0000000000000000"
},
{
"Key": "Application",
"Value": "Appname"
},
{
"Key": "Function",
"Value": "cache"
},
{
"Key": "Environment",
"Value": "dev"
}
],
"VpcId": "vpc-8c3113e2"
}
},
"SecurityGroupEgress": {
"Type": "AWS::EC2::SecurityGroupEgress",
"Properties": {
"DestinationSecurityGroupId": {
"Fn::GetAtt": [
"VpcSecurityGroup",
"GroupId"
]
},
"FromPort": "6379",
"ToPort": "6379",
"IpProtocol": "tcp"
}
},
"SecurityGroupIngress": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
"SourceSecurityGroupId": {
"Fn::GetAtt": [
"VpcSecurityGroup",
"GroupId"
]
},
"FromPort": "6379",
"ToPort": "6379",
"IpProtocol": "tcp"
}
}
[...etc...]
您还需要确保注意 Fn::GetAtt 函数的拼写和语法,我已经在上面为您更正了。