Reference AWS ARN in serverless.ts file

How can I reference the ARN of a resource in a serverless.ts file? Details below…

I created a new Serverless project with the command: serverless create --template aws-nodejs-typescript. I noticed that I am supplied with a serverless.ts file now rather than a serverless.yml file.

In the old serverless.yml file I can get a resource’s ARN by using the following code:

custom:
  AuctionsTable:
  arn: !GetAtt AuctionsTable.Arn

I can reference that code elsewhere in the serverless.yml with the following code:

  Resource:
  - ${self:custom.AuctionsTable.arn}

When I use the sls print command, that code becomes CF code that looks like this:

      Resource:
      - 'Fn::GetAtt':
          - AuctionsTable
          - Arn

With the serverless.ts file, that same code does not become the same CF code. The following code:

  custom: {
    auctionsTable: {
      arn: "!GetAtt AuctionsTable.Arn"
  }

Becomes the following after sls print:

      Resource:
      - '!GetAtt AuctionsTable.Arn'

Which produces the following error when trying to deploy:

Resource !GetAtt AuctionsTable.Arn must be in ARN format or "*".

It seems like Serverless framework isn’t converting:

!GetAtt AuctionsTable.Arn

to:

          Resource:
          - 'Fn::GetAtt':
            - AuctionsTable
            - Arn

Any ideas on how to workaround this? Or am I taking the wrong approach?

I learned that you can reference an ARN using the following syntax:

  Resource: {
    "Fn::GetAtt": ["AuctionsTable, "Arn"],
  },

The file awsProvider.d.ts proved to be helpful here. The IamRoleStatement shows an indexable type can be provided to the Resource field:

    interface IamRoleStatement {
      Effect: 'Allow' | 'Deny';
      Sid?: string;
      Condition?: {
          [key: string]: any;
      };
      Action?: string | string[] | { [key: string]: any };
      NotAction?: string | string[] | { [key: string]: any };
      Resource?: string | string[] | { [key: string]: any };
      NotResource?: string | string[] | { [key: string]: any };
  }

Just a quick note - @scott 's answer is right on (there’s a missing quote in his Resource example, otherwise perfect).

If you are using SNS you can’t call Fn::GetAtt and need to do this:

iamRoleStatements: [
  {
    Effect: 'Allow',
    Action: ['sns:Publish'],
    Resource: {
      "Ref": "doMagic",
    },
  }
]

where doMagic is the resource. Because GetAtt is not available on SNS for obtaining the ARN.

Hopefully that helps someone else out!

1 Like

Hi, I am having trouble getting this work. I am trying to attach lambda func with dynamo stream. could you please help. It would be great if you can share any documentation for serverless.ts file

handleMdmEventStream: {
      name: '${self:custom.name}-handleMdmEventStream',
      handler: 'src/triggers/mdm-stream-trigger.handler',
      events: [
        {
          stream: {
            arn: {
              "Fn::GetAtt": ["loggers", "StreamArn"]
            },
          }
        }
      ]
    },
1 Like

Using the typescript node.js serverless template, I was able to use a Kinesis Stream Arn using the following syntax:

functions: {
    ingestion: {
      handler: 'handler.ingestStream',
      events: [
        {
          stream: {
            type: 'kinesis',
            arn: { 'Fn::GetAtt': ['SuperSweetStream', 'Arn'] },
          },
        }
      ]
    }
  },
resources: {
    Resources: {
      'SuperSweetStream': {
        'Type' : 'AWS::Kinesis::Stream',
        'Properties' : {
            'Name' : '${self:service}-stream',
            'RetentionPeriodHours' : 24,
            'ShardCount' : 3,
          }
      }
    }
  }
1 Like

@cgradwohl can you please also share the Kinesis stream definition you used? Thanks!