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".
Related
I use the following Terraform ARM template to deploy to Azure Stack:
...
resource "azurestack_template_deployment" "nsg-rule1" {
count = "${var.nsgr_map["nsg_sourceportranges"] == "" && var.nsgr_map["nsg_destinationportranges"] == "" && var.nsgr_map["nsg_sourceaddressprefixes"] == "" && var.nsgr_map["nsg_destinationaddressprefixes"] == "" ? 1 : 0}"
name = "${var.nsgr_map["nsg_rulename"]}"
resource_group_name = "${var.nsgr_map["rsg_name"]}"
template_body = <<DEPLOY
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"networkSecurityGroupName": {
"type": "String"
},
"networkSecurityGroupRuleName": {
"type" : "String"
},
"protocol" : {
"type" : "String"
},
"sourcePortRange": {
"type" : "String"
},
"destinationPortRange": {
"type" : "String"
},
"sourceAddressPrefix" : {
"type" : "String"
},
"destinationAddressPrefix" : {
"type" : "String"
},
"access" : {
"type" : "String"
},
"priority" : {
"type" : "String"
},
"direction" : {
"type" : "String"
},
"sourcePortRanges" : {
"type" : "String"
},
"destinationPortRanges" : {
"type" : "String"
},
"sourceAddressPrefixes" : {
"type" : "String"
},
"destinationAddressPrefixes" : {
"type" : "String"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Network/networkSecurityGroups/securityRules",
"apiVersion": "2017-10-01",
"name": "[concat(parameters('networkSecurityGroupName'),'/',parameters('networkSecurityGroupRuleName'))]",
"properties": {
"protocol": "[parameters('protocol')]",
"sourcePortRange": "[parameters('sourcePortRange')]",
"destinationPortRange": "[parameters('destinationPortRange')]",
"sourceAddressPrefix": "[parameters('sourceAddressPrefix')]",
"destinationAddressPrefix": "[parameters('destinationAddressPrefix')]",
"access": "[parameters('access')]",
"priority": "[parameters('priority')]",
"direction": "[parameters('direction')]",
"sourcePortRanges": "[parameters('sourcePortRanges')]",
"destinationPortRanges": "[parameters('destinationPortRanges')]",
"sourceAddressPrefixes": "[parameters('sourceAddressPrefixes')]",
"destinationAddressPrefixes": "[parameters('destinationAddressPrefixes')]"
}
}
]
}
DEPLOY
# these key-value pairs are passed into the ARM Template's `parameters` block
parameters = {
networkSecurityGroupName = "${var.nsgr_map["nsg_name"]}"
networkSecurityGroupRuleName = "${var.nsgr_map["nsg_rulename"]}"
protocol = "${var.nsgr_map["nsg_protocol"]}"
sourcePortRange = "${var.nsgr_map["nsg_source_portrange"]}"
destinationPortRange = "${var.nsgr_map["nsg_destination_portrange"]}"
sourceAddressPrefix ="${var.nsgr_map["nsg_sourceaddressprefix"]}"
destinationAddressPrefix = "${var.nsgr_map["nsg_destinationaddressprefix"]}"
access = "${var.nsgr_map["nsg_access"]}"
priority = "${var.nsgr_map["nsg_priority"]}"
direction = "${var.nsgr_map["nsg_direction"]}"
sourcePortRanges = ""
destinationPortRanges = ""
sourceAddressPrefixes = ""
destinationAddressPrefixes = ""
}
deployment_mode = "Incremental"
}
...
In fact I want to add to an existing Network Security Group (NSG) on Azure Stack, some NSG-rules.
The problem is that if I deploy different rules with the same name under the same resource group the deployment fails because the NSG is not part of the ID, which identifies the resource to create.
In other words I have two rules with the same name - say 'NSG_Rule_Open_VPN' under the resource group 'Virtual_Network_1' but for two different network security groups 'nsg_1' and 'nsg_2'.
Then the deployment fails with an error, because Terraform deploys the same resource twice (but the targeted NSG's are not the same)
If I look to the activity protocol on Azure Stack it becomes clear that Terraform doesn't use the name of the targeted NSG in the ID to create the resource:
"resourceId": "/subscriptions/yyyxxx/resourcegroups/RSG_99_VirtualNetwork_01/providers/Microsoft.Resources/deployments/NSR_out_TCP_allow_VMtoINTERNET-HTTPS",
It uses only the resource group name 'RSG_99_VirtualNetwork_01' and the rule name 'NSR_out_TCP_allow_VMtoINTERNET-HTTPS' but not the NSG name.
Is there a way to avoid this. so that Terraform creates a resourceID which also has a dependency to the NSG name?
this happens because this is the deployment name, not the NSG rule name. so you need to update this bit to include nsg-name or some counter or something random:
resource "azurestack_template_deployment" "nsg-rule1" {
count = not_important_removed
name = "${var.nsgr_map["nsg_rulename"]}" # this bit needs to be updated
resource_group_name = "${var.nsgr_map["rsg_name"]}"
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": {
[...]
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.
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" ] }
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