1
votes

I have 2 AWS accounts. Account 1 has a CloudSearch domain that I need to query from a Lambda function in account 2. I've followed a tutorial here for creating a role in account 1 that allows cross-account access.

So, in account 1 I have a role arn:aws:iam::111111111111:role/my_cloudsearch_query_role that looks like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "cloudsearch:search",
            "Resource": "*"
        }
    ]
}

This role has one trusted entity, account 2, and I can see the correct account ID under the Trusted Entities section for the role in the IAM console.

In account 2, I've created a Lambda function with an execution role that looks like this:

{
  "roleName": "my_cloudsearch_query_role",
  "policies": [
    {
      "document": {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Action": [
              "logs:CreateLogGroup",
              "logs:CreateLogStream",
              "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
          },
          {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::111111111111:role/my_cloudsearch_query_role"
          }
        ]
      },
      "name": "oneClick_lambda_basic_execution_1526469274620",
      "type": "inline"
    }
  ]
}

My Lambda function (Python 3) code tries to query CloudSearch like this:

client = boto3.client('cloudsearchdomain', endpoint_url=endpoint)
response = client.search(
    query="(and name:'foobar')",
    queryParser='structured',
    returnFields='curr_addr',
    size=1
)

All calls to the Lambda function fail with the following error:

An error occurred (AccessDenied) when calling the Search operation: User: arn:aws:sts::222222222222:assumed-role/my_cloudsearch_query_role/my_lambda_func is not authorized to perform: cloudsearch:search on resource: myCSDomain

I'm positive that I've gotten the account IDs correct so there's no mix-up. Is there something else I need to do to get it working?

1
You need to assume the role in account 111111111111 and then use the returned credentials to create your client object. Use assume_role boto3 API call to get the credentials. – krishna_mee2004
Ah, I thought the role would be assumed automatically. If you wanna throw that into an answer I’ll accept it for you – RTF
Sure. I will add an answer. – krishna_mee2004

1 Answers

4
votes

You need to assume the role in account 111111111111 and then use the returned credentials to create your client object. Use assume_role boto3 API call to get the credentials. Here's a sample code:

role_arn = "arn:aws:iam::111111111111:role/my_cloudsearch_query_role"
sts = boto3.client('sts', region_name="us-east-1")
token = sts.assume_role(RoleArn=role_arn, RoleSessionName="Session1")
credentials = token['Credentials']
access_key = credentials['AccessKeyId']
secret_key = credentials['SecretAccessKey']
token = credentials['SessionToken']
session = boto3.session.Session(
    aws_access_key_id=access_key,
    aws_secret_access_key=secret_key,
    aws_session_token=token
)
client = session.client('cloudsearchdomain', endpoint_url=endpoint)
response = client.search(...)

Please update the role_arn with the correct details. Documentation about Session object can be found here.