CloudFormation ForEach OutputKey processing

0

We have the following CloudFormation template that creates subscriptions from one SQS queue to one or more SNS topics. We need it to be dynamic since we don't know how many topics we will have beforehand.

...
Transform: "AWS::LanguageExtensions"

Parameters:
  TopicNames:
    Type: CommaDelimitedList
    Description: A list of SNS topic Names.
  QueueArn:
    Type: String
    Description: QueueArn.

Resources:
  Fn::ForEach::Subscription:
    - TopicName
    - !Ref TopicNames
    - !Join [ "", !Split [ "-", !Sub "SnsSubscription${TopicName}" ] ]:
        Type: AWS::SNS::Subscription
        Properties:
          Protocol: sqs
          Endpoint: !Ref QueueArn
          Region: !Ref "AWS::Region"
          TopicArn: !Sub "arn:aws:sns:${AWS::Region}:${AWS::AccountId}:${TopicName}"

The problem is that the topic names will contain hyphens, so we cannot just use SnsSubscription${TopicName} in the ForEach OutputKey (because Resource Logical IDs have to be alphanumeric).

The Split-Join strategy used in the snippet above fails with Error creating stack: An error occurred (ValidationError) when calling the CreateStack operation: Template format error: [/Resources/Fn::ForEach::Subscription/2] map keys must be strings; received a map instead. Join returns a string, as far as I know, I guess it has to do with how ForEach preprocesses this input.

Any idea on how to solve this? Is developing a custom macro our only option?

Thanks!

4 Answers
0

As far as I know, Fn::Join returns a string. After playing around with this for a bit, I was able to get an example working:

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::LanguageExtensions'
Parameters:
  QueueNames:
    Type: CommaDelimitedList
    Description: A list of SNS topic Names.
    Default: 'queue-1, queue-2, queue-3'
Resources:
  Fn::ForEach::Subscription:
    - QueueName
    - !Split [",", !Join ["", !Split ["-", !Join [",", !Split [", ", !Ref QueueNames]]]]]
    - "${QueueName}":
        Type: AWS::SQS::Queue
        Properties: 
          QueueName: !Sub "${QueueName}"

I am not sure what your topic names look like (other than having a dash in them), but this should be enough to get you where you need to go. The issue with the old template is that, as far as I can tell, you cannot use intrinsic functions for the "output key."

answered 7 months ago
0

Hi Dylan, thanks for your answer.

The problem with that solution, in our case, is that we also need the original TopicName (including hyphens and/or whatever other non-alphanumeric character) to build the TopicArn for the subscription (check the last line of the template snippet).

As you say, looks like just a "plain" string is allowed for the OutputKey.

answered 7 months ago
0

The same problem with Fn::ForEach in CloudFormation. Anyone can help? Thank you.

HuanNV
answered 7 months ago
0

Try this:

Transform: "AWS::LanguageExtensions"

Parameters:
  TopicNames:
    Type: CommaDelimitedList
    Description: A list of SNS topic Names.
  QueueArn:
    Type: String
    Description: QueueArn.

Resources:
  Fn::ForEach::Subscription:
    - TopicName
    - !Ref TopicNames
    - "SnsSubscription&{TopicName}":
        Type: AWS::SNS::Subscription
        Properties:
          Protocol: sqs
          Endpoint: !Ref QueueArn
          Region: !Ref "AWS::Region"
          TopicArn: !Sub "arn:aws:sns:${AWS::Region}:${AWS::AccountId}:${TopicName}"

From docs:

OutputKey The key in the transformed template. ${Identifier} or &{Identifier} must be included within the OutputKey parameter. For example, if Fn::ForEach is used in the Resources section of the template, this is the logical Id of each resource.

The &{} syntax allows non-alphanumeric characters in the Collection to be used in OutputKey parameter.

answered 4 months ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions