Every DependsOn value must be a string - How to explode a Mapping for the DependsOn property - aws-cloudformation

I am using the explode transform macro in the following manner.
ServiceMap:
Private:
Prefix: Private
Public:
Prefix: Public
Service:
ExplodeMap: ServiceMap
Type: AWS::ECS::Service
DependsOn:
- !Sub 'LoadBalancerRule${!Explode Prefix}'
Properties:
Cluster: !Ref "ECSCluster"
...
TaskDefinition: !Ref TaskDefinition!Explode Prefix
LoadBalancers:
- ContainerName: !Sub '!Explode Prefix${ServiceName}'
ContainerPort: !Ref "ContainerPort"
TargetGroupArn: !Ref TargetGroup!Explode Prefix
LoadBalancerRule:
ExplodeMap: ServiceMap
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
...
ListenerArn: !Ref "LoadBalancerListener"
Priority: !Ref "Priority"
This seems to be successful, but for transformation specified within the DependsOn property. As I create the stack, this is the error I receive:
Template format error: Every DependsOn value must be a string.
Questions:
- I don't know how to actually view the transformed template
- Why does this happen? As per the doc, !Sub creates a string
Any ideas how t

Not really sure what the difference between !Sub 'LoadBalancerRule${!Explode Prefix}' & - LoadBalancerRule!Explode Prefix is, but this worked out
Service:
ExplodeMap: ServiceMap
Type: AWS::ECS::Service
DependsOn:
- LoadBalancerRule!Explode Prefix
Properties:
Cluster: !Ref "ECSCluster"
...
TaskDefinition: !Ref TaskDefinition!Explode Prefix
LoadBalancers:
- ContainerName: !Sub '!Explode Prefix${ServiceName}'
ContainerPort: !Ref "ContainerPort"
TargetGroupArn: !Ref TargetGroup!Explode Prefix

Related

AWS Cloudformation - security group ids list export and import - SecurityGroupIds not valid

Im working with 2 nested stacks. I need to use security group ids exported from NestedA in NestedB. The exported security group ids are to be used in a SecurityGroupIds property in NestedB based on conditions.
However cloudformation returns error: Property validation failure: [Value of property {/LaunchTemplateData/SecurityGroupIds/0} does not match type {String}]
The following are snippets of what I have tried:
NestedA export
Outputs:
SG1
Value: !Join
- ','
- - !Ref securitygroup1
- !Ref securitygroup2
Export:
Name: !Sub ${ExportVpcStackName}-SG1
SG2
Value: !Join
- ','
- - !Ref securitygroup3
- !Ref securitygroup4
Export:
Name: !Sub ${ExportVpcStackName}-SG2
ParentStack
Resources:
...
launchtemplate:
Type: AWS::Cloudformation::Stack
Properties:
TemplateURL: https://s3/nestedB.yaml
...
SG1:
Fn::ImportValue: !Sub ${ExportVpcStackName}-SG1
SG2:
Fn::ImportValue: !Sub ${ExportVpcStackName}-SG2
NestedB import
Parameters:
SG1
Type: List<AWS::EC2::SecurityGroup::Id>
SG2
Type: List<AWS::EC2::SecurityGroup::Id>
Resources:
launchtemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
...
SecurityGroupIds:
!If
- Condition1
-
- !Ref SG1
- !Ref SG2
- !If
- Condition2
-
- !Ref SG1
- !Ref AWS::NoValue
Ive also tried importing each of the security groups directly/individually into NestedB with no success ie:
NestedA export
Outputs:
securitygroup1:
Value: !Ref securitygroup1
Export:
Name: !Sub ${ExportVpcStackName}-securitygroup1
securitygroup2:
Value: !Ref securitygroup2
Export:
Name: !Sub ${ExportVpcStackName}-securitygroup2
securitygroup3:
Value: !Ref securitygroup3
Export:
Name: !Sub ${ExportVpcStackName}-securitygroup3
securitygroup4:
Value: !Ref securitygroup4
Export:
Name: !Sub ${ExportVpcStackName}-securitygroup4
NestedB import
Resources:
launchtemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
...
SecurityGroupIds:
!If
- Condition1
-
- Fn::ImportValue: !Sub ${ExportVpcStackName}-securitygroup1
- Fn::ImportValue: !Sub ${ExportVpcStackName}-securitygroup2
- Fn::ImportValue: !Sub ${ExportVpcStackName}-securitygroup3
- Fn::ImportValue: !Sub ${ExportVpcStackName}-securitygroup4
- !If
- Condition2
-
- Fn::ImportValue: !Sub ${ExportVpcStackName}-securitygroup1
- Fn::ImportValue: !Sub ${ExportVpcStackName}-securitygroup2
- !Ref AWS::NoValue
Whats the error Im making?
Edit: I have tried #marcin suggestion but still get the error:
Property validation failure: [Value of property {/LaunchTemplateData/SecurityGroupIds/0} does not match type {String}]
Instead of Type: List<AWS::EC2::SecurityGroup::Id>, please use CommaDelimitedList.
Also your SG1 is a list of SGs. You have to use Fn::Select to get individual SG values from the list.

