how to use ImportValue in parameters? - amazon-web-services

As I knew, I can use ImportValue to reference value from another cloudformation stack in part of Resources.
NetworkInterfaces:
- GroupSet:
- Fn::ImportValue:
Fn::Sub: "${NetworkStackNameParameter}-SecurityGroupID"
AssociatePublicIpAddress: 'true'
DeviceIndex: '0'
DeleteOnTermination: 'true'
SubnetId:
Fn::ImportValue:
Fn::Sub: "${NetworkStackNameParameter}-SubnetID"
But seems this feature can't be used in Parameters
Parameters:
VPC:
Description: VPC ID
Type: String
Default:
Fn::ImportValue:
!Sub "${NetworkStackNameParameter}-VPC"
If I use above way, will get the error:
An error occurred (ValidationError) when calling the CreateChangeSet operation: Template format error: Every Default member must be a string.
Anyway to work around? because the same vpc id, subnet id, security group Id, will be used not only one place.
updates
So I have to give up:
In your AWS CloudFormation template, confirm that the Parameters section doesn't contain any intrinsic functions.
https://aws.amazon.com/premiumsupport/knowledge-center/cloudformation-template-validation/

One way of doing this is to use a condition:
Parameters:
MyValue:
Type: String
Value: ''
Conditions:
MyValueExists: !Not [ !Equals [!Ref MyValue, '']]
Resources:
Resource:
Type: AWS::Something
Properties:
Key: !If [MyValueExists, !Ref MyValue, !ImportValue 'Imported']

Related

Template format error: Unresolved resource dependencies [ECSCluster] in the Resources block of the template

I have a condition to create or not the ECS Cluster and when I choose not to create it, indicating the boolean value false, Cloudformation returns the following error: Template format error: Unresolved resource dependencies [ECSCluster] in the Resources block of the template.
Below is a snippet of my code for this error:
Parameters:
NameNewECSCluster:
Type: String
NameOldECSCluster:
Type: String
CreationECSCluster:
Type: String
AllowedValues: [true, false]
Conditions:
CreationECSClusterSelected: !Equals [!Ref CreationECSCluster, true]
ECSCluster:
Type: AWS::ECS::Cluster
Condition: CreationECSClusterSelected
Properties:
ClusterName: !Ref NameNewECSCluster
CapacityProviders:
- FARGATE
- FARGATE_SPOT
Tags:
- Key: CLUSTER
Value: !Ref NameNewECSCluster
ECSService:
Type: AWS::ECS::Service
DependsOn: ListenerHTTPforALB
Properties:
ServiceName: !Sub ${ApplicationName}-${Environment}
Cluster: !If [CreationECSClusterSelected, !Ref ECSCluster, !Ref NameOldECSCluster]
The problem only occurs when I refer to a Cluster already created, when I create the Cluster inside the template it does not.
Does anyone have an idea how to resolve this?
If CreationECSClusterSelected is false, then ECSCluster does not exist and !Ref ECSCluster will result in the error. It does not matter the you have !If. Both false and true alternatives of your If must be valid as If gets executed after validation of your If statement. You can try with:
Cluster: !If [CreationECSClusterSelected, !Ref NameNewECSCluster, !Ref NameOldECSCluster]

CloudFormation Template Error when placing EC2 Instance in particular subnet

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

How do I solve "Incompatible launch template: The network interface's device index must be zero" when updating a CloudFormation template?

I have an existing stack that created an auto-scale group that uses a Launch Configuration. I am now trying to switch this stack so the auto-scale group will use a Launch Template instead of Launch Configuration, but the update is giving this error:
Incompatible launch template: The network interface's device index
must be zero. (Service: AmazonAutoScaling; Status Code: 400; Error
Code: InvalidQueryParameter; Request ID:
97bdf4cf-5c90-4035-v234-806367461438; Proxy: null)'
The launch configuration defined in the current CloudFormation template sets AssociatePublicIpAddress: true and the instance created by this template has a public IP. The launch template in the CloudFormation template I am trying to use for the update specifies AssociatePublicIpAddress: true under NetworkNetworkInterfaces.
What does this error mean and how do I fix it?
Relevant parts of template:
LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: my-launch-template
LaunchTemplateData:
EbsOptimized: false
IamInstanceProfile:
Arn: !GetAtt MyInstanceProfile.Arn
ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", AMI]
InstanceType: !Ref InstanceType
KeyName: !Ref KeyName
NetworkInterfaces:
- AssociatePublicIpAddress: true
If you want to explicitly set NetworkInterfaces, the it should be:
LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateName: my-launch-template
LaunchTemplateData:
EbsOptimized: false
IamInstanceProfile:
Arn: !GetAtt MyInstanceProfile.Arn
ImageId: !FindInMap [RegionMap, !Ref "AWS::Region", AMI]
InstanceType: !Ref InstanceType
KeyName: !Ref KeyName
NetworkInterfaces:
- DeviceIndex: 0
AssociatePublicIpAddress: true
Groups: [<security-group-id>]

