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?
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:
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
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.