NodeJS:aws-sdk sts.assumeRole无法正常工作。

4

我遇到了一个奇怪的问题,一直无法解决。我已经按照网上的指导(多个教程等)进行了操作,但无法让 sts.assumeRole 起作用。

我的设置如下:

  • 主 AWS 帐户(用于计费、IAM 等)
  • 子 AWS 帐户 1(用于客户 1)
  • 子 AWS 帐户 2(用于客户 2)
  • 等等

我在 子 AWS 帐户 1 中运行着一个机器人,需要从 主 AWS 帐户 获取定价信息。

所以,我在 主 AWS 帐户 上创建了一个角色,拥有 AWS ce:* 访问权限,如下:

{
    "Version": "2012-10-17",
    "Statement": [{
            "Effect": "Allow",
            "Action": ["ce:*"],
            "Resource": ["*"]
        }]
}

信任关系

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com",
        "AWS": "arn:aws:iam::SubAWSaccount1-ID:role/instance-profile"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

现在,这是附加到在Sub AWS账户1上运行的EC2实例的实例配置文件

"Version": "2012-10-17",
"Statement": [
    {
        "Sid": "VisualEditor1",
        "Effect": "Allow",
        "Action": "sts:AssumeRole",
        "Resource": "arn:aws:iam::mainAWSaccount-ID:role/botRole"
    }
  ]
}

信任关系

{
  "Version": "2012-10-17",
  "Statement": [
   {
    "Sid": "",
    "Effect": "Allow",
    "Principal": {
      "Service": "ec2.amazonaws.com"
    },
    "Action": "sts:AssumeRole"
   }
  ]
}

好的,既然如此,这是未能正常工作的代码:

好的,请注意,这是未能正常工作的代码:

var AWS = require('aws-sdk');
var pricingAWS = new AWS.CostExplorer();

var getPricing = function(){

    var costParams = {
        TimePeriod: { Start: "2019-12-01 ", End: "2020-01-01"},
        Granularity: 'MONTHLY',
        Metrics: ['BlendedCost'],
        Filter: {      
            Dimensions: {
                Key: "LINKED_ACCOUNT",
                Values: ["Sub AWS account 2s ID"] //Main AWS account has access to many sub accounts info. So bot in running on Sub account 1, I need info from Sub account 1, 2, 3 etc and Role is on Main account
            }
        }
    };

    var roleToAssume = {
        RoleArn: 'arn:aws:iam::mainAWSaccount-ID:role/botRole',
        RoleSessionName: 'testTestTest',
        DurationSeconds: 900
    };

    var roleCreds = {};

    sts.assumeRole(roleToAssume, function(err, data) {
        if (err) {
            console.log(err);
        } else {
            roleCreds = {
                accessKeyId: data.Credentials.AccessKeyId,
                secretAccessKey: data.Credentials.SecretAccessKey,
                sessionToken: data.Credentials.SessionToken
            };

            pricingAWS.config.update({
                accessKeyId: roleCreds.AccessKeyId,
                secretAccessKey: roleCreds.SecretAccessKey,
                sessionToken: roleCreds.SessionToken
              });
        }
    });

    pricingAWS.getCostAndUsage(costParams, function (err, data) {
        if (err) {
            reject(err);
        }else{
            resolve(data);
        }
    });
};

getPricing();

我从console.log(err)中获取的结果是:

User: arn:aws:sts::SubAWSAccount-1:assumed-role/slack-instance-profile/instanceID is not authorized to perform: ce:GetCostAndUsage on resource: arn:aws:ce:us-east-1:SubAWSAccount-1:/GetCostAndUsage'
1个回答

7
为确认我的理解,您正在尝试从一个账户的EC2实例中扮演另一个账户中的角色。
以下是需要进行的操作:
  1. 在“子”账户中创建IAM角色
  2. 通过附加IAM策略,允许新创建的角色扮演“主”账户中存在的角色。允许子角色通过主角色的信任策略扮演主角色(您已经在执行此操作)
  3. 在运行于子EC2实例中的Nodejs代码中,扮演父角色并读取账单报告(您已经在执行此操作)

代码修复

pricingAWS.getCostAndUsage() 代码行移至扮演角色回调函数内部,因为该行在凭证更新之前被调用 :). 您也可以像下面演示的一样将所有内容更改为async/await模式。
import AWS = require('aws-sdk');
var pricingAWS = new AWS.CostExplorer();
const sts = new AWS.STS()

var getPricing = async function () {

  var costParams = {
    TimePeriod: { Start: "2019-12-01 ", End: "2020-01-01" },
    Granularity: 'MONTHLY',
    Metrics: ['BlendedCost'],
    Filter: {
      Dimensions: {
        Key: "LINKED_ACCOUNT",
        Values: ["Sub AWS account 2s ID"] //Main AWS account has access to many sub accounts info. So bot in running on Sub account 1, I need info from Sub account 1, 2, 3 etc and Role is on Main account
      }
    }
  };

  var roleToAssume = {
    RoleArn: 'arn:aws:iam::mainAWSaccount-ID:role/botRole',
    RoleSessionName: 'testTestTest',
    DurationSeconds: 900
  };

  var roleCreds = {};


  try {

    const data = await sts.assumeRole(roleToAssume).promise();
    const roleCreds = {
      accessKeyId: data.Credentials.AccessKeyId,
      secretAccessKey: data.Credentials.SecretAccessKey,
      sessionToken: data.Credentials.SessionToken
    };

    pricingAWS.config.update({
      accessKeyId: roleCreds.accessKeyId,
      secretAccessKey: roleCreds.secretAccessKey,
      sessionToken: roleCreds.sessionToken
    });

    const costAndUsage = await pricingAWS.getCostAndUsage(costParams).promise()
    return costAndUsage
  } catch (err) {
    console.log('error: ', err);
    throw err;
  }

};

getPricing();

希望这能有所帮助。

没有起作用。实际上,IAM因为该AWS账户下的角色不存在而出现错误。 - Sean
嘿,Arun。你解释的就是我想要做的事情。我只是不知道该怎么做,或者为什么会失败,因为我觉得我已经做得没问题了。 - Sean
当我在实例上运行以下命令时: aws sts assume-role --role-arn arn:aws:iam::mainAccountID:role/roleName --role-session-name "botRole" - 它可以正常工作!因此,我认为这消除了基础架构设置问题的可能性。但是我的代码看起来完美无缺...... - Sean
我还注意到,您正在使用roleCreds.AccessKeyId,但是您正在设置roleCreds = { accessKeyId: 'value'}。应该是小写的access而不是大写。祝好运。 - Arun Kamalanathan
1
这就解决了,伙计!我一直固执地认为这是AWS库或我的使用方法的问题,而忽略了基础知识。非常感谢你。我欠你一瓶啤酒。 - Sean
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接