AWS cloudformation waitcondtion for VPN gateway - amazon-web-services

I am trying to create VPN gateway and route table entry which need VPN gateway as dependency. Due to race condition, route table entry (i.e. RouteA), is unable to find the VPN gateway by the time of its creation. I tried adding WaitCondition to solve this issue, but it needs a success condition. Looking at AWS documentation, I couldn't find any way to send success signal after creation of VPN gateway. Here is the code:
"VPNGateway" : {
"Type" : "AWS::EC2::VPNGateway",
"Properties" : {
"Type" : "ipsec.1"
}
},
"WaitHandle" : {
"Type" : "AWS::CloudFormation::WaitConditionHandle"
},
"WaitCondition" : {
"Type" : "AWS::CloudFormation::WaitCondition",
"DependsOn" : "VPNGateway",
"Properties" : {
"Handle" : { "Ref" : "WaitHandle" },
"Timeout" : "300"
}
},
"RouteA": {
"Type": "AWS::EC2::Route",
"DependsOn": ["VPNGateway"],
"Properties": {
"DestinationCidrBlock": {"Ref": "CidrBlock"},
"RouteTableId": {"Ref": "PrivateRouteTableA"},
"GatewayId": {"Ref": "VPNGateway"}
}
}

Related

How do I specify subnet and VPC IDs in AWS CloudFormation?

