Create IAM role only with managed cloudformation policy - aws-cloudformation

I am trying to create IAM role with existing maneged policy:
"SomeRole":
{
"Type": "AWS::IAM::Role",
"Properties":
{
"AssumeRolePolicyDocument": {},
"ManagedPolicyArns":
[
"arn:aws:iam::aws:policy/AmazonKinesisReadOnlyAccess",
"arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess",
"arn:aws:iam::aws:policy/CloudWatchFullAccess"
],
"RoleName": "SomeRole"
}
},
But it is failing with error: Syntax error at position (1,3)

Looks like you have to have some value in the AssumeRolePolicyDocument.
Try with this one.
{
"Resources": {
"NewRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"ec2.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"ManagedPolicyArns": [
"arn:aws:iam::aws:policy/AmazonKinesisReadOnlyAccess",
"arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess",
"arn:aws:iam::aws:policy/CloudWatchFullAccess"
]
}
}
}
}

Related

Error: At least one Resources member must be defined. when uploading template file CloudFormation to allow exterrnal DNS on EKS cluster

I'm getting the "Template format error: At least one Resources member must be defined." error when I try to upload a template file to cloudFormation to allow external DNS on my EKS cluster
the file I'm trying to upload is
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/*"
]
},
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:ListResourceRecordSets"
],
"Resource": [
"*"
]
}
]
}
Obviously I'm pretty new to this..can anybody give me a clue to where I am going wrong?
Your CloudFormation does not have Resources section which is required. Please check the proper format of a template.
The full code that fixed it was
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "The IAM Resources for External DNS",
"Parameters": {
"DeployRole": {
"Description": "Decide whether deploy or not the IAM Role",
"Type": "String",
"Default": "no",
"AllowedValues": [
"yes",
"no"
]
}
},
"Conditions": {
"CreateIamRole": { "Fn::Equals": [ { "Ref": "DeployRole" }, "yes"] }
},
"Resources": {
"ExternalDnsIamPolicy": {
"Type": "AWS::IAM::ManagedPolicy",
"Properties": {
"PolicyDocument" : {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:ChangeResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/*"
]
},
{
"Effect": "Allow",
"Action": [
"route53:ListHostedZones",
"route53:ListResourceRecordSets"
],
"Resource": [
"*"
]
}
]
},
"ManagedPolicyName" : "ExternalDNSPolicy"
}
}
}
}

destinationArn for vendor firehose cannot be used with roleArn when creating AWS::Logs::SubscriptionFilter via CloudFormation

My CloudFormation template that fails to create AWS::Logs::SubscriptionFilter resource:
{
"Resources": {
"Bucket83908E77": {
"Type": "AWS::S3::Bucket",
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
},
"MyFirehoseServiceRoleFD019CCC": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "firehose.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
}
},
"MyFirehoseS3DestinationRoleDE043A9B": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "firehose.amazonaws.com"
}
}
],
"Version": "2012-10-17"
}
}
},
"MyFirehoseS3DestinationRoleDefaultPolicyF2D4C970": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"s3:GetObject*",
"s3:GetBucket*",
"s3:List*",
"s3:DeleteObject*",
"s3:PutObject",
"s3:Abort*"
],
"Effect": "Allow",
"Resource": [
{
"Fn::GetAtt": [
"Bucket83908E77",
"Arn"
]
},
{
"Fn::Join": [
"",
[
{
"Fn::GetAtt": [
"Bucket83908E77",
"Arn"
]
},
"/*"
]
]
}
]
},
{
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Effect": "Allow",
"Resource": {
"Fn::GetAtt": [
"MyFirehoseLogGroupE92127AD",
"Arn"
]
}
}
],
"Version": "2012-10-17"
},
"PolicyName": "MyFirehoseS3DestinationRoleDefaultPolicyF2D4C970",
"Roles": [
{
"Ref": "MyFirehoseS3DestinationRoleDE043A9B"
}
]
}
},
"MyFirehoseLogGroupE92127AD": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"RetentionInDays": 731
},
"UpdateReplacePolicy": "Retain",
"DeletionPolicy": "Retain"
},
"MyFirehoseLogGroupS3Destination06C9B080": {
"Type": "AWS::Logs::LogStream",
"Properties": {
"LogGroupName": {
"Ref": "MyFirehoseLogGroupE92127AD"
}
},
"UpdateReplacePolicy": "Retain",
"DeletionPolicy": "Retain"
},
"MyFirehoseFCA2F9D3": {
"Type": "AWS::KinesisFirehose::DeliveryStream",
"Properties": {
"DeliveryStreamType": "DirectPut",
"ExtendedS3DestinationConfiguration": {
"BucketARN": {
"Fn::GetAtt": [
"Bucket83908E77",
"Arn"
]
},
"CloudWatchLoggingOptions": {
"Enabled": true,
"LogGroupName": {
"Ref": "MyFirehoseLogGroupE92127AD"
},
"LogStreamName": {
"Ref": "MyFirehoseLogGroupS3Destination06C9B080"
}
},
"RoleARN": {
"Fn::GetAtt": [
"MyFirehoseS3DestinationRoleDE043A9B",
"Arn"
]
}
}
},
"DependsOn": [
"MyFirehoseS3DestinationRoleDefaultPolicyF2D4C970"
]
},
"MyFirehoseCloudWatchLogsCanPutRecordsIntoKinesisFirehose30DECEBA": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": {
"Fn::Join": [
"",
[
"logs.",
{
"Ref": "AWS::Region"
},
".amazonaws.com"
]
]
}
}
}
],
"Version": "2012-10-17"
}
}
},
"MyFirehoseCloudWatchLogsCanPutRecordsIntoKinesisFirehoseDefaultPolicyF5730531": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"firehose:PutRecord",
"firehose:PutRecordBatch"
],
"Effect": "Allow",
"Resource": {
"Fn::GetAtt": [
"MyFirehoseFCA2F9D3",
"Arn"
]
}
}
],
"Version": "2012-10-17"
},
"PolicyName": "MyFirehoseCloudWatchLogsCanPutRecordsIntoKinesisFirehoseDefaultPolicyF5730531",
"Roles": [
{
"Ref": "MyFirehoseCloudWatchLogsCanPutRecordsIntoKinesisFirehose30DECEBA"
}
]
}
},
"LogGroupF5B46931": {
"Type": "AWS::Logs::LogGroup",
"Properties": {
"RetentionInDays": 731
},
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
},
"Subscription391C9821": {
"Type": "AWS::Logs::SubscriptionFilter",
"Properties": {
"DestinationArn": {
"Fn::GetAtt": [
"MyFirehoseFCA2F9D3",
"Arn"
]
},
"FilterPattern": "",
"LogGroupName": {
"Ref": "LogGroupF5B46931"
},
"RoleArn": {
"Fn::GetAtt": [
"MyFirehoseCloudWatchLogsCanPutRecordsIntoKinesisFirehose30DECEBA",
"Arn"
]
}
}
}
}
}
Cryptic error message:
Subscription (Subscription391C9821) destinationArn for vendor firehose cannot be used with roleArn (Service: AWSLogs; Status Code: 400; Error Code: InvalidParameterException; Request ID: 0e598426-5fcb-4fde-b9d3-11b14c129eb6; Proxy: null)
Stack name is cdk-logs-destination-firehose-to-s3.
Apparently, there is a bug in CloudWatch Logs where destination ARNs that contain the string destination are rejected from creating a subscription.
Workaround is to remove the destination substring from the stack name.

AWS CloudFormation/API Gateway gives 'Invalid Resource identifier specified'

I have been trying to use CloudFormation to deploy to API Gateway, however, I constantly run into the same issue with my method resources. The stack deployments keep failing with 'Invalid Resource identifier specified'.
Here is my method resource from my CloudFormation template:
"UsersPut": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"ResourceId": "UsersResource",
"RestApiId": "MyApi",
"ApiKeyRequired": true,
"AuthorizationType": "NONE",
"HttpMethod": "PUT",
"Integration": {
"Type": "AWS_PROXY",
"IntegrationHttpMethod": "POST",
"Uri": {
"Fn::Join": ["", ["arn:aws:apigateway:", {
"Ref": "AWS::Region"
}, ":lambda:path/2015-03-31/functions/", {
"Fn::GetAtt": ["MyLambdaFunc", "Arn"]
}, "/invocations"]]
}
},
"MethodResponses": [{
"StatusCode": 200
}]
}
}
Is anyone able to help me figure out why this keeps failing the stack deployment?
UPDATE: I forgot to mention that I had also tried using references to add the resource ID, that also gave me the same error:
"UsersPut": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"ResourceId": {
"Ref": "UsersResource"
},
"RestApiId": "MyApi",
"ApiKeyRequired": true,
"AuthorizationType": "NONE",
"HttpMethod": "PUT",
"Integration": {
"Type": "AWS_PROXY",
"IntegrationHttpMethod": "POST",
"Uri": {
"Fn::Join": ["", ["arn:aws:apigateway:", {
"Ref": "AWS::Region"
}, ":lambda:path/2015-03-31/functions/", {
"Fn::GetAtt": ["MyLambdaFunc", "Arn"]
}, "/invocations"]]
}
},
"MethodResponses": [{
"StatusCode": 200
}]
}
}
Here is the full CloudFormation template:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"LambdaDynamoDBRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}]
},
"Path": "/",
"Policies": [{
"PolicyName": "DynamoReadWritePolicy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Sid": "1",
"Action": [
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:UpdateItem"
],
"Effect": "Allow",
"Resource": "*"
}, {
"Sid": "2",
"Resource": "*",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Effect": "Allow"
}]
}
}]
}
},
"MyFirstLambdaFn": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": "myfirstlambdafn",
"S3Key": "lambda_handler.py.zip"
},
"Description": "",
"FunctionName": "MyFirstLambdaFn",
"Handler": "lambda_function.lambda_handler",
"MemorySize": 512,
"Role": {
"Fn::GetAtt": [
"LambdaDynamoDBRole",
"Arn"
]
},
"Runtime": "python2.7",
"Timeout": 3
},
"DependsOn": "LambdaDynamoDBRole"
},
"MySecondLambdaFn": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": "mysecondlambdafn",
"S3Key": "lambda_handler.py.zip"
},
"Description": "",
"FunctionName": "MySecondLambdaFn",
"Handler": "lambda_function.lambda_handler",
"MemorySize": 512,
"Role": {
"Fn::GetAtt": [
"LambdaDynamoDBRole",
"Arn"
]
},
"Runtime": "python2.7",
"Timeout": 3
},
"DependsOn": "LambdaDynamoDBRole"
},
"MyApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Name": "Project Test API",
"Description": "Project Test API",
"FailOnWarnings": true
}
},
"FirstUserPropertyModel": {
"Type": "AWS::ApiGateway::Model",
"Properties": {
"ContentType": "application/json",
"Name": "FirstUserPropertyModel",
"RestApiId": {
"Ref": "MyApi"
},
"Schema": {
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "FirstUserPropertyModel",
"type": "object",
"properties": {
"Email": {
"type": "string"
}
}
}
}
},
"SecondUserPropertyModel": {
"Type": "AWS::ApiGateway::Model",
"Properties": {
"ContentType": "application/json",
"Name": "SecondUserPropertyModel",
"RestApiId": {
"Ref": "MyApi"
},
"Schema": {
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "SecondUserPropertyModel",
"type": "object",
"properties": {
"Name": {
"type": "string"
}
}
}
}
},
"ErrorCfn": {
"Type": "AWS::ApiGateway::Model",
"Properties": {
"ContentType": "application/json",
"Name": "ErrorCfn",
"RestApiId": {
"Ref": "MyApi"
},
"Schema": {
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Error Schema",
"type": "object",
"properties": {
"message": {
"type": "string"
}
}
}
}
},
"UsersResource": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"RestApiId": {
"Ref": "MyApi"
},
"ParentId": {
"Fn::GetAtt": ["MyApi", "RootResourceId"]
},
"PathPart": "users"
}
},
"UsersPost": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"ResourceId": {
"Ref": "UsersResource"
},
"RestApiId": "MyApi",
"ApiKeyRequired": true,
"AuthorizationType": "NONE",
"HttpMethod": "POST",
"Integration": {
"Type": "AWS_PROXY",
"IntegrationHttpMethod": "POST",
"Uri": {
"Fn::Join": ["", ["arn:aws:apigateway:", {
"Ref": "AWS::Region"
}, ":lambda:path/2015-03-31/functions/", {
"Fn::GetAtt": ["MyFirstLambdaFn", "Arn"]
}, "/invocations"]]
}
},
"MethodResponses": [{
"ResponseModels": {
"application/json": {
"Ref": "FirstUserPropertyModel"
}
},
"StatusCode": 200
}, {
"ResponseModels": {
"application/json": {
"Ref": "ErrorCfn"
}
},
"StatusCode": 404
}, {
"ResponseModels": {
"application/json": {
"Ref": "ErrorCfn"
}
},
"StatusCode": 500
}]
}
},
"UsersPut": {
"Type": "AWS::ApiGateway::Method",
"Properties": {
"ResourceId": {
"Ref": "UsersResource"
},
"RestApiId": "MyApi",
"ApiKeyRequired": true,
"AuthorizationType": "NONE",
"HttpMethod": "PUT",
"Integration": {
"Type": "AWS_PROXY",
"IntegrationHttpMethod": "POST",
"Uri": {
"Fn::Join": ["", ["arn:aws:apigateway:", {
"Ref": "AWS::Region"
}, ":lambda:path/2015-03-31/functions/", {
"Fn::GetAtt": ["MySecondLambdaFn", "Arn"]
}, "/invocations"]]
}
},
"MethodResponses": [{
"ResponseModels": {
"application/json": {
"Ref": "SecondUserPropertyModel"
}
},
"StatusCode": 200
}, {
"ResponseModels": {
"application/json": {
"Ref": "ErrorCfn"
}
},
"StatusCode": 404
}, {
"ResponseModels": {
"application/json": {
"Ref": "ErrorCfn"
}
},
"StatusCode": 500
}]
}
},
"RestApiDeployment": {
"Type": "AWS::ApiGateway::Deployment",
"Properties": {
"RestApiId": {
"Ref": "MyApi"
},
"StageName": "Prod"
},
"DependsOn": ["UsersPost", "UsersPut"]
}
},
"Description": "Project description"
}
ResourceId must be a reference to a cloudformation resource, not a simple string.
e.g.
ResourceId:
Ref: UsersResource
I figured that actually it was the RestApiId which needed to be a reference too:
"RestApiId": {
"Ref": "MyApi"
},
When you create an API resource(1), a default root resource(2) for the API is created for path /. In order to get the id for the MyApi resource(1) root resource(2) use:
"ResourceId": {
"Fn::GetAtt": [
"MyApi",
"RootResourceId"
]
}
(1) The stack resource
(2) The API resource
Try
{
"$ref": "https://apigateway.amazonaws.com/restapis/YOUR_API_GATEWAY_IT/models/YOUR_MODEL_NAME"
}
In addition, you can also reference another model schema defined in an external model file by setting that model's URL as the value of the $ref property: "$ref": "https://apigateway.amazonaws.com/restapis/{restapi_id}/models/{model_name}".
See here for more details

Cloudformation Template validation error?

I am receiving the follow error but do not know where it is coming from, hopefully someone can help.
Template validation error: Template format error: Any Properties member must be a JSON object.
The cloudformation script
{
"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"
]
}
}
}
}
The error describes that the Properties member requires a JSON object. Looking at your code, two of your Properties members are defined as JSON arrays. The underlying issue is that AWS::EC2::SecurityGroupIngress and AWS::EC2::SecurityGroupEgress resources define a single security group rule, whereas you're attempting to define multiple rules within a single resource.
I see that you're trying to self-reference the security group for a custom port (6379), in addition to fully-open ports 80 and 443. As noted in the documentation, this is the correct use-case for using AWS::EC2::SecurityGroupEgress and AWS::EC2::SecurityGroupIngress resources:
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.
To accomplish this without defining several additional resources, you can leave the fully-open port rules inline with the resource (since they don't cause a circular dependency), and just create additional AWS::EC2::SecurityGroup[In|E]gress resources for the ones you want locked down to the security group:
"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...]
You'll also want to make sure to be careful with the spelling and syntax of the Fn::GetAtt function, which I've corrected above for you.

Using CloudFormation to configure CloudFront with an S3 origin

I am trying to use CloudFormation for the first time to configure a CloudFront distribution that uses an S3 bucket as its origin.
However I am receiving the error One or more of your origins do not exist when the template is run. I have assumed it is down to the origin DomainName being configured incorrectly, however have not been able to find a configuration that works.
I currently have the following template:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"AssetBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": "cdn-assets",
"AccessControl": "PublicRead",
"CorsConfiguration": {
"CorsRules": [
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET"
],
"AllowedOrigins": [
"*"
],
"Id": "OpenCors",
"MaxAge": "3600"
}
]
}
}
},
"AssetCDN": {
"Type": "AWS::CloudFront::Distribution",
"Properties": {
"DistributionConfig": {
"Origins": [
{
"DomainName": {
"Fn::GetAtt": [
"AssetBucket",
"DomainName"
]
},
"Id": "AssetBucketOrigin",
"S3OriginConfig": {}
}
],
"Enabled": "true",
"DefaultCacheBehavior": {
"Compress": true,
"AllowedMethods": [
"GET",
"HEAD",
"OPTIONS"
],
"TargetOriginId": "origin-access-identity/cloudfront/AssetCDN",
"ForwardedValues": {
"QueryString": "false",
"Cookies": {
"Forward": "none"
}
},
"ViewerProtocolPolicy": "allow-all"
},
"PriceClass": "PriceClass_All",
"ViewerCertificate": {
"CloudFrontDefaultCertificate": "true"
}
}
},
"DependsOn": [
"AssetBucket"
]
}
}
}
I have not been able to find much advice on this, so hoping someone can point me in the right direction.
Your Cache Behavior's TargetOriginId property must match the value specified in the S3 Origin's Id property.
In your above example, TargetOriginId is origin-access-identity/cloudfront/AssetCDN while Id is AssetBucketOrigin, which is causing the error.
The real issue here is that Cloudfront have a dependency - S3 bucket. And so you should put this reference inside cloudfront object to let CFN know that first of all it should create S3 bucket. To do this you have to change your Origins.Id and DefaultCacheBehavior.TargetOriginId properties to Ref to your bucket config:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"AssetBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": "cdn-assets",
"AccessControl": "PublicRead",
"CorsConfiguration": {
"CorsRules": [
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET"
],
"AllowedOrigins": [
"*"
],
"Id": "OpenCors",
"MaxAge": "3600"
}
]
}
}
},
"AssetCDN": {
"Type": "AWS::CloudFront::Distribution",
"Properties": {
"DistributionConfig": {
"Origins": [
{
"DomainName": {
"Fn::GetAtt": [
"AssetBucket",
"DomainName"
]
},
"Id": { "Ref": "AssetBucket" }, /// HERE!!!!
"S3OriginConfig": {}
}
],
"Enabled": "true",
"DefaultCacheBehavior": {
"Compress": true,
"AllowedMethods": [
"GET",
"HEAD",
"OPTIONS"
],
"TargetOriginId": { "Ref": "AssetBucket" }, /// HERE!!!!
"ForwardedValues": {
"QueryString": "false",
"Cookies": {
"Forward": "none"
}
},
"ViewerProtocolPolicy": "allow-all"
},
"PriceClass": "PriceClass_All",
"ViewerCertificate": {
"CloudFrontDefaultCertificate": "true"
}
}
},
"DependsOn": [
"AssetBucket"
]
}
}
}