I have 2 stacks in CloudFormation. One is creating a vpc with a couple of subnets which are exported in order to be used in other stacks. The idea is to have those subnets to be used in other stacks.
The vpc stack exports the values properly but I am unable to Import them in the second stack because it uses a list of strings.
Stack 1:
PrivateSubnets:
Description: "A list of the public subnets"
Value: !Join [ ",", [ !Ref PrivateSubnet1, !Ref PrivateSubnet2 ]]
Export:
Name: !Sub "${StagingArea}-PrivateSubnets"
PublicSubnet1:
Description: "Reference to the publi subnet in the 1st Availability Zone"
Value: !Ref PublicSubnet1
PublicSubnet2:
Description: "A reference to the public subnet in the 2nd Availability Zone"
Value: !Ref PublicSubnet2
PrivateSubnet1:
Description: "A reference to the private subnet in the 1st Availability Zone"
Value: !Ref PrivateSubnet1
Export:
Name: !Sub "${StagingArea}-PrivateSubnet1"
PrivateSubnet2:
Description: "A reference to the private subnet in the 2nd Availability Zone"
Value: !Ref PrivateSubnet2
Export:
Name: !Sub "${StagingArea}-PrivateSubnet2"
When I try to ImportValue into my second stack it does not work. Stack 2 below:
DbSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: !Sub "${StagingArea} RDS DB Subnet Group"
SubnetIds:
- !ImportValue 'Fn::Sub': '{$StagingArea}-PrivateSubnet1'
- !ImportValue 'Fn::Sub': '{$StagingArea}-PrivateSubnet2'
Is it possible to get the values exported from the first stack into the second stack? I have tried various options but none of them seem to be working.
Sub is incorrect (wrong use of $) and its better to follow the docs and have the statement in two lines:
- Fn::ImportValue:
!Sub '${StagingArea}-PrivateSubnet1'
- Fn::ImportValue:
!Sub '${StagingArea}--PrivateSubnet2'
Related
I have a cloudformation script that configures a VPC and in the Outputs section it exports a few values - one is the Zone B AZ:
Parameters:
PublicAvailabilityZoneB:
Type: String
Default: us-east-1b
Outputs:
PublicAvailabilityZoneB:
Description: Pubic Subnet B Availability Zone
Value: !Ref PublicAvailabilityZoneB
Export:
Name: !Sub "${AWS::StackName}-${OwnerID}-${PublicAvailabilityZoneB}-PublicSubnetB-AZ"
In the console this is in the Outputs section:
PublicAvailabilityZoneB us-east-2b Pubic Subnet B Availability Zone Stack-02-Schwartz-us-east-2b-PublicSubnetB-AZ
I have a second CFN script that instantiates EC2 instances.
Parameters:
PublicAvailabilityZoneB:
Type: String
Default: us-east-1b
NetworkStackParameter:
Description: Parent stack
Type: String
Default: Stack-02
OwnerID:
Type: String
Default: Schwartz
Resources:
BastionInstance:
Type: 'AWS::EC2::Instance'
DependsOn:
- BastionInterface
Properties:
ImageId: !Ref LinuxAmi
InstanceType: c4.large
AvailabilityZone:
Fn::ImportValue: !Sub ${NetworkStackParameter}-${OwnerID}-${PublicAvailabilityZoneB}-PublicSubnetB-AZ
I am receiving this error when I run the second CFN script:
No export named ${NetworkStackParameter}-${OwnerID}-${PublicAvailabilityZoneB}-PublicSubnetB-AZ found.
What am I missing? I have triple checked the CFN script. Thanks.
Ugh, easy mistake. It should have had quotes
Fn::ImportValue: !Sub "${NetworkStackParameter}-${OwnerID}-${PublicAvailabilityZoneB}-PublicSubnetB-AZ"
I create 2 Subnets with Cloudformation, but both are created in the same ZONE. How can I create them in a separate zone? I don't want to give zone manually. I set it according to the zone I am in.
YAML file for Subnet1
Subnet1:
Type: AWS::EC2::Subnet
DependsOn: NginxVPC
Properties:
VpcId: !Ref NginxVPC
CidrBlock: !Ref Subnet1CidrBlock
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
Tags:
- Key: Name
Value: !Sub ${AWS::StackName}-Subnet1
Working on a CF example template and am attempting to place an EC2 instance into a subnet created from the same template. When doing things as is, I get this error:
The parameter groupName cannot be used with the parameter subnet
Here's a subset of the template:
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 172.34.0.0/16
EnableDnsHostnames: False
Tags:
Subnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: us-west-1a
CidrBlock: 172.34.0.0/24
VpcId:
Ref: VPC
MapPublicIpOnLaunch: False
WebServer1:
Type: AWS::EC2::Instance
Properties:
ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", AMI]
InstanceType: t2.micro
SubnetId:
Ref: Subnet1
SecurityGroups:
- Ref: ServerSecurityGroup
Tags:
- Key: "Name"
Value: "Tyler-Cloudformation"
How can I refer to Subnet 1 when creating WebServer1 and place it within that subnet? What am I missing here? Thanks in advance!
The error is probably because you are using SecurityGroups rather then SecurityGroupIds. The former parameter is only used for default-VPCs, while for non-default ones, the latter must be used.
Thus, instead of SecurityGroups you should have:
SecurityGroupIds:
- !GetAtt ServerSecurityGroup.GroupId
I have a CloudFormation template that creates a custom VPC.
The template creates the following resources - a VPC, an Internet Gateway, attaches the IGW to the VPC, and creates a Public Subnet.
I want to add a route (destination 0.0.0.0/0, target IGW) to the Route Table that gets created as part of the VPC.
I have read through the cloudformation documentation for routes, route tables to figure out how to do this, but to no avail.
I can use the Fn::Ref function to refer to resources or parameters that are explicitly created as part of the template, but how do I refer to resources that get created inherently with the VPC?
Any insights on how to re-use the existing route table, NACL and Security Group are much appreciated.
Thanks,
Good job so far - you have your internet gateway, route table, and a public subnet. Now you need to create the route and attach the route table to the subnet if you haven't already done so. If you're using YAML it might look something like this:
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Ref EnvironmentName
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 0, !GetAZs '' ]
CidrBlock: !Ref PublicSubnet1CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Subnet (AZ1)
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Routes
DefaultPublicRoute:
Type: AWS::EC2::Route
DependsOn: InternetGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet1
Don't use the default route table (see https://serverfault.com/questions/588904/aws-vpc-default-route-table-in-cloudformation)
You can get default security group as per https://serverfault.com/questions/544439/aws-cloudformation-vpc-default-security-group
And finally you can also get the DefaultNetworkAcl in the same as DefaultSecurityGroup above. See also https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpc.html)
CloudFormation beginner here. I've been researching and working on developing a CloudFormation template that will eventually be used as the starting point for a development environment for my team.
I've been picking at bits and pieces through some courses and examples online and have been relatively successful in my small attempt... Until tonight.
I am now trying to attach an Internet Gateway to my VPC and it is causing the Stack creation job to fail and rollback. The Internet Gateway will not attach and for the life of me I just cannot determine why.
My full template is here. The plan is to create a VPC with 2 public and 2 private subnets. There will be an Internet Gateway attached to the 2 public subnets. This is where the failure comes in. If I comment out the Internet Gateway creation, the template is successful. Thanks in advance for your help.
AWSTemplateFormatVersion: '2010-09-09'
Resources:
DevVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: 'true'
EnableDnsHostnames: 'true'
InstanceTenancy: default
Tags:
- Key: Name
Value: dev-vpc
DevRoute53HostedZone:
Type: "AWS::Route53::HostedZone"
Properties:
HostedZoneConfig:
Comment: "aws hosted dev environment"
Name: "mydomain.oregon-dev.local"
VPCs:
-
VPCId: !Ref DevVPC
VPCRegion: "us-west-2"
DevPublicSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref DevVPC
CidrBlock: 10.0.8.0/25
AvailabilityZone: "us-west-2a"
Tags:
- Key: Name
Value: DevPublicSubnetA
DevPublicSubnetB:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref DevVPC
CidrBlock: 10.0.8.128/25
AvailabilityZone: "us-west-2b"
Tags:
- Key: Name
Value: DevPublicSubnetB
DevPrivateSubnetA:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref DevVPC
CidrBlock: 10.0.9.0/25
AvailabilityZone: "us-west-2a"
Tags:
- Key: Name
Value: DevPrivateSubnetA
DevPrivateSubnetB:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref DevVPC
CidrBlock: 10.0.9.128/25
AvailabilityZone: "us-west-2b"
Tags:
- Key: Name
Value: DevPrivateSubnetB
RouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId:
Ref: DevVPC
Tags:
- Key: Name
Value: DevRouteTable
DevRoute:
Type: AWS::EC2::Route
DependsOn: NonProdNATGateway
Properties:
RouteTableId:
Ref: RouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId:
Ref: NonProdNATGateway
NonProdNATEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
NonProdNATGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NonProdNATEIP.AllocationId
SubnetId: !Ref DevPublicSubnetA
SubnetId: !Ref DevPublicSubnetB
DependsOn:
- NonProdNATEIP
- DevPublicSubnetA
- DevPublicSubnetB
NonProdGWVPCAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref NonProdNATGateway
VpcId: !Ref DevVPC
DependsOn:
- NonProdNATGateway
Route:
Type: AWS::EC2::Route
Properties:
RouteTableId:
Ref: RouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId:
Ref: NonProdNATGateway
PrivateRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref RouteTable
SubnetId: !Ref DevPrivateSubnetA
SubnetId: !Ref DevPrivateSubnetB
PublicRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref RouteTable
SubnetId: !Ref DevPublicSubnetA
SubnetId: !Ref DevPublicSubnetB
Mappings:
R53EnvironmentMapping:
dev:
oregonawslocal: mydomain.oregon-dev.local
Outputs:
DevPublicSubnetA:
Description: ID for dev subnet A
Value: !Ref DevPublicSubnetA
Export:
Name: DevPublicSubnetA
DevPublicSubnetB:
Description: ID for dev subnet B
Value: !Ref DevPublicSubnetB
Export:
Name: DevPublicSubnetB
DevPrivateSubnetA:
Description: ID for dev subnet A
Value: !Ref DevPrivateSubnetA
Export:
Name: DevPrivateSubnetA
DevPrivateSubnetB:
Description: ID for dev subnet B
Value: !Ref DevPrivateSubnetB
Export:
Name: DevPrivateSubnetB
DevRoute53OregonAWSLocalHostedZone:
Description: Hosted zone ID for hosted zone
Value: !Ref DevRoute53HostedZone
Export:
Name: DevRoute53OregonAWSLocalHostedZone
DevRoute53OregonAWSLocalHostedZoneName:
Description: Hosted zone name for hosted zone
Value: !FindInMap [R53EnvironmentMapping, dev, oregonawslocal]
Export:
Name: DevRoute53OregonAWSLocalHostedZoneName
As Michael - sqlbot mentioned in a comment, one issue is that you're referencing an AWS::EC2::NATGateway resource in the AWS::EC2::VPCGatewayAttachment resource's InternetGatewayId property, which requires an AWS::EC2::InternetGateway resource.
NAT Gateways and Internet Gateways are two different types of AWS resources - a NAT Gateway provides outbound-only Internet access to a private Subnet, while an Internet Gateway provides two-way Internet access to a public Subnet.
Another issue is that you need two separate sets of AWS::EC2::RouteTable and AWS::EC2::Route Resources, one set for your public Subnet and another for your private Subnet. The public Route should have GatewayId referencing the Internet Gateway, and the private Route should have NatGatewayId referencing the NAT Gateway.
Finally, you have some invalid duplicate SubnetId properties in several resources (NatGateway, SubnetRouteTableAssociation)- each of these Resources only points accepts a single Subnet ID.
Since you're a CloudFormation beginner, I strongly recommend leveraging AWS Quick Start's Amazon VPC Architecture template to get started quickly with a reference VPC architecture. This AWS-supported template creates a single VPC containing both public and private subnets within each specified Availability Zone (you provide 2-4 Availability Zones as Parameters). You can later customize this template to better fit your specific needs if necessary, or use it as a reference for configuring your own template's resources.