Does anyone know what is wrong with my YAML? - yaml

I have recently started learning YAML to use with AWS CloudFormation. It is a part of a course I am doing. I have written my YAML but my stack gives something different to what is expected in the designer.
This is my YAML
Parameters:
EnvironmentName:
Description: An environment name that is prefixed to resource names
Type: String
Default: DE-Extract
VpcCIDR:
Description: Please enter the IP range (CIDR notation) for this VPC
Type: String
Default: 192.168.0.0/16
DataCenterPublicSubnetCIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
Type: String
Default: 192.168.10.0/24
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock:
Ref: VpcCIDR
EnableDnsSupport: 'true'
EnableDnsHostnames: 'true'
Tags:
- Key: Name
Value:
Ref: EnvironmentName
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value:
Ref: EnvironmentName
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: InternetGateway
VpcId:
Ref: VPC
DataCenterPublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: VPC
CidrBlock:
Ref: DataCenterPublicSubnetCIDR
AvailabilityZone: !Select [0, !GetAZs '']
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: DE-Extract Data Center Subnet
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: VPC
Tags:
- Key: Name
Value: DE-Extract Public Routes
DefaultPublicRoute:
Type: AWS::EC2::Route
DependsOn: InternetGatewayAttachment
Properties:
RouteTableId:
Ref: PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: InternetGateway
DataCenterPublicSubnetRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId:
Ref: DataCenterPublicSubnet
RouteTableId:
Ref: PublicRouteTable
WindowsInstanceSG:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId:
Ref: VPC
GroupName: DE-Extract-WindowsInstanceSG
GroupDescription: This group permits RDP access to an instance deployed within the public subnet of the VPC.
SecurityGroupIngress:
- IpProtocol: tcp
CidrIp: 0.0.0/0
FromPort: 3389
ToPort: 3389
Tags:
- Key: Name
Value: DE-Extract-WindowsInstanceSG
FileServerSG:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId:
Ref: VPC
GroupName: DE-Extract-FileServerSG
GroupDescription: is responsible for permitting ssh access to the data center's file server from an internal source within the VPC.
SecurityGroupIngress:
- IpProtocol: tcp
CidrIp: 192.168.10.0/24
FromPort: 22
ToPort: 22
Tags:
Key: Name
Value: DE-Extract-FileServerSG
FileGatewaySG:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId:
Ref: VPC
GroupName: DE-Extract-FileGatewaySG
GroupDescription: This security group controls the access to the file gateway instance configured later on
SecurityGroupIngress:
- IpProtocol: tcp
CidrIp: 192.168.0.0/16
FromPort: 1
ToPort: 65534
This is what i am getting.
This is what i need
I am not too sure what is wrong, any form of direction would be much appreciated. I think theres an issue with the referencing (i was originally using !Ref and changed it to long form but nothng changed)

Related

AWS CloudFormation template not accepting bash script

