Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS ElasticSearch write to account "A" from lambda in account "B"

I have an AWS ElasticSearch Cluster in account "A".

I'm trying to create a lambda (triggered from a DynamoDB Stream) in account "B" that will write to ES in account "A".

I'm getting the following error:

{
"Message":"User: arn:aws:sts::AccountB:assumed-role/lambdaRole1/sourceTableToES is not authorized to perform: es:ESHttpPost on resource: beta-na-lifeguard"
}

I have tried putting the STS as well as the ROLE into the ES access policy (within account "A") with no luck. Here is my policy:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::AccountA:user/beta-elasticsearch-admin"
      },
      "Action": "es:*",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::AccountA:user/beta-elasticsearch-readwrite",
          "arn:aws:iam::AccountA:role/beta-na-DynamoDBStreamLambdaElasticSearch",
          "arn:aws:sts::AccountB:assumed-role/lambdaRole1/sourceTableToES",
          "arn:aws:iam::AccountB:role/service-role/lambdaRole1"
        ]
      },
      "Action": [
        "es:ESHttpGet",
        "es:ESHttpPost",
        "es:ESHttpPut"
      ],
      "Resource": "*"
    }
  ]
}
like image 494
jhilden Avatar asked Jan 03 '23 08:01

jhilden


2 Answers

In my code above I was adding arn:aws:sts::AccountB:assumed-role/lambdaRole1/sourceTableToSNS into the AccountA ES access list, that is wrong. Instead do the following:

I already had arn:aws:iam::AccountA:role/beta-na-DynamoDBStreamLambdaElasticSearch in the ES access list, I needed to add a trust relationship (from the IAM role screen) for that role to be assumable by AccountB. I added this into the trust relationship:

{
  "Effect": "Allow",
  "Principal": {
    "AWS": "arn:aws:iam::AccountB:root"
  },
  "Action": "sts:AssumeRole"
}

Then, in my accountB lambda code, I needed to assume that role. Here is the relevent code from the lambda.

var AWS = require('aws-sdk');
var sts = new AWS.STS({ region: process.env.REGION });
var params = {
    RoleSessionName: "hello-cross-account-session",
    RoleArn: "arn:aws:iam::accountA:role/beta-na-DynamoDBStreamLambdaElasticSearch",
    DurationSeconds: 900
};
sts.assumeRole(params, function (err, data) {
    if (err) {
        console.log(err, err.stack); // an error occurred
        context.fail('failed to assume role ' + err);
        return;
    }
    log("assumed role successfully! %j", data)
    postToES(bulkUpdateCommand, context);
}); 
like image 189
jhilden Avatar answered Jan 13 '23 10:01

jhilden


When you create a "role" for another account you also need to setup the "Trust relationships". This is done in the AWS IAM console under "Roles". Second tab for your role is "Trust relationships". You will need to specify the account details for the other account as trusted.

The "Trust relationships" is a policy document itself. Here is an example that will allow you to call AssumeRole from another account to my AWS account.

    {
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::2812XXXXYYYY:root"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

In your role, just specify permissions as normal just like you were granting permissions for another IAM user / service (e.g. remove all those account type entries). The Trust relationships policy document defines who can call AssumeRole to be granted those permissions.

Creating a Role to Delegate Permissions to an IAM User

Modifying a Role

like image 28
John Hanley Avatar answered Jan 13 '23 11:01

John Hanley