Getting handle "accountId" in serverless config

aws

#1

Is there a simple way to get the AWS Account ID as a variable in the serverless.yml? I’m trying to lock down IAM rights very specifically and it would be nice to have a dynamic way of getting the ID rather than requiring it to be hardcoded into the configuration.


#2

@yankeeinlondon are you trying to get the AccountID in CloudFormation. Can you use a Pseudo Parameter ? i.e. AWS::AccountId - http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/pseudo-parameter-reference.html


#3

Yes @johncmckim that looks exactly right. Sorry never sure whether I should be looking for things in cloudfront, serverless, or elsewhere. So if I’m understanding correctly I could put something like this in my serverless.yml:

custom:
    accountId: !Ref AWS::AccountId

I’m running to a meeting but will plug it in this afternoon.


#4

@yankeeinlondon no worries. All part of learning. You won’t be able to use it in that part of the serverless.yml.

See this example

service: foo
provider: # Not CloudFormation
  name: aws
  iamRoleStatements: # You can use CloudFormation here
    ...


functions: #  Not CloudFormation
 ....
resources:
  Resources: # This section is CloudFormation
    SomeResource:
       Type: AWS::IAM::Role
       ...
           # something like this to build an ARN
           Resource:
             Fn::Sub: 'aws:ec2:${AWS::Region}:${AWS::AccountId}:xxxxx:xxx/*'

If you’re just using the AccountId from IAM you should be able to use it directly rather than through a custom property.

Hope that makes sense. P.S. it’s off the top of my head so there might be syntax issue but should be close :slight_smile:


#5

Hmmm. Tried your suggestion and got:

Invalid variable reference syntax for variable AWS::Region.
You can only reference env vars, options, & files. You
can check our docs for more info.


#6

Ah yes sorry. Again, was off the top of my head. That’s an issue with Fn::Sub right now. The syntax for variables i.e. ${blah} conflicts with Serverless. It’s a PITA. You would normally be able to use variableSyntax to work around that but there’s a bug

You might have to do something like this instead:

Fn::Join: ["", [ "aws:ec2:", { "Ref": "AWS::Region" }, ':', { Ref: "AWS::AccountId" }, ":xxx:xxx/*" ]]

Clearly that’s no where near as nice as Fn::Sub


#7

Well lots of thanks for your help. Don’t think I’d have gotten there myself. For now I’ll wildcard the accountId as I have the stage and region available locally in the serverless.yml and that’s pretty good resolution. I’ve tested and this seems to work:

Resource: 
    - "arn:aws:lambda:${self:custom.region}:*:function:serverless-event-${self:custom.stage}-*"

#8

Hi … I was wondering if there was any progress on the ability to distinguish AWS variables from serverless variables, or at least to escape the serverless variable replacement functionality … it seems like a pretty useful ability so that I can pass a string literal to AWS for it to use to replace variables. From what I can tell variableSyntax that is referred to above isn’t active right now? No documentation that I can find …


#9

I’ve been down this road myself. Here’s the comment I made to remind me of the problems, and the variableSyntax I’m using to get past this issue:

provider:
  name: aws
  runtime: nodejs4.3
  # by default AWS variables like ${saml:sub} use same format as Serverless variables like ${self:custom.prefix}
  # We use variableSyntax here to change serverless vars to look instead like ${{self:custom.prefix}}
  variableSyntax: '\${{([\s\S]+?)}}'

With that in place, I can now use Fn::Sub basically as indicated by @johncmckim

Resource: 
- Fn::Sub: 'arn:aws:iot:${AWS::Region}:${AWS::AccountId}:topicfilter/public/*'

Don’t forget to then change all your Serverless variables as indicated in the comment above-- ${self:custom.whatever} becomes ${{self:custom.whatever}}


#10

Oh, that’s a really sweet idea @donpedro … I’m definitely going to do that, thanks!


#11

Hey, @donpedro … thanks for the idea, had to adjust your regular expression a little bit to make it work with my recursive variables, thought you might want to know about it:

variableSyntax: '\${{(((?!\${{).)+?)}}'

Now works for things like this:

DefaultCurrency: ${{self:custom.${{opt:region, self:provider.region}}.${{opt:stage, self:provider.stage}}.DefaultCurrency}}

Thanks again! seems like this feature is somewhat undocumented.


#12

@cdichiara I expanded on your regex to

variableSyntax: '\${((self|opt):((?!\${).)+?)}'

The difference is I do not need to wrap my serverless variables in the extra {}

${self:custom.${self.custom.other}}

#13

Thank you for that solution! It doesn’t make much sense to me that Serverless uses the same variable syntax as CloudFormation.

I’ve changed mine accordingly:

variableSyntax: '\$\(([\s\S]+?)\)'

#14

What about this one ?

(?!${AWS::)${([\s\S]+?)}

If you only want to avoid issues with AWS pseudo parameters, it should do the trick without having to deal with changing format of all serverless variables


#15

Ok, easier solution: User the “serverless-pseudo-parameters” plugin.

It fixed my issue instantly by replacing $ character by # in my resource declarations.


#16

This is a much easier solution. :-1:
Works for me.