Trying to put a bash script to install MongoDB on an EC2 via userdata. Im starting simple with this easy script before I do that one I am actually trying to do. I cannot even get the simple one to work. When I try and create the stack with the template below it gives me the error Invalid template property or properties [Properties]. Any ideas whats wrong with my userdata section?
AWSTemplateFormatVersion: 2010-09-09
Description: Launch EC2 via CloudFormation
Parameters:
KeyName:
Type: AWS::EC2::KeyPair::KeyName
Default: mongodb
AvailabilityZone:
Type: AWS::EC2::AvailabilityZone::Name
VpcCIDR:
Description: Please enter the IP range (CIDR notation) for this VPC
Type: String
Default: 10.0.0.0/16
PublicSubnetCIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
Type: String
Default: 10.0.0.0/24
PrivateSubnetCIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone
Type: String
Default: 10.0.2.0/24
EnvironmentName:
Description: An environment name that is prefixed to resource names
Type: String
Resources:
496Ec2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-04505e74c0741db8d # ImageID valid only in us-east-1 region
InstanceType: t2.micro
KeyName: !Ref KeyName
SecurityGroupIds:
- !Ref 496SecurityGroup
496SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Join ["-", [496-security-group, dev]]
GroupDescription: "Allow HTTP/HTTPS and SSH inbound and outbound traffic"
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Ref EnvironmentName
- Key: Env
Value: !Ref EnvironmentName
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Ref EnvironmentName
- Key: Env
Value: !Ref EnvironmentName
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 0, !GetAZs '' ]
CidrBlock: !Ref PublicSubnetCIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Subnet (AZ1)
- Key: Env
Value: !Ref EnvironmentName
PrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 0, !GetAZs '' ]
CidrBlock: !Ref PrivateSubnetCIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Subnet (AZ1)
- Key: Env
Value: !Ref EnvironmentName
DefaultPublicRoute:
Type: AWS::EC2::Route
DependsOn: InternetGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Routes
- Key: Env
Value: !Ref EnvironmentName
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Routes (AZ1)
- Key: Env
Value: !Ref EnvironmentName
DefaultPrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway
NatGatewayEIP:
Type: AWS::EC2::EIP
DependsOn: InternetGatewayAttachment
Properties:
Domain: vpc
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayEIP.AllocationId
SubnetId: !Ref PublicSubnet
Properties:
UserData: !Base64
Fn::Sub: |
#!/bin/bash
wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list
sudo apt-get update
sudo apt-get install -y mongodb-org
Your UserData is part of AWS::EC2::Instance. It is not a separate resource. Thus it should be:
AWSTemplateFormatVersion: 2010-09-09
Description: Launch EC2 via CloudFormation
Parameters:
KeyName:
Type: AWS::EC2::KeyPair::KeyName
Default: mongodb
AvailabilityZone:
Type: AWS::EC2::AvailabilityZone::Name
VpcCIDR:
Description: Please enter the IP range (CIDR notation) for this VPC
Type: String
Default: 10.0.0.0/16
PublicSubnetCIDR:
Description: Please enter the IP range (CIDR notation) for the public subnet in the first Availability Zone
Type: String
Default: 10.0.0.0/24
PrivateSubnetCIDR:
Description: Please enter the IP range (CIDR notation) for the private subnet in the first Availability Zone
Type: String
Default: 10.0.2.0/24
EnvironmentName:
Description: An environment name that is prefixed to resource names
Type: String
Resources:
496Ec2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-04505e74c0741db8d # ImageID valid only in us-east-1 region
InstanceType: t2.micro
KeyName: !Ref KeyName
SecurityGroupIds:
- !Ref 496SecurityGroup
UserData: !Base64
Fn::Sub: |
#!/bin/bash
wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list
sudo apt-get update
sudo apt-get install -y mongodb-org
496SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Join ["-", [496-security-group, dev]]
GroupDescription: "Allow HTTP/HTTPS and SSH inbound and outbound traffic"
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Ref EnvironmentName
- Key: Env
Value: !Ref EnvironmentName
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Ref EnvironmentName
- Key: Env
Value: !Ref EnvironmentName
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
PublicSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 0, !GetAZs '' ]
CidrBlock: !Ref PublicSubnetCIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Subnet (AZ1)
- Key: Env
Value: !Ref EnvironmentName
PrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 0, !GetAZs '' ]
CidrBlock: !Ref PrivateSubnetCIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Subnet (AZ1)
- Key: Env
Value: !Ref EnvironmentName
DefaultPublicRoute:
Type: AWS::EC2::Route
DependsOn: InternetGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Routes
- Key: Env
Value: !Ref EnvironmentName
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Routes (AZ1)
- Key: Env
Value: !Ref EnvironmentName
DefaultPrivateRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway
NatGatewayEIP:
Type: AWS::EC2::EIP
DependsOn: InternetGatewayAttachment
Properties:
Domain: vpc
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayEIP.AllocationId
SubnetId: !Ref PublicSubnet

How to update a file application.properties in EC2 instance from an external file (e.g from S3 bucket) using CloudFormation script?

