Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get AWS account id as custom variable in serverless framework?

In serverless framework, I want to set the deployment bucket as

<project_name>-<stage>-<account_id>

I can get the stage using a custom variable, like:

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

but how can I get the aws account id? I already tried to used serverless-pseudo-parameters, like this below, without success.

custom:
    account_id: #{AWS::AccountId}
plugins:
  - serverless-pseudo-parameters

Someone could help me to set the account id as a custom variable?

like image 929
bcosta12 Avatar asked Oct 09 '19 19:10

bcosta12


2 Answers

According to the documentation, to get the Account Id, you can use external js files:

// myCustomFile.js
module.exports.getAccountId = async (context) => {
    return context.providers.aws.getAccountId();
};

.

# serverless.yml
service: new-service
provider: aws
custom:
  accountId: ${file(../myCustomFile.js):getAccountId}
like image 147
filipebarretto Avatar answered Sep 24 '22 11:09

filipebarretto


For anyone using Serverless with an "assumed role" where your IAM users are defined in a master AWS account and you're trying to deploy in a child account using a role from that child account: the documented solution - the one in the accepted answer above - does not work.

This setup in described in detail here: https://theithollow.com/2018/04/30/manage-multiple-aws-accounts-with-role-switching/. When using serverless with an --aws-profile that's configured to assume a role defined in another account, sts.getCallerIdentity() returns the account info of your master account from the default profile, and not the account of the assumed role.

To get the account ID of the assumed role (which is where we're deploying to), I did the following:

const { STS } = require('aws-sdk');

module.exports.getAccountId = async (context) => {
  // This loads the AWS credentials Serverless is currently using
  // They contain the role ARN of the assumed role
  const credentials = context.providers.aws.getCredentials();

  // init STS using the same credentials
  const sts = new STS(credentials);
  const identity = await sts.getCallerIdentity().promise();
  return identity.Account;
};

Edit:

Found an even better way, that is simpler than the one presented in Serverless docs and also works fine with assumed roles:

module.exports.getAccountId = async (context) => {
  return context.providers.aws.getAccountId();
};
like image 32
Dan C. Avatar answered Sep 23 '22 11:09

Dan C.