Search code examples
aws-lambdaopensearchamazon-opensearch

Accessing Opensearch Serverless from a Lambda in AWS


I'm trying to access my Opensearch Serverless collection using a Nodejs lambda. This is what my lambda code looks like:

import { Client } from '@opensearch-project/opensearch';
const REGION = 'eu-central-1';
const SEARCH_ENDPOINT = 'some-endpoint.eu-central-1.es.amazonaws.com';

const client = new Client({
  node: SEARCH_ENDPOINT
});

export const handler = async (event, context) => {
  try {
    client.indices.create({ index: 'restaurants' }).then(() => {
      console.log(`Index restaurants created`);
    });

    
    await client.bulk({ body: somebody });

    return {
      statusCode: 200,
      body: 'Data inserted into OpenSearch successfully.'
    };
  } catch (error) {
    //error handling
  }
};

However when trying to execute the lambda with some dummy event I get the following Access Denied error:

User: arn:aws:sts::xxxxxxxx is not authorized to perform: aoss:APIAccessAll because no identity-based policy allows the aoss:APIAccessAll action

How can I make my Lambda access my AOSS collection?


Solution

  • The documentation unluckily is not one of the best, but first off you need to create a data access policy inside your Opensearch Serverless collection where you add a rule with:

    • as Principal: your lambda role
    • as grants/permissions: based on what the lambda should do with the collection

    enter image description here

    enter image description here

    If you don't know your lambda role, you can just go to your lambda detail page and then navigate to 'Configuration > Permissions' and its sitting right on top of that page

    enter image description here

    After that you should give to the lambda role the access policy to perform the aoss:APIAccessAll action. Now I didn't find any 'pre-made' access policy so I created a new one with name OpensearchServerlessAPICaller with the following json policy

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

    With everything in place now your lambda CAN perform calls directly to your Opensearch Serverless collection. Meanwhile to actually perform calls you need to correctly authenticate, and using @opensearch-project/opensearch, means having something like this:

    import { AwsSigv4Signer } from '@opensearch-project/opensearch/aws';
    import { Client } from '@opensearch-project/opensearch';
    import { defaultProvider } from '@aws-sdk/credential-provider-node'
    
    const client = new Client({
      node: "Your opensearch host",
      ...AwsSigv4Signer({
        region: 'eu-central-1',
        service: 'aoss',
    
        getCredentials: () => {
          const credentialsProvider = defaultProvider();
          return credentialsProvider();
        },
      }),
    });
    

    The default credentials provider here should be fine since you are using a lambda after all

    Sidenote: Keep in mind that if you opted to protect your opensearch collection within a VPC then you should place the lambda within the same VPC otherwise it's not going to reach the collection.