I can update the application.properties and restart the service using the following CloudFormation template. But I want to update the application.properties file from an external file (e.g: S3 or git) instead of a script.
How can I achieve this?
My CF template,
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS CloudFormation Template with EC2InstanceWithSecurityGroup
Parameters:
KeyName:
Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
Type: AWS::EC2::KeyPair::KeyName
ConstraintDescription: must be the name of an existing EC2 KeyPair.
InstanceType:
Description: EC2 instance type
Type: String
Default: t2.medium
AllowedValues:
- t2.medium
- t2.large
ConstraintDescription: must be a valid EC2 instance type.
RemoteAccessLocation:
Description: The IP address range that can be used to access to the EC2 instances
Type: String
MinLength: '9'
MaxLength: '18'
Default: 0.0.0.0/0
AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
Resources:
S3Bucket:
Type: 'AWS::S3::Bucket'
DeletionPolicy: Retain
Properties:
BucketName: my-test-bucket
AccessControl: Private
EC2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref 'InstanceType'
SecurityGroups:
- !Ref 'InstanceSecurityGroup'
KeyName: !Ref 'KeyName'
ImageId: ami-xxxxxxxxxxxxxxxx
UserData:
Fn::Base64: !Sub |
#!/bin/bash -ex
cat >/usr/local/application.properties <<EOL
amazon.s3.bucket-name=${S3Bucket}
amazon.s3.region=ap-south-1
amazon.s3.access-key=xxxxxxxxxxxxxxxxxxx
amazon.s3.secret-key=yyyyyyyyyyyyyyyyxxxxxxxxx
## H2 Config
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=username
spring.datasource.password=password
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
EOL
## Restart our service
sudo systemctl restart myapplication.service
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Enable SSH (22), HTTP (8080)
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '22'
ToPort: '22'
CidrIp: !Ref 'RemoteAccessLocation'
- CidrIp: 0.0.0.0/0
FromPort: '8080'
IpProtocol: tcp
ToPort: '8080'
Outputs:
InstanceId:
Description: InstanceId of the newly created EC2 instance
Value: !Ref 'EC2Instance'
AZ:
Description: Availability Zone of the newly created EC2 instance
Value: !GetAtt 'EC2Instance.AvailabilityZone'
PublicDNS:
Description: Public DNSName of the newly created EC2 instance
Value: !GetAtt 'EC2Instance.PublicDnsName'
PublicIP:
Description: Public IP address of the newly created EC2 instance
Value: !GetAtt 'EC2Instance.PublicIp'
Any inputs here really appreciated.
You have to create AWS::IAM::InstanceProfile with AWS::IAM::Role that has read permissions to S3 or to a specific bucket/object. Then you use aws CLI in your user data to get the file from s3 into your instance. I don't know what is your AMI, but if its standard Amazon Linux 2 or Ubuntu, it will have AWS CLI already installed.
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS CloudFormation Template with EC2InstanceWithSecurityGroup
Parameters:
KeyName:
Description: Name of an existing EC2 KeyPair to enable SSH access to the instance
Type: AWS::EC2::KeyPair::KeyName
ConstraintDescription: must be the name of an existing EC2 KeyPair.
InstanceType:
Description: EC2 instance type
Type: String
Default: t2.medium
AllowedValues:
- t2.medium
- t2.large
ConstraintDescription: must be a valid EC2 instance type.
RemoteAccessLocation:
Description: The IP address range that can be used to access to the EC2 instances
Type: String
MinLength: '9'
MaxLength: '18'
Default: 0.0.0.0/0
AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
Resources:
S3Bucket:
Type: 'AWS::S3::Bucket'
DeletionPolicy: Retain
Properties:
BucketName: my-test-bucket
AccessControl: Private
MyInstanceRole:
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/AmazonS3ReadOnlyAccess
Path: '/'
MyInstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref MyInstanceRole
EC2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref 'InstanceType'
SecurityGroups:
- !Ref 'InstanceSecurityGroup'
KeyName: !Ref 'KeyName'
ImageId: ami-xxxxxxxxxxxxxxxx
IamInstanceProfile: !Ref MyInstanceProfile
UserData:
Fn::Base64: !Sub |
#!/bin/bash -ex
aws s3 cp s3://<your-bucket-with-settings>/application.properties /usr/local/application.properties
## Restart our service
sudo systemctl restart myapplication.service
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Enable SSH (22), HTTP (8080)
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '22'
ToPort: '22'
CidrIp: !Ref 'RemoteAccessLocation'
- CidrIp: 0.0.0.0/0
FromPort: '8080'
IpProtocol: tcp
ToPort: '8080'
Outputs:
InstanceId:
Description: InstanceId of the newly created EC2 instance
Value: !Ref 'EC2Instance'
AZ:
Description: Availability Zone of the newly created EC2 instance
Value: !GetAtt 'EC2Instance.AvailabilityZone'
PublicDNS:
Description: Public DNSName of the newly created EC2 instance
Value: !GetAtt 'EC2Instance.PublicDnsName'
PublicIP:
Description: Public IP address of the newly created EC2 instance
Value: !GetAtt 'EC2Instance.PublicIp'

How to have a public APIG access a lambda inside a VPC?