Value of property Parameters must be an object with String (or simple type) properties

I am trying to pass parameters to one of the nested stacks by populating the values from another nested stacks output.
And i do not want any cross-referencing (unless there is no way around it)
The idea is pretty straight forward.
RootStack
-NstdStackVPC
-NstdStackSG
-NstdStackEC2
The problem is on the last nested stack while creating EC2.
If i created the resource in the root stack directly the EC2 gets created
Description: RootStack
Parameters:
MyKeyName:
Type: AWS::EC2::KeyPair::KeyName
Default: my-test-key
EC2ImageId:
Type: AWS::EC2::Image::Id
Default: ami-0dxxxxa
Resources:
NstdStackVPC ......
NstdStackSG ......
EC2Host:
Type: AWS::EC2::Instance
Properties:
SubnetId: !GetAtt NstdStackVPC.Outputs.VPCPubSubnet
ImageId: !Ref EC2ImageId
InstanceType: t2.micro
KeyName: !Ref MyKeyName
SecurityGroupIds:
- !GetAtt NstdStackSG.Outputs.SecGrp4EC2Host
But if i try to create the EC2 as a nested stack
AWSTemplateFormatVersion: '2010-09-09'
Description: NstdStackEC2.
Parameters:
myNstdKeyName:
Type: AWS::EC2::KeyPair::KeyName
myNstdImageId:
Type: AWS::EC2::Image::Id
myNstdSecGrp:
Type: AWS::EC2::SecurityGroup::Id
myNstdEC2HostSubnet:
Type: AWS::EC2::Subnet::Id
Resources:
EC2Host:
Type: AWS::EC2::Instance
Properties:
SubnetId: !Ref myNstdEC2HostSubnet
ImageId: !Ref myNstdImageId
InstanceType: t2.micro
KeyName: !Ref myNstdKeyName
SecurityGroupIds:
- Ref myNstdSecGrp
By changing the root stack as follows
AWSTemplateFormatVersion: '2010-09-09'
Description: RootStack
Parameters:
MyKeyName:
Type: AWS::EC2::KeyPair::KeyName
Default: my-test-key
EC2ImageId:
Type: AWS::EC2::Image::Id
Default: ami-0dxxxxa
Resources:
NstdStackVPC ......
NstdStackSG ......
NstdStackEC2:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://bkt.s3.eu-central-1.amazonaws.com/NstdEC2Host.yml
Parameters:
myNstdKeyName: !Ref MyKeyName
myNstdImageId: !Ref EC2ImageId
myNstdSecGrp: !GetAtt NstdStackSG.Outputs.SecGrp4BasHost
myNstdEC2HostSubnet: !GetAtt NstdStackVPC.Outputs.VPCPubSubnet
It gives me the following error:
Value of property Parameters must be an object with String (or simple type) properties
tried removing all the parameters to try one by one. But it fails on everything.
Even for the parameters that are being referenced directly from the root stack i.e., MyKeyName, EC2ImageId
I ran into the same exact error message with a similar problem and solution. I came here and since the issue was slightly different, this question helped me get to my solution. So, not trying to hijack this question, simply hoping to provide what I found additionally useful to the next person visiting.
I was nesting a cluster template very similar to this one and OPs example. Passing Subnets as a list of strings (I believe List<AWS::Some::Type> will also work).
Subnets:
Description: Subnets of the of the cluster availaibility zone
Type: CommaDelimitedList
Default: subnet-0d..de,subnet-0e..7a,subnet-0b..24
And I'm using the above parameters to call the partial child template as follows.
ECS:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://xx.amazonaws.com/yy/zz.yaml
Parameters:
SecurityGroups: !Join [",", [!GetAtt SecurityGroups.Outputs.ECSHostSecurityGroup]]
Subnets: !Join [",", !Ref Subnets]
So, In the above example, the SecurityGroups are joined together into a list from the output of the SecurityGroup Nested Template, but the subnets are simply joined together from the comma delimited parameter. There is a knowledge-center article too, if you want more info. TA OP
Ok finally sorted this out myself.
In my NstdStackSG outputs section i was referring to the object itself.
And that is where this goes wrong.
AWSTemplateFormatVersion: 2010-09-09
Description: Security group nested stack
Resources:
MySecGrp
Type: ....
.....
....
Outputs:
MyOtptSecGrp:
#This one is working for me.
Value: !GetAtt MySecGrp.GroupId
#previously i was assigning the following value
#Value: !Re MySecGrp
And now in the RootStack
AWSTemplateFormatVersion: '2010-09-09'
Description: RootStack
Parameters:
MyKeyName:
Type: AWS::EC2::KeyPair::KeyName
Default: my-test-key
EC2ImageId:
Type: AWS::EC2::Image::Id
Default: ami-0dxxxxa
Resources:
NstdStackVPC ......
NstdStackSG ......
NstdStackEC2:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://bkt.s3.eu-central-1.amazonaws.com/NstdEC2Host.yml
Parameters:
myNstdKeyName: !Ref MyKeyName
myNstdImageId: !Ref EC2ImageId
myNstdSecGrp: !GetAtt NstdStackSG.Outputs.SecGrp4BasHost
myNstdEC2HostSubnet: !GetAtt NstdStackVPC.Outputs.VPCPubSubnet
And in my nestedEC2Stack
AWSTemplateFormatVersion: 2010-09-09
Description: NstdStackEC2
Parameters:
myNstdSecGrp:
Type: AWS::EC2::SecurityGroup::Id
myNstdEC2HostSubnet:
Type: AWS::EC2::Subnet::Id
myNstdKeyName:
Type: AWS::EC2::KeyPair::KeyName
myNstdImageId:
Type: AWS::EC2::Image::Id
Resources:
EC2Host:
Type: AWS::EC2::Instance
Properties:
SubnetId: !Ref myNstdEC2HostSubnet
ImageId: !Ref myNstdImageId
InstanceType: t2.micro
KeyName: !Ref myNstdKeyName
SecurityGroupIds:
- !Ref myNstdSecGrp
Hope this helps. (If not in solving then at least in pointing the right direction)

AWS Cloudformation nested intrinsic function not evaluating

This is part of the cloudformation template I am writing and getting errors using the Fn::FindInMap function:
Parameters:
VpcStackName:
Description: >-
Name of an active CloudFormation VPC stack that contains the networking
resources, such as the subnet and security group, that will be used in
this stack.
Type: String
MinLength: 1
MaxLength: 255
AllowedPattern: '^[a-zA-Z][-a-zA-Z0-9]*$'
Default: wordpress-dev-vpc
Mappings:
Instance:
development:
AllocatedStorage: 20
DBInstanceClass: db.t2.micro
production:
AllocatedStorage: 25
DBInstanceClass: db.m3.medium
Resources:
DBInstance:
Type: AWS::RDS::DBInstance
DeletionPolicy: Snapshot
Properties:
Engine: MariaDB
StorageType: gp2
MasterUsername: !Ref MasterUsername
MasterUserPassword: !Ref MasterUserPassword
AllocatedStorage:
Fn::FindInMap:
- Instance
- Fn::ImportValue:
Fn::Sub: '${VpcStackName}-Environment'
- AllocatedStorage
DBInstanceClass:
Fn::FindInMap:
- Instance
- Fn::ImportValue:
Fn::Sub: '${VpcStackName}-Environment'
- DBInstanceClass
In another stack, I am exporting ${VpcStackName}-Environment like this:
Outputs:
Environment:
Description: Environment type of this stack
Value: !Ref Environment
Export:
Name: !Sub '${AWS::StackName}-Environment'
When trying to use the Fn::FindInMap function, I get this error:
An error occurred (ValidationError) when calling the ValidateTemplate operation: Template error: every Fn::FindInMap object requires three parameters, the map name, map key and the attribute for return value
Any advice?
Based on the documentation at https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-findinmap.html , the supported functions inside a Fn::FindInMap function are Fn::FindInMap and Ref. So is there another way to do it? For example, storing the value of Fn::ImportValue: !Sub '${VpcStackName}-Environment' in a temporary variable?
According to this document, the Fn::FindInMap function is only usable with these:
Fn::FindInMap
Ref
So Fn::ImportValue and Fn::Sub won't be evaluated.