Launch an ec2 instance with cloudformation - aws-cloudformation

I am trying to launch an ec2 instance using cloudformation.I created this json template but I get error Template format error: At least one Resources member must be defined.
{
"Type" : "AWS::EC2::Instance",
"Properties" : {
"ImageId" : "ami-08ddb3f251a88cf33",
"InstanceType" : "t2.micro ",
"KeyName" : "Stagingkey",
"LaunchTemplate" : {
"LaunchTemplateId" : "jen1",
"LaunchTemplateName" : "Launchinstance",
"Version":"V1"
},
"SecurityGroupIds" : [ "sg-055f49a32efd4238b" ],
"SecurityGroups" : [ "jenkins_group" ],
}
}
What am I doing wrong?
Is there any other template for ap-south-1 region which I could use? Any help would be appreciated.

The error says it all: At least one Resources member must be defined.
The major sections of a template are:
Parameters
Mappings
Resources
Outputs
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "My Stack",
"Resources": {
"MyInstance": {
"Type": "AWS::EC2::Instance",
"Properties": {
"ImageId": "ami-08ddb3f251a88cf33",
"InstanceType": "t2.micro ",
"KeyName": "Stagingkey",
"LaunchTemplate": {
"LaunchTemplateId": "jen1",
"LaunchTemplateName": "Launchinstance",
"Version": "V1"
},
"SecurityGroupIds": [
"sg-055f49a32efd4238b"
],
"SecurityGroups": [
"jenkins_group"
]
}
}
}
}
You'll need to test it. For example, it is unlikely that you will define both SecurityGroupIds and SecurityGroups.

All the properties you have entered are properties of an EC2 resource, which you need to declare. You have no resources block/a logical name for you resource, like so:
"Resources": {
"MyTomcatName": {
"Type": "AWS::EC2::Instance",
"Properties": {
[...]

Related

Property Handler cannot be empty - The following resource(s) failed to create

Am trying to create lamda function using cloudformation. While creating stack am getting error like below. I have pasted my template below. Please help me where am doing mistake.
**20:01:50 UTC+0550 ROLLBACK_IN_PROGRESS AWS::CloudFormation::Stack MyStack The
following resource(s) failed to create: [Lamdafuntion]. . Rollback
requested by user.
20:01:50
UTC+0550 CREATE_FAILED AWS::Lambda::Function Lamdafuntion Property
Handler cannot be empty.**
Template :
"Type": "AWS::Lambda::Function",
"Properties": {
"Description" : "Lambda Function",
"Code" : {
"S3Bucket" : "awstier1bucket"
"S3Key" : "code.py.zip"
},
"FunctionName" : lambda_function
"Handler" : "test.lambda_handler",
"Tags": [
{
"Key": "Name",
"Value": "LambdaTest"
}
]
I believe it's due to mismatch of function and handler name.
Generally it has to be constructed by combining file_name.function_name
I've tried the following and it worked:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "yeye",
"Resources": {
"my-resource-1": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Description": "Lambda Function",
"Role": "arn:aws:iam::account_number:role/lambda_basic_execution",
"Runtime": "python2.7",
"Code": {
"S3Bucket": "my_bucket",
"S3Key": "**lambda_script**.py.zip"
},
"FunctionName": "my_function",
"Handler": "**lambda_script.function_name**"
}
}
}
}
In the example above I am uploading file named lambda_script.py which contains code with the following function defined:
def function_name(event, context):
"""
code
more code
"""
Which makes handler name lambda_script.function_name

Permission issue for an ECS Service to use an ALB

I am trying to deploy an ECS stack with an ALB using cloudformation, and i get an error at the Service creation, which seems to be a missing permission to access the load balancer.
Here is the error: Unable to assume role and validate the specified targetGroupArn. Please verify that the ECS service role being passed has the proper permissions.
Here is the service definition:
"EcsService": {
"Type":"AWS::ECS::Service",
"DependsOn": [
"loadBalancer",
"EcsServiceRole"
],
"Properties":{
"Cluster":{
"Ref": "EcsCluster"
},
"DesiredCount":"1",
"DeploymentConfiguration":{
"MaximumPercent":100,
"MinimumHealthyPercent":0
},
"LoadBalancers": [
{
"ContainerName": "test-web",
"ContainerPort": "80",
"TargetGroupArn" : {
"Ref": "loadBalancer"
},
}
],
"Role":{
"Ref": "EcsServiceRole"
},
"TaskDefinition":{
"Ref": "runWebServerTaskDefinition"
}
}
}
Here is the Load Balancer definition:
"loadBalancer" : {
"Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
"Properties": {
"Name": "testalb",
"Scheme" : "internal",
"Subnets" : [
"subnet-b8217295",
"subnet-ddaad2b8",
"subnet-6d71fb51"
],
"LoadBalancerAttributes" : [
{ "Key" : "idle_timeout.timeout_seconds", "Value" : "50" }
],
"SecurityGroups": [
{ "Ref": "InstanceSecurityGroupOpenWeb" },
{ "Ref" : "InstanceSecurityGroupOpenFull" }
],
"Tags" : [
{ "Key" : "key", "Value" : "value" },
{ "Key" : "key2", "Value" : "value2" }
]
}
}
Here is the IAM role the service should use:
"EcsServiceRole": {
"Type":"AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement":[
{
"Effect":"Allow",
"Principal":{
"Service":[
"ecs.amazonaws.com"
]
},
"Action":[
"sts:AssumeRole"
]
}
]
},
"Path":"/",
"Policies":[
{
"PolicyName":"ecs-service",
"PolicyDocument":{
"Statement":[
{
"Effect":"Allow",
"Action":[
"elasticloadbalancing:*",
"ec2:*"
],
"Resource":"*"
}
]
}
}
]
}
}
I didn't find if there is a specific namespace for ALB in IAM.
Do you have an idea?
TargetGroupArn should be pointing to TargetGroup ARN, not ALB ARN, Currently, it is pointed to Load Balancer ARN.
"TargetGroupArn" : {
"Ref": "loadBalancer"
},
UPDATE:
As of July 19th 2018, it is now possible to create a IAM Service-Linked Roles using CloudFormation https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-servicelinkedrole.html.
EcsServiceLinkedRole:
Type: "AWS::IAM::ServiceLinkedRole"
Properties:
AWSServiceName: "ecs.amazonaws.com"
Description: "Role to enable Amazon ECS to manage your cluster."
OLD ANSWER:
Since AWS introduced Service-Linked Roles, I no longer specify a role for my AWS::ECS::Service. It will default to the service linked role which has all the necessary permissions.

"elb name longer than 32" but only 8

I am trying to use AWS cloudformation to create a stack with an ALB and an ECS service, but i get a CREATE_FAILED on the AWS::ECS::Service, which is elb name longer than 32.
I don’t get why the ECS Service is complaining about the ELB name while the ALB itself is in CREATE_COMPLETE status…
Here is the JSON related to the ALB creation i send to cloudformation:
"loadBalancer" : {
"Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
"Properties": {
"Name": "test-alb",
"Scheme" : "internal",
"Subnets" : [
"subnet-b8217295",
"subnet-ddaad2b8",
"subnet-6d71fb51"
],
"LoadBalancerAttributes" : [
{ "Key" : "idle_timeout.timeout_seconds", "Value" : "50" }
],
"SecurityGroups": [
{ "Ref": "InstanceSecurityGroupOpenWeb" },
{ "Ref" : "InstanceSecurityGroupOpenFull" }
],
"Tags" : [
{ "Key" : "key", "Value" : "value" },
{ "Key" : "key2", "Value" : "value2" }
]
}
}
And here is the JSON related to the ECS Service creation (with a ref to the ALB defining above):
"EcsService": {
"Type":"AWS::ECS::Service",
"Properties":{
"Cluster":{
"Ref": "EcsCluster"
},
"DesiredCount":"1",
"DeploymentConfiguration":{
"MaximumPercent":100,
"MinimumHealthyPercent":0
},
"LoadBalancers": [
{
"ContainerName": "test-web",
"ContainerPort":"80",
"LoadBalancerName":{
"Ref": "loadBalancer"
}
}
],
"Role":{
"Ref": "EcsServiceRole"
},
"TaskDefinition":{
"Ref": "runWebServerTaskDefinition"
}
}
}
And as you can see i set the name of the ALB by myself and it is only 8 characters, so i really don’t get the point, any idea?
When you do "Ref", it would return the Load balancer ARN not the Load balancer name. you need to use GetAtt to get the load balancer name
{ "Fn::GetAtt" : [ "loadBalancer", "LoadBalancerName" ] }

