28

I am trying to create an AWS cloudformation stack using a yaml template. The goal is to create a sns topic for some notifications. I want to output the topic arn, to be able to subscribe multiple functions to that topic by just specifying the topic arn.

However I am getting an error when I try to create the stack from the aws console:

"Template validation error: Template error: resource NotificationsTopic does not support attribute type Arn in Fn::GetAtt"

I have done exactly the same for s3 buckets, dynamodb tables, and all working good, but for some reason, with SNS topic I cannot get the ARN.

I want to avoid hardcoding the topic arn in all functions that are subscribed. Because if one day the the ARN topic changes, I'll need to change all functions, instead I want to import the topic arn in all functions and use it. This way I will have to modify nothing if for any reason I have a new arn topic in the future.

This is the template:

    Parameters:
  stage:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - int
      - uat
      - prod

Resources:
   NotificationsTopic:
        Type: AWS::SNS::Topic
        Properties:
          DisplayName: !Sub 'notifications-${stage}'
          Subscription:
            - SNS Subscription
          TopicName: !Sub 'notifications-${stage}'
Outputs:
  NotificationsTopicArn:
    Description: The notifications topic Arn.
    Value: !GetAtt NotificationsTopic.Arn
    Export:
      Name: !Sub '${AWS::StackName}-NotificationsTopicArn'
  NotificationsTopicName:
    Description: Notifications topic name.
    Value: !Sub 'notifications-${stage}'
    Export:
      Name: !Sub '${AWS::StackName}-NotificationsTopicName'
fgonzalez
  • 3,787
  • 7
  • 45
  • 79

2 Answers2

42

Not all resources are the same. Always check the documentation for the particular resource. It has the "Return Values" section and you can easily verify that SNS topic has ARN as a Ref value, so you don't have to use GetAtt function

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html

Edit: Thanks for the comment which points out that not every resource provides its ARN. A notable example is the Autoscaling group. Sure, the key thing in my answer was "check the documentation for each resource", this is an example that not every resource has every attribute. Having said that, ARN missing for the ASG output is a really strange thing. It cannot be also constructed easily, because the ARN also contains GroupId which is a random hash. There is probably some effort to solve this at least for the use-case of ECS Capacity Providers https://github.com/aws-cloudformation/aws-cloudformation-coverage-roadmap/issues/548 and https://github.com/aws/containers-roadmap/issues/631#issuecomment-648377011 but I think that is is an significant enough issue that it should be mentioned here.

petrch
  • 1,807
  • 15
  • 19
  • 1
    What do you do about the attributes that neither !GetAtt nor !Ref support? Like `HostedZone.Name`: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-hostedzone.html – Manav Kataria Sep 21 '19 at 04:58
  • Well, I am not in a position to argue on AWS's behalf, but CF is not a comprehensive scripting language, you have the zone Id, you can pass it to a lambda/ec2 and there you can call describe the zone with the id as an argument and progress from there. – petrch Sep 25 '19 at 21:12
  • Return Values, of course! I was actually trying to target the NAME of a resource with `Fn::GetAttr` and this answer helped me see that `TargetGroup.Name` should actually be `TargetGroup.TargetGroupName`. This was very helpful, thank you. – daevski Nov 11 '20 at 15:21
  • 1
    This answer is only helpful if the target resource returns an ARN when invoked by `Ref`. It doesn't explain how to get an ARN for a resource whose ARN is not returned by `Ref`. Take `AWS::AutoScaling::AutoScalingGroup` - `Ref` doesn't return an ARN, but it's ARN is often needed (i.e., as a value for `AWS::ECS::CapacityProvider AutoScalingGroupProvider.AutoScalingGroupArn`) [docs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-capacityprovider-autoscalinggroupprovider.html). – teuber789 Mar 15 '21 at 18:13
  • @teuber789 thanks for the comment. I did not run into this issue, because we do use rather Fargate when needed. But this is a really strange quirk indeed. I found there is an effort to solve this https://github.com/aws-cloudformation/aws-cloudformation-coverage-roadmap/issues/548 , but the only workaround I can see for now is a custom CF resource with lambda which would describe the ASG and return its ARN. Well, nothing is perfect. – petrch Mar 15 '21 at 20:46
3

For resources that don't directly return ARN, I found a workaround which consists of building the ARN myself.

For instance, to get the ARN of my codepipeline:

!Join [ ':', [ "arn:aws:codepipeline", !Ref AWS::Region, !Ref AWS::AccountId, !Ref StackDeletePipeline ] ]
aboitier
  • 180
  • 11