Export and ImportValue in another stack under sub

I am trying to get a value from one stack to another using the below syntax.
stack one-
Outputs:
CompRestAPI:
Description: Rest Api Id
Value: !Ref CompRestAPI
Export:
Name: 'CompRestAPI'
Stack two -
CompRestApiWaf:
Type: AWS::WAFv2::WebACLAssociation
DependsOn: CompApiGatewayStage
Properties:
RestApiId: !ImportValue 'CompRestAPI'
ResourceArn: !Sub 'arn:aws:apigateway:${REGION}:/${RestApiId}/${STAGENAME}-apistage'
WebACLArn: !Ref WafId
I am able to get the values for other resources using 1st syntax, but I am not able to get the value for RestApiId under !Sub
RestApiId: !ImportValue 'CompRestAPI'
ResourceArn: !Sub 'arn:aws:apigateway:${REGION}:/${RestApiId}/apistage'
So is there any way to use !ImportValue under !Sub condition?
I tried it using below code, validation is pass but still showing me an error
Error reason: The ARN isn't valid. A valid ARN begins with arn: and includes other information separated by colons or slashes., field: RESOURCE_ARN, parameter:
CompRestApiWaf:
Type: AWS::WAFv2::WebACLAssociation
DependsOn: CompApiGatewayStage
Properties:
ResourceArn: !Sub 'arn:aws:apigateway:${REGION}:/{!ImportValue CompRestAPI}/stages/apistage'
WebACLArn: !Ref WafId
I am done with it using Fn::join:
SourceArn:
Fn::Join:
- ""
- - 'arn:aws:execute-api:'
- !Ref AWS::Region
- ':'
- !Ref AWS::AccountId
- ':'
- !Ref ApiGatewayRestApiResource
- '/*'
this should work
ResourceArn: !Sub
- 'arn:aws:apigateway:${REGION}:/${CompRestAPI}/stages/apistage'
- CompRestAPI: !ImportValue CompRestAPI
you can expand the second parameter to have multiple keys for multiple imports like so
SecretString: !Sub
- 'postgres://${username}:${password}#${dbhost}:${dbport}/${dbname}'
- username: !Ref 'DBUser'
password: !Ref 'DBPassword'
dbhost: !Ref DbMasterDnsEntry
dbport: !GetAtt AuroraPgCluster.Endpoint.Port
dbname: !Ref 'DBName'

AWS CloudFormation Fn::ImportValue doesn't like !Join?

I have the following resource in my CloudFormation template that's trying to create a listener rule. The idea is, based on the passed-in EnvironmentType, and the AWS Region, I want to import the listener ARN from the appropriate CloudFormation stack that exported it.
Parameters:
EnvironmentType:
Type: String
Default: "sandbox"
ECSClusterStackNameParameter:
Type: String
Default: "ECS-US-Sandbox"
Mappings:
production:
us-east-1:
stackWithAlbListenerInfo: "ECS-US-Prod"
eu-north-1:
stackWithAlbListenerInfo: "ECS-EU-Prod"
staging:
us-east-1:
stackWithAlbListenerInfo: "ECS-US-Staging"
eu-north-1:
stackWithAlbListenerInfo: ""
sandbox:
us-east-1:
stackWithAlbListenerInfo: "ECS-US-Sandbox"
eu-north-1:
stackWithAlbListenerInfo: ""
Conditions:
StackExists:
!Not [ !Equals [ !FindInMap [ !Ref EnvironmentType, !Ref "AWS::Region", stackWithAlbListenerInfo ], ""] ]
Resources:
AlbListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Condition: UseListenerRule
Properties:
ListenerArn:
!If
- StackExists
-
- Fn::ImportValue:
!Join
- "-"
- - !FindInMap [ !Ref EnvironmentType, !Ref "AWS::Region", stackWithAlbListenerInfo ]
- "ListenerArn"
- Fn::ImportValue:
- !Sub "${ECSClusterStackNameParameter}-ListenerArn"
However, it fails validation due to this error, and seems like the first Fn::ImportValue: doesn't like the !Join. But !Join returns a concatenated string correct? What am I missing?
ERROR: Service: marcom-stats-service, cfnUpdate error: com.amazonaws.services.cloudformation.model.AmazonCloudFormationException: Template error: the attribute in Fn::ImportValue must be a string or a function that returns a string (Service: AmazonCloudFormation; Status Code: 400; Error Code: ValidationError; Request ID: 2678552e-cf6c-46e1-b640-a7c07de385c2; Proxy: null)
UPDATE:
Though Robert Kossendey's answer fixed my error, my original template was wrong. This is really what I wanted to do. I hope it helps someone.
AlbListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Condition: UseListenerRule
Properties:
ListenerArn:
Fn::ImportValue: !Sub
- ${StackName}-ListenerArn
- { StackName: !If [ StackExists, !FindInMap [ !Ref EnvironmentType, !Ref "AWS::Region", stackWithAlbListenerInfo ], !Ref ECSClusterStackNameParameter ] }
Now I see it I think. At the second import you need to remove the dash in front of the !Sub:
- Fn::ImportValue:
!Sub "${ECSClusterStackNameParameter}-ListenerArn"