I have a small web app deployed as an aws lambda that correctly operates when tested via the lambda management console. However running a test via the apig console yeilds this error:
Sun Jan 26 21:43:30 UTC 2020 : Execution failed due to configuration error: Invalid permissions on Lambda function
However the apig is provisioned with the execute permission:
apiGatewayRole:
DependsOn:
- squashApp
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- "apigateway.amazonaws.com"
Action: "sts:AssumeRole"
Path: "/"
ManagedPolicyArns:
- !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"
Policies:
- PolicyName: "API_Service_Role_Policy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Action: "lambda:InvokeFunction"
Resource: !GetAtt "squashApp.Arn"
Effect: "Allow"
lambdaApiGatewayInvoke:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt "squashApp.Arn"
Principal: "apigateway.amazonaws.com"
SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/*/*/"
Previously the permission was sufficient (The IAM policy is recently added) to permit the lambda invocation. The error started occuring after I moved the lambda inside a VPC.
squashApp:
Type: AWS::Lambda::Function
Properties:
Environment:
Variables:
GO_ENV: production
DB_HOST: !GetAtt "squashRDS.Endpoint.Address"
DB_PORT: !GetAtt "squashRDS.Endpoint.Port"
DB_USER_NAME: !Sub "${rdsUser}"
DB_USER_PASS: !Sub "${rdsPassword}"
Code:
S3Bucket: '${lambdaHandoffBucket}'
S3Key: !Sub 'functions/${lambdaVersion}/${lambdaHash}' # TODO make parameter
Handler: 'app'
Role: !GetAtt "squashLambdaRole.Arn"
Runtime: 'go1.x'
Timeout: 2
FunctionName: !Ref "lambdaFunctionName"
VpcConfig:
SecurityGroupIds:
- !Ref "lambdaSecurtiyGroup"
SubnetIds:
- !Ref "privateSubnet1"
- !Ref "privateSubnet2"
vpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.192.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
privateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref vpc
CidrBlock: 10.192.21.0/24
MapPublicIpOnLaunch: false
AvailabilityZone: !Ref "PrimaryAZ"
Tags:
- Key: Name
Value: !Sub ${apiGatewayStageName} Private Subnet (AZ1)
privateSubnet2:
Type: "AWS::EC2::Subnet"
Properties:
VpcId: !Ref vpc
CidrBlock: 10.192.30.0/24
MapPublicIpOnLaunch: false
AvailabilityZone: !Ref "SecondaryAZ"
privateRouteTable1:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref vpc
privateSubnetRouteTableAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref privateRouteTable1
SubnetId: !Ref privateSubnet1
privateRouteTable2:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref vpc
privateSubnetRouteTableAssociation2:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref privateRouteTable1
SubnetId: !Ref privateSubnet1
noIngressSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: "no-ingress-sg"
GroupDescription: "Security group with no ingress rule"
VpcId: !Ref vpc
The full cloud formation resource section:
Resources:
apiGateway:
Type: "AWS::ApiGateway::RestApi"
Properties:
Name: "SquashAPI"
Description: "Squash Box Ladder"
apiGatewayRootMethod:
Type: "AWS::ApiGateway::Method"
Properties:
AuthorizationType: "NONE"
# This can be ANY | GET| POST | etc and references the api http method as seen by a client
HttpMethod: "ANY"
Integration:
# This must be post or the integration between gateway and lambda fails
IntegrationHttpMethod: "POST"
Type: "AWS_PROXY"
Uri: !Sub
- "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations"
- lambdaArn: !GetAtt "squashApp.Arn"
ResourceId: !GetAtt "apiGateway.RootResourceId"
RestApiId: !Ref "apiGateway"
apiGatewayCatchAllProxy:
Type: AWS::ApiGateway::Resource
Properties:
PathPart: "{proxy+}"
RestApiId: !Ref "apiGateway"
ParentId: !GetAtt "apiGateway.RootResourceId"
apiGatewayCatchAllMethod:
Type: "AWS::ApiGateway::Method"
Properties:
AuthorizationType: "NONE"
HttpMethod: "ANY"
Integration:
# This must be post or the integration between gateway and lambda fails
IntegrationHttpMethod: "POST"
Type: "AWS_PROXY"
Uri: !Sub
- "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations"
- lambdaArn: !GetAtt "squashApp.Arn"
ResourceId: !Ref "apiGatewayCatchAllProxy"
RestApiId: !Ref "apiGateway"
apiGatewayDeployment:
Type: "AWS::ApiGateway::Deployment"
DependsOn:
- "apiGatewayRootMethod"
- "apiGatewayCatchAllMethod"
Properties:
RestApiId: !Ref "apiGateway"
StageName: !Ref "apiGatewayStageName"
squashApp:
Type: AWS::Lambda::Function
Properties:
Environment:
Variables:
GO_ENV: production
DB_HOST: !GetAtt "squashRDS.Endpoint.Address"
DB_PORT: !GetAtt "squashRDS.Endpoint.Port"
DB_USER_NAME: !Sub "${rdsUser}"
DB_USER_PASS: !Sub "${rdsPassword}"
Code:
S3Bucket: '${lambdaHandoffBucket}'
S3Key: !Sub 'functions/${lambdaVersion}/${lambdaHash}' # TODO make parameter
Handler: 'app'
Role: !GetAtt "squashLambdaRole.Arn"
Runtime: 'go1.x'
Timeout: 2
FunctionName: !Ref "lambdaFunctionName"
VpcConfig:
SecurityGroupIds:
- !Ref "lambdaSecurtiyGroup"
SubnetIds:
- !Ref "privateSubnet1"
- !Ref "privateSubnet2"
lambdaSecurtiyGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
GroupDescription: For Lambda Application
VpcId: !Ref vpc
lambdaEgres:
Type: AWS::EC2::SecurityGroupEgress
Properties:
GroupId: !Ref lambdaSecurtiyGroup
IpProtocol: tcp
FromPort: !GetAtt "squashRDS.Endpoint.Port"
ToPort: !GetAtt "squashRDS.Endpoint.Port"
CidrIp: !GetAtt 'vpc.CidrBlock'
lambdaApiGatewayInvoke:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt "squashApp.Arn"
Principal: "apigateway.amazonaws.com"
SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/*/*/"
squashLambdaRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- "sts:AssumeRole"
Effect: "Allow"
Principal:
Service:
- "lambda.amazonaws.com"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
Policies:
- PolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- "logs:CreateLogGroup"
- "logs:CreateLogStream"
- "logs:PutLogEvents"
Effect: "Allow"
Resource:
- !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${lambdaFunctionName}:*"
PolicyName: "lambda"
lambdaLogGroup:
Type: "AWS::Logs::LogGroup"
Properties:
LogGroupName: !Sub "/aws/lambda/${lambdaFunctionName}"
RetentionInDays: 14
apiGatewayRole:
DependsOn:
- squashApp
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- "apigateway.amazonaws.com"
Action: "sts:AssumeRole"
Path: "/"
ManagedPolicyArns:
- !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"
Policies:
- PolicyName: "API_Service_Role_Policy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Action: "lambda:InvokeFunction"
Resource: !GetAtt "squashApp.Arn"
Effect: "Allow"
apiGwAccountConfig:
Type: "AWS::ApiGateway::Account"
Properties:
CloudWatchRoleArn: !GetAtt "apiGatewayRole.Arn"
squashRDS:
Type: AWS::RDS::DBInstance
Properties:
DBInstanceClass: db.t2.micro
AllocatedStorage: 20
StorageType: "gp2"
Engine: "postgres"
MasterUsername: !Sub "${rdsUser}"
MasterUserPassword: !Sub "${rdsPassword}"
DBSubnetGroupName: !Ref "rdsSubnetGroup"
VPCSecurityGroups:
- !Ref rdsSecurityGroup
DeletionPolicy: Snapshot
rdsSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: For RDS Instance
VpcId: !Ref vpc
Tags:
- Key: Name
Value: RDS-SecurityGroup
rdsSubnetGroup:
Type: "AWS::RDS::DBSubnetGroup"
Properties:
DBSubnetGroupName: "RDS Subnet Group"
DBSubnetGroupDescription: Subnet including the RDS into the VPC
SubnetIds:
- !Ref "privateSubnet1"
- !Ref "privateSubnet2"
rdsIngres:
Type: AWS::EC2::SecurityGroupIngress
Properties:
GroupId: !Ref rdsSecurityGroup
IpProtocol: tcp
FromPort: !GetAtt "squashRDS.Endpoint.Port"
ToPort: !GetAtt "squashRDS.Endpoint.Port"
CidrIp: !GetAtt 'vpc.CidrBlock'
vpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.192.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
privateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref vpc
CidrBlock: 10.192.21.0/24
MapPublicIpOnLaunch: false
AvailabilityZone: !Ref "PrimaryAZ"
privateSubnet2:
Type: "AWS::EC2::Subnet"
Properties:
VpcId: !Ref vpc
CidrBlock: 10.192.30.0/24
MapPublicIpOnLaunch: false
AvailabilityZone: !Ref "SecondaryAZ"
privateRouteTable1:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref vpc
privateSubnetRouteTableAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref privateRouteTable1
SubnetId: !Ref privateSubnet1
privateRouteTable2:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref vpc
privateSubnetRouteTableAssociation2:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref privateRouteTable1
SubnetId: !Ref privateSubnet1
noIngressSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: "no-ingress-sg"
GroupDescription: "Security group with no ingress rule"
VpcId: !Ref vpc
Outputs:
apiGatewayInvokeURL:
Value: !Sub "https://${apiGateway}.execute-api.${AWS::Region}.amazonaws.com/${apiGatewayStageName}"
lambdaArn:
Value: !GetAtt "squashApp.Arn"
In "squashLambdaRole", try adding "apigateway.amazonaws.com" in service principal list + attach a AWS managed policy named "AWSLambdaRole".
It solved my problem but I did not understand why :/
The only thing I can think of is, the API gateway source Arn should end with a resource path. In your case, it ends with a /.
I would add an * at the end to allow any resource path to invoke the lambda. You can change it to a specific path once you get it working.
lambdaApiGatewayInvoke:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt "squashApp.Arn"
Principal: "apigateway.amazonaws.com"
SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${apiGateway}/*/*/*"
hope this helps. good luck.