aws cloudformation -resource property error

I have defined my parameters like this:
{
"PrivateSubnets":{
"Description":"db subnetlist",
"Type": "List<AWS::EC2::Subnet::Id>"
},
"VPCLIST": {
"Description": "VPC list",
"Type": "List<AWS::EC2::VPC::Id>"
}
}
and referring the above parameters in "resources" section like below:
"InstanceSecurityGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"VpcId" : {"Ref": "VPCLIST"} ,
"GroupDescription" : "Enable 3306/80/SSH access via port 22"
}
and while executing this I am getting the below error.
AWS::EC2::SecurityGroup InstanceSecurityGroup "Value of property VpcId must be of type String"
Note: I have only default VPC available which is not taken as string? any solutions to this issue...
The correct way is make this change:
{
"PrivateSubnets": {
"Description":"db subnetlist",
"Type": "AWS::EC2::Subnet::Id"
},
"VPCLIST": {
"Description": "VPC list",
"Type": "AWS::EC2::VPC::Id"
}
}
The Security Groups requires the VpcId to be a string, the property is an array list, So you need to change the property to Type: String, or use the
Fn::Select function.
{ "Fn::Select" : [ 0, VPCLIST ] }
List – An array of VPC IDs
{
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupName" : String,
"GroupDescription" : String,
"SecurityGroupEgress" : [ Security Group Rule, ... ],
"SecurityGroupIngress" : [ Security Group Rule, ... ],
"Tags" : [ Resource Tag, ... ],
"VpcId" : String
}
}
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-security-group.html

Retrieving the ResourceId of a scaleable target

In the AWS Resource AWS::ApplicationAutoScaling::ScalableTarget, how do I retrieve the value of ResourceId which is the unique resource identifier that associated with the scaleable target?
The format used in the ResourceId property is service/cluster_name/service_name.
You are correct that the ResourceId property should be in the form service/<cluster_name>/<service_name>.
Incidentally, (and to help future Googlers) the error message that you get when you use an incorrect ResourceId or ScalableDimension is:
Unsupported service namespace, resource type or scalable dimension
To achieve this in CloudFormation you can use a Fn::Join for the ResourceId. Here is a snippet of the Scalable target that I am using:
"ECSServiceScalableTarget": {
"Type": "AWS::ApplicationAutoScaling::ScalableTarget",
"Properties": {
"MaxCapacity": 5,
"MinCapacity": 1,
"ResourceId": { "Fn::Join" : ["/", [
"service",
{ "Ref": "ECSCluster" },
{ "Fn::GetAtt" : ["ECSService", "Name"] }
]]},
"RoleARN": { "Fn::Join" : ["", ["arn:aws:iam::", { "Ref" : "AWS::AccountId" }, ":role/ApplicationAutoscalingECSRole"]]},
"ScalableDimension": "ecs:service:DesiredCount",
"ServiceNamespace": "ecs"
}
}
I use the {"Fn::Join" : [ ":", [ "a", "b", "c" ] ]"} to get the value of the "ResourceId".