I want my CloudFormation template to use existing subnets and VPCs. I don't want to create new ones.
How do I parameterize these?
When I look at the docs for AWS::EC2::VPC and AWS::EC2::Subnet, it seems these resources are only for creating new VPCs and subnets. Is that correct?
Should I just point the instance resource directly to the existing VPC and subnets I want it to use?
For example - if I have an instance resource in my template and I point it directly to an existing subnet, like this:
{
"Resources": {
"MyServer": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": {
"Ref": "InstanceType"
},
"SubnetId": {
"Ref": "subnet-abc123"
},
...
I get this error when validating the template:
Template contains errors.: Template format error: Unresolved resource dependencies [subnet-abc123] in the Resources block of the template
I tried to do this with mappings but still getting an error:
"Mappings": {
"SubnetID": {
"TopKey": {
"Default": "subnet-abc123"
}
}
And with this in the instance resource:
"SubnetId": {
"Fn::FindInMap": [
"SubnetID",
{
"Ref": "TopKey"
},
"Default"
]
}
I get this error when trying to validate:
Template contains errors.: Template format error: Unresolved resource dependencies [TopKey] in the Resources block of the template
If you wish to use a specific VPC and subnet, just insert their values:
{
"Resources": {
"MyServer": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": "t2.micro",
"SubnetId": "subnet-abc123",
"ImageId": "ami-abcd1234"
}
}
}
A subnet always belongs to a VPC, so specifying the subnet will automatically select the matching VPC.
Specify them in the Parameters section, and refer them in Resources section. CF will let you select the VPC first and then the Subnet.
"Parameters" : {
"VpcId" : {
"Type" : "AWS::EC2::VPC::Id",
"Description" : "VPCId of Virtual Private Cloud (VPC).",
"Default" : ""
},
"VpcSubnet": {
"Description" : "SubnetId in VPC",
"Type" : "AWS::EC2::Subnet::Id",
"Default" : ""
},
"Resources" : {
...
"Ec2Instance" : {
"Properties" : {
"SubnetId" : { "Ref" : "VpcSubnet" },

How get "cidrblock" of a subnet in the "outputs" of a AWS Cloudformation?

I am writing a AWS Code formation. I have to print the Cidrblock of a subnet. But that does not work. Please help
"Resources": {
"Subnet": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"VpcId": {
"Ref": "VPC"
},
"CidrBlock": "10.0.0.0/16",
}
},
Outputs : {
"SubnetCIDR": {
"Value": {
"Fn::GetAtt": [
"Subnet",
"CidrBlock"
]
},
"Description": "The CIDR"
},
}
This does not work. The following error message is shown while uploading the template:
Template validation error: Template error: resource Subnet does not
support attribute type CidrBlock in Fn::GetAtt
Not supported.
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html
If you look at the doc, the only supported attribute is AvailabilityZone
Since you seem to be hard coding the CIDR block anyway, you could set it as a parameter and then just reference the parameter in both places.
"Parameters" : {
"CidrBlock" : {
"Type" : "String",
"Default" : "10.0.0.0/16"
}
},
"Resources" : {
"Subnet" : {
"Type" : "AWS::EC2::Subnet",
"Properties" : {
"VpcId" : {
"Ref" : "VPC"
},
"CidrBlock" : { "Ref" : "CidrBlock" }
}
}
},
"Outputs" : {
"SubnetCIDR" : {
"Value" : { "Ref" : "CidrBlock" },
"Description": "The CIDR"
}
}

Can I use public security groups in cloud formation for ec2 launch configs?

Can I use public security groups in cloud formation for ec2 launch configs ?
I am trying to simply direct the cloudformation stack to use an existing set and it fails to create those resources.
I tried to create those security groups as a rolling set (ssh1,ssh2...) for each stack but no such luck either.
It would be really cool if your answer would include a code snippet as to how to do this exactly. thanks.
You can refer the sample template for deep understanding.
Amazon EC2 instance in a security group
Here is the part you are interesting.
"Resources" : {
"EC2Instance" : {
"Type" : "AWS::EC2::Instance",
"Properties" : {
"InstanceType" : { "Ref" : "InstanceType" },
"SecurityGroups" : [ { "Ref" : "InstanceSecurityGroup" } ], # <--Here is the refer
"KeyName" : { "Ref" : "KeyName" },
"ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" },
{ "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] }
}
},
"InstanceSecurityGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Enable SSH access via port 22",
"SecurityGroupIngress" : [ {
"IpProtocol" : "tcp",
"FromPort" : "22",
"ToPort" : "22",
"CidrIp" : { "Ref" : "SSHLocation"}
} ]
}
}
},
Above sample to create a new security group, and assign it to a new ec2 instance. If you have exist security group, then you needn't the part InstanceSecurityGroup, and assign the real security group name to ec2 instance at:
"SecurityGroups" : "REAL Security Group Name",

How do I connect my AWS::EC2::DBSecurityGroup to my AWS::RDS::DBSecurityGroup in a VPC context?

I have this AWS::EC2::SecurityGroup:
"InstanceSecurityGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Enable HTTP access on the configured port",
"VpcId" : { "Ref" : "VpcId" },
"SecurityGroupIngress" : [ {
"IpProtocol" : "tcp",
"FromPort" : { "Ref" : "WebServerPort" },
"ToPort" : { "Ref" : "WebServerPort" },
"SourceSecurityGroupId" : { "Ref" : "LoadBalancerSecurityGroup" }
} ]
}
}
and I have this AWS::RDS::DBSecurityGroup
"DBSecurityGroup": {
"Type": "AWS::RDS::DBSecurityGroup",
"Properties": {
"DBSecurityGroupIngress": { "EC2SecurityGroupName": { "Ref": "InstanceSecurityGroup"} },
"GroupDescription" : "Frontend Access"
}
}
when I try to bring up this stack, I get:
Invalid security group , groupId=, groupName= sg-a381fdc6.
Edit 1: Reading a bit more suggests I need AWS::RDS::DBSecurityGroup to be associated with my VPC, so I change to this:
"DBSecurityGroup": {
"Type": "AWS::RDS::DBSecurityGroup",
"Properties": {
"EC2VpcId" : { "Ref" : "VpcId" },
"DBSecurityGroupIngress": { "EC2SecurityGroupName": { "Ref": "InstanceSecurityGroup"} },
"GroupDescription" : "Frontend Access"
}
}
and when I bring up the stack I get
Please see the documentation for authorizing DBSecurityGroup ingress. For VPC, EC2SecurityGroupId is required. To authorize only the source address of this request (and no other address), pass 205.251.233.35/32 as the CIDRIP parameter.
EC2SecurityGroupId is the ID of the security group, not the name of it, and that ID is assigned outside my control, so I don't know what value to put in here.
How do I connect my AWS::EC2::DBSecurityGroup to my AWS::RDS::DBSecurityGroup in a VPC context?
The problem is that your { "Ref": "InstanceSecurityGroup"} doesn't hold the id only the name. To get a hold on the EC2SecurityGroupId use Fn::GetAtt.
Your template for the DBSecurityGroup should look something like this (notice how Ref have been replaced by Fn::GetAtt:
"DBSecurityGroup": {
"Type": "AWS::RDS::DBSecurityGroup",
"Properties": {
"EC2VpcId" : { "Ref" : "VpcId" },
"DBSecurityGroupIngress": { "EC2SecurityGroupId": { "Fn::GetAtt" : [ "InstanceSecurityGroup", "GroupId" ] } },
"GroupDescription" : "Frontend Access"
}
When you RDS Security group is defined inside a VPC, you must refer to other security group by group-id, not by group name.
See
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-security-group.html
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-security-group-rule.html
"For VPC DB Security Groups, use EC2SecurityGroupId. For EC2 Security Groups, use EC2SecurityGroupOwnerId and either EC2SecurityGroupName or EC2SecurityGroupId."
You can get the Security group ID by using the "Ref" function as described here
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-security-group.html
So, your modified Security Group should be
"DBSecurityGroup": {
"Type": "AWS::RDS::DBSecurityGroup",
"Properties": {
"EC2VpcId" : { "Ref" : "VpcId" },
"DBSecurityGroupIngress": { "EC2SecurityGroupId": { "Ref": "InstanceSecurityGroup"} },
"GroupDescription" : "Frontend Access"
}
}

How to automatically add an autoscaled EC2 instance to a Security Group?

I want to set up my AWS to autoscale EC2 instances (Windows Server 2012). The catch is that they need to have their IP addresses added to a Security Group so they can communicate with another EC2.
Is there a way that AWS can handle this automatically through its autoscaling feature? (The closest I could find was to assign an IAM role to the new instances, but I don't I can add an IAM role to a Security Group, I can only add IP addresses.)
The way I am currently looking into is to use the AWS CLI (command line) as a startup script.
ec2-authorize mySecurityGroup -p 1433 -s xx.xx.xx.xx/32
But how do I get the public IP of the current instance? Is there a AWS CLI command to get this? I'd rather not depend on an external website like "curl echoip.com". I heard about ec2-metadata, but I don't think that works for Windows, and I'd prefer not to use another third party software.
Create a security group called web. For the sake of an example, lets say the id of that group is: sg-7aa91911
Create a security group called db.
Add a new rule to the db security group for port 1433 with the source of sg-7aa91911
Create an Autoscaling launch configuration and set the SecurityGroups to sg-7aa91911 and any other configuration you need.
Create Autoscaling group with that launch configuration.
I wrote up a quick CloudFormation template to do this task. You should be able to just run it and it will create an Autoscaling group with the connected security groups. It'll also create a blank instance where you can store your db.
If you prefer not to use a CloudFormation template, just look at where the security groups are defined. It shows how the 2 security groups are to be connected
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "test tempalte",
"Parameters" : {
"KeyName" : {
"Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instance",
"Type" : "String"
}
},
"Mappings" : {
"RegionMap" : {
"us-east-1" : { "AMI" : "ami-7f418316" },
"us-west-1" : { "AMI" : "ami-951945d0" },
"us-west-2" : { "AMI" : "ami-16fd7026" },
"eu-west-1" : { "AMI" : "ami-24506250" },
"sa-east-1" : { "AMI" : "ami-3e3be423" },
"ap-southeast-1" : { "AMI" : "ami-74dda626" },
"ap-northeast-1" : { "AMI" : "ami-dcfa4edd" }
}
},
"Resources" : {
"WebServerGroup" : {
"Type" : "AWS::AutoScaling::AutoScalingGroup",
"Properties" : {
"AvailabilityZones" : { "Fn::GetAZs" : "" },
"LaunchConfigurationName" : { "Ref" : "LaunchConfig" },
"MinSize" : "1",
"MaxSize" : "10",
"DesiredCapacity" : "1"
}
},
"LaunchConfig" : {
"Type" : "AWS::AutoScaling::LaunchConfiguration",
"Properties" : {
"InstanceType" : "m1.small",
"KeyName" : { "Ref" : "KeyName" },
"SecurityGroups" : [ {"Ref" : "websg"} ],
"ImageId" : { "Fn::FindInMap" : [ "RegionMap", { "Ref" : "AWS::Region" }, "AMI" ]}
}
},
"Ec2Instance" : {
"Type" : "AWS::EC2::Instance",
"Properties" : {
"KeyName" : { "Ref" : "KeyName" },
"ImageId" : { "Fn::FindInMap" : [ "RegionMap", { "Ref" : "AWS::Region" }, "AMI" ]},
"UserData" : { "Fn::Base64" : "80" }
}
},
"websg" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Enable SSH and access, 8080, and 80",
"SecurityGroupIngress" : [
{"IpProtocol" : "tcp", "FromPort" : "8080", "ToPort" : "8080", "CidrIp" : "0.0.0.0/0"},
{"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0"},
{"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : "0.0.0.0/0"}
]
}
},
"dbsg" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Port opened only to security group",
"SecurityGroupIngress" : [
{"IpProtocol" : "tcp", "FromPort" : "1433", "ToPort" : "1433", "SourceSecurityGroupName" : {"Ref" : "websg"}
}
]
}
}
}
}