Getting Error : Circular dependency between resources

I'm getting circular dependency errors for my CloudFormation code:
Circular dependency between resources: [WebServerScaleDownPolicy,
WebServerScaleUpPolicy, LaunchConfig, ElasticLoadBalancer,
CPUAlarmHigh, MySecurityGroup, CPUAlarmLow, WebServerGroup]
Code File : https://drive.google.com/open?id=1SxDqc4oPRW0SgjtDg3eoVN_YE01iRLD1
I tried adding "DependsOn", but that doesn't help. I'm new to CloudFormation and looking for help.
AWSTemplateFormatVersion: '2010-09-09'
# this is the CloudFormation template deploys a Vpc
Resources:
VPC:
Type: 'AWS::EC2::VPC'
Properties:
CidrBlock: '10.0.0.0/16'
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: myWebsite-VPC
InternetGateway:
Type: 'AWS::EC2::InternetGateway'
Properties:
Tags:
- Key: Name
Value: myWebsite-IGW
VPCGatewayAttachment:
Type: 'AWS::EC2::VPCGatewayAttachment'
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
SubnetAPublic:
Type: 'AWS::EC2::Subnet'
Properties:
AvailabilityZone: us-east-1a
CidrBlock: '10.0.1.0/24'
MapPublicIpOnLaunch: Yes
VpcId: !Ref VPC
Tags:
- Key: name
Value: 'A public'
- Key: Reach
Value: Public
SubnetBPublic:
Type: 'AWS::EC2::Subnet'
Properties:
AvailabilityZone: us-east-1b
CidrBlock: '10.0.2.0/24'
MapPublicIpOnLaunch: Yes
VpcId: !Ref VPC
Tags:
- Key: Name
Value: 'B public'
- Key: Reach
Value: Public
RouteTablePublic:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: Public-routeTable
RouteTableAssociationAPublic:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
SubnetId: !Ref SubnetAPublic
RouteTableId: !Ref RouteTablePublic
RouteTableAssociationBPublic:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
SubnetId: !Ref SubnetBPublic
RouteTableId: !Ref RouteTablePublic
RouteTablePublicInternetRoute:
Type: 'AWS::EC2::Route'
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref RouteTablePublic
DestinationCidrBlock: '0.0.0.0/0'
GatewayId: !Ref InternetGateway
WebServerGroup:
Type: 'AWS::AutoScaling::AutoScalingGroup'
Properties:
AutoScalingGroupName: myASG
Cooldown: 200
DesiredCapacity: 2
LaunchConfigurationName: !Ref LaunchConfig
MaxSize: 6
MinSize: 2
LoadBalancerNames: [!Ref 'ElasticLoadBalancer']
HealthCheckGracePeriod: 300
Subnets:
- us-east-1a
- us-east-1b
LaunchConfig:
Type: AWS::AutoScaling::LaunchConfiguration
Metadata:
Comment: Install Apache
AWS::CloudFormation::Init:
config:
packages:
yum:
httpd: []
files:
/var/www/html/index.html:
content: "<html><h1>this is my webpage</h1></html>"
mode: '000644'
owner: root
group: root
services:
sysvinit:
httpd:
enabled: "true"
ensureRunning: "true"
Properties:
KeyName: MYEC2Keypair
SecurityGroup: !Ref MySecurityGroup
InstanceType: t2.micro
ImageId: ami-0b898040803850657
WebServerScaleUpPolicy:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AdjustmentType: ChangeInCapacity
AutoScalingGroupName: !Ref WebServerGroup
Cooldown: '60'
ScalingAdjustment: 1
WebServerScaleDownPolicy:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AdjustmentType: ChangeInCapacity
AutoScalingGroupName: !Ref WebServerGroup
Cooldown: '60'
ScalingAdjustment: -1
CPUAlarmHigh:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: Scale-up if CPU > 90% for 10 minutes
MetricName: CPUUtilization
Namespace: AWS/EC2
Statistic: Average
Period: 300
EvaluationPerioods: 2
Threshold: 90
AlarmActions: [!Ref 'WebServerScaleUpPolicy']
Dimensions:
- Name: AutoScalingGroupName
Value: !Ref WebServerGroup
ComparisonOperator: GreaterThanThreshold
CPUAlarmLow:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmDescription: Scale-down if CPU < 70% for 10 minutes
MetricName: CPUUtilization
Namespace: AWS/EC2
Statistic: Average
Period: 300
EvaluationPeriods: 2
Threshold: 70
AlarmActions: [!Ref 'WebServerScaleDownPolicy']
Dimensions:
- Name: AutoScalingGroupName
Value: !Ref WebServerGroup
ComparisonOperator: LessThanThreshold
ElasticLoadBalancer:
Type: 'AWS::ElasticLoadBalancing::LoadBalancer'
DependsOn: MySecurityGroup
Properties:
VpcId: !Ref VPC
CrossZone: 'true'
Listeners:
- LoadBalancerPort: '80'
InstancePort: '80'
Protocol: HTTP
SecurityGroup: !Ref MySecurityGroup
AvailabilityZones:
- us-east-1a
- us-east-1b
HealthCheck:
Target: HTTP:80/
HealthyThreshold: '3'
UnhealthyThreshold: '5'
Interval: '30'
Timeout: '5'
Tags:
- Key: Name
Value: MyELB
MySecurityGroup:
Type: AWS::EC2::SecruityGroup
Properties:
GroupDescription: Allow http and ssh only from LoadBalancer
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: '0.0.0.0/0'
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: '0.0.0.0/0'
SourceSecurityGroupOwnerId: !GetAtt [ElasticLoadBalancer, SourceSecurityGroup.OwnerAlias]
SourceSecurityGroupName: !GetAtt [ElasticLoadBalancer, SourceSecurityGroup.GroupName]
Tags:
- Key: Name
Value: MySecurityGroup
This is because your "ElasticLoadBalancer" resource depends on your security group "MySecurityGroup" and MySecurityGroup is referencing the Load Balancer in it's ingress rule, that's why there is a circular dependency.
You should define a separate security group for your load balancer and then in "MySecurityGroup" allow ssh and and http from that security group.
The CloudFormation Linter will warn about circular dependencies and more:
E3012 Property Resources/WebServerGroup/Properties/Cooldown should be of type String
~/Downloads/template.yml:76:7
E3012 Property Resources/WebServerGroup/Properties/DesiredCapacity should be of type String
~/Downloads/template.yml:77:7
E3012 Property Resources/WebServerGroup/Properties/MaxSize should be of type String
~/Downloads/template.yml:79:7
E3012 Property Resources/WebServerGroup/Properties/MinSize should be of type String
~/Downloads/template.yml:80:7
E3002 Invalid Property Resources/WebServerGroup/Properties/Subnets
~/Downloads/template.yml:83:7
E3002 Invalid Property Resources/LaunchConfig/Properties/SecurityGroup
~/Downloads/template.yml:108:7
E3003 Property EvaluationPeriods missing at Resources/CPUAlarmHigh/Properties
~/Downloads/template.yml:127:5
E3002 Invalid Property Resources/CPUAlarmHigh/Properties/EvaluationPerioods
~/Downloads/template.yml:133:7
E3004 Circular Dependencies for resource ElasticLoadBalancer. Circular dependency with [MySecurityGroup, ElasticLoadBalancer]
~/Downloads/template.yml:155:3
E3002 Invalid Property Resources/ElasticLoadBalancer/Properties/VpcId
~/Downloads/template.yml:159:7
E3012 Property Resources/ElasticLoadBalancer/Properties/CrossZone should be of type Boolean
~/Downloads/template.yml:160:7
E3002 Invalid Property Resources/ElasticLoadBalancer/Properties/SecurityGroup
~/Downloads/template.yml:165:7
E3002 Invalid Property Resources/ElasticLoadBalancer/Properties/HealthCheck/Tags
~/Downloads/template.yml:175:9
E3004 Circular Dependencies for resource MySecurityGroup. Circular dependency with [MySecurityGroup, ElasticLoadBalancer]
~/Downloads/template.yml:178:3
E3001 Invalid or unsupported Type AWS::EC2::SecruityGroup for resource MySecurityGroup in us-east-1
~/Downloads/template.yml:179:5
DependsOn won't solve circular dependencies.
Would it be possible to remove DependsOn: MySecurityGroup from ElasticLoadBalancer and choose the value of properties SourceSecurityGroupOwnerId and SourceSecurityGroupName in MySecurityGroup without depending on ElasticLoadBalancer? Those two properties may not be required if you'd rather not specify it at all for one of those properties.
Those options would solve one of the circular dependencies.