AWS CloudFormation - AWS::ElasticLoadBalancingV2::LoadBalancer - SecurityGroups

Is there a possibility in CFN templates to add some specific Security Groups to ALB depending on the parameter?
I have a situation where two security groups are adding to the ALB:
ALB
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
...
SecurityGroups:
- !Ref 'SecurityGroup1'
- !Ref 'SecurityGroup2'
Now there is a SecurityGroup3 that I would like to eventually add only if some parameter has a specific value. Let's say if parameter add_sg3 equals yes then the third SG is added to ALB. I always use "!If in similar situations but there are more than 2 SGs. Any advice would be welcome. Thanks!
You can achieve that using a Condition and the AWS::NoValue pseudo-parameter. Follow below a complete example:
Parameters:
Environment:
Type: String
Default: dev
AllowedValues: ["dev", "prod"]
VpcId:
Type: 'AWS::EC2::VPC::Id'
Subnet1:
Type: 'AWS::EC2::Subnet::Id'
Subnet2:
Type: 'AWS::EC2::Subnet::Id'
Conditions:
MyTest: !Equals ["dev", !Ref Environment]
Resources:
ALB:
Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer'
Properties:
SecurityGroups:
- !Ref SecurityGroup1
- !If [ MyTest, !Ref SecurityGroup2, !Ref 'AWS::NoValue' ]
Subnets:
- !Ref Subnet1
- !Ref Subnet2
SecurityGroup1:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: 'Group 1'
VpcId: !Ref VpcId
SecurityGroup2:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: 'Group 2'
VpcId: !Ref VpcId

Nested Fn::ImportValue in Fn::Sub not working for SAM template

Description:
I am trying to define Serverless API resource. But having trouble in defining location of swagger specification file using function ImportValue.
Steps to reproduce the issue:
I am not able to define AWS::Serverless::Api resource having nested function ImportValue in Location. I have tried following three ways, none of them work.
Note: Stack parameters are defined properly and export value from other stack exists. Not showing them here for brevity reason.
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
Name: !Sub ${AWS::StackName}-API
StageName: !Ref ApiGatewayStageName
DefinitionBody:
'Fn::Transform':
Name: 'AWS::Include'
Parameters:
Location:
Fn::Sub:
- s3://${BucketName}/${SwaggerSpecificationS3Key}
- BucketName:
Fn::ImportValue:
!Sub "${EnvironmentName}-dist-bucket-${AWS::Region}"
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
Name: !Sub ${AWS::StackName}-API
StageName: !Ref ApiGatewayStageName
DefinitionBody:
'Fn::Transform':
Name: 'AWS::Include'
Parameters:
Location:
Fn::Sub:
- s3://${BucketName}/${SwaggerSpecificationS3Key}
- BucketName:
!ImportValue 'dev-dist-bucket-us-east-1'
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
Name: !Sub ${AWS::StackName}-API
StageName: !Ref ApiGatewayStageName
DefinitionBody:
'Fn::Transform':
Name: 'AWS::Include'
Parameters:
Location:
Fn::Sub:
- s3://${BucketName}/${SwaggerSpecificationS3Key}
- BucketName:
Fn::ImportValue: 'dev-dist-bucket-us-east-1'
Cloudformation shows following error.
FAILED - The value of parameter Location under transform Include must
resolve to a string, number, boolean or a list of any of these.
However, if I do not use ImportValue it works with a nested Fn::Sub
ApiGatewayApi:
Type: AWS::Serverless::Api
Properties:
Name: !Sub ${AWS::StackName}-API
StageName: !Ref ApiGatewayStageName
DefinitionBody:
'Fn::Transform':
Name: 'AWS::Include'
Parameters:
Location:
Fn::Sub:
- s3://${BucketName}/${SwaggerSpecificationS3Key}
- BucketName:
Fn::Sub: dist-bucket-${EnvironmentName}-${AWS::Region}
Is it because of Fn::Transform or AWS::Include?