Cloud fomation: 2 EIPs, 2PIPs on one ENI

Getting "EIP will not stabilize" errors. Code is below... might be the code, or could be cloudformation bug.
I would like to attach 2 EIPs to the interface, one to the primary private IP and one to the secondary private IP. It works when I do it from the console.
I can also add 2 private IPs and a single EIP attached to either the primary or secondary private IP successfully if I comment out the 'VIP' or 'EIP' code. Eithe one works, but not both together.
#ServerOne.
ServerOne:
Type: AWS::EC2::Instance
Properties:
AvailabilityZone: !Ref AvailabilityZoneA
DisableApiTermination: !Ref disableInstanceDeletion
ImageId: !FindInMap [ RegionMap, !Ref "AWS::Region", ServerOne ]
InstanceType: !FindInMap [ InstanceSizingMap, !Ref StackSizing, ServerOne ]
EbsOptimized: !FindInMap [ InstanceSizingMap, !Ref StackSizing, ebsOptimizedInstances ]
BlockDeviceMappings:
- DeviceName: "/dev/sda1"
Ebs:
DeleteOnTermination: !FindInMap [ InstanceSizingMap, !Ref StackSizing, DeleteOnTermination ]
KeyName: !Ref SSHKeyName
Monitoring: 'false'
NetworkInterfaces:
-
NetworkInterfaceId: !Ref ServerOneInterface
DeviceIndex: 0
Tags:
- Key: Name
Value: ServerOne
- Key: Role
Value: Infrastructure
# ServerOne Server Network. 2 Private IPs, 2 EIPs all on one interface.
ServerOneEIP:
Type: AWS::EC2::EIP
DependsOn: IGW
Properties:
InstanceId: !Ref ServerOne
Domain: vpc
ServerOneVIP:
Type: AWS::EC2::EIP
DependsOn: IGW
Properties:
InstanceId: !Ref ServerOne
Domain: vpc
ServerOneEIPAssociation:
Type: AWS::EC2::EIPAssociation
DependsOn: ServerOneVIPAssociation
Properties:
AllocationId: !GetAtt ServerOneEIP.AllocationId
NetworkInterfaceId: !Ref ServerOneInterface
PrivateIpAddress: !GetAtt ServerOneInterface.PrimaryPrivateIpAddress
ServerOneVIPAssociation:
Type: AWS::EC2::EIPAssociation
DependsOn: IGW
Properties:
AllocationId: !GetAtt ServerOneVIP.AllocationId
NetworkInterfaceId: !Ref ServerOneInterface
PrivateIpAddress: !Select [ 0, !GetAtt ServerOneInterface.SecondaryPrivateIpAddresses ]
ServerOneInterface:
Type: AWS::EC2::NetworkInterface
Properties:
SubnetId: !Ref PublicSubnetA
SecondaryPrivateIpAddressCount: 1
Description: ServerOne Network Interface
GroupSet: [
!Ref PuppetClientSG ]
# ServerOne is doing NAT, so Source/Dest is false.
SourceDestCheck: false
Code is below.
---
Parameters:
Subnet:
Description: ID of the Subnet the instance should be launched in, this will
link the instance to the same VPC.
Type: List<AWS::EC2::Subnet::Id>
Resources:
EIP1:
Type: AWS::EC2::EIP
Properties:
Domain: VPC
EIP2:
Type: AWS::EC2::EIP
Properties:
Domain: VPC
Association1:
Type: AWS::EC2::EIPAssociation
DependsOn:
- ENI
- EIP1
Properties:
AllocationId:
Fn::GetAtt:
- EIP1
- AllocationId
NetworkInterfaceId:
Ref: ENI
PrivateIpAddress:
Fn::GetAtt:
- ENI
- PrimaryPrivateIpAddress
Association2:
Type: AWS::EC2::EIPAssociation
DependsOn:
- ENI
- EIP2
Properties:
AllocationId:
Fn::GetAtt:
- EIP2
- AllocationId
NetworkInterfaceId:
Ref: ENI
PrivateIpAddress:
Fn::Select:
- '0'
- Fn::GetAtt:
- ENI
- SecondaryPrivateIpAddresses
ENI:
Type: AWS::EC2::NetworkInterface
Properties:
SecondaryPrivateIpAddressCount: 1
SourceDestCheck: false
SubnetId:
Fn::Select:
- '0'
- Ref: Subnet
OpenVPN:
Type: AWS::EC2::Instance
DependsOn:
- ENI
Properties:
InstanceType: t2.micro
AvailabilityZone: us-east-2a
NetworkInterfaces:
- NetworkInterfaceId:
Ref: ENI
DeviceIndex: '0'
ImageId: ami-8a7859ef
KeyName: jimkey

Resources