I created a Table with the partitionKey as “id” and other attributes like: firstName, lastName etc… I also created an AWS Lambda, which I can interact with using API Gateway, with this IAM Permission Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:xxxxxxx/aws/lambda/test-production:log-stream:*",
"Effect": "Allow"
},
{
"Sid": "1",
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem"
],
"Resource": "arn:aws:dynamodb:xxxxxxxxxxxxxxxxxxx/xxxxxxx",
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": "${cognito-identity.amazonaws.com:sub}"
}
}
},
{
"Sid": "2",
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:BatchGetItem",
"dynamodb:Query"
],
"Resource": "arn:aws:dynamodb:xxxxxxxxxxxxxxx/xxxxx",
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:Attributes": [
"id",
"firstName",
"lastName"
]
},
"StringEqualsIfExists": {
"dynamodb:Select": "SPECIFIC_ATTRIBUTES"
}
}
}
]
}
The goal for this policy is to let common users to only be able to read specific attributes: like id, firstName, lastName etc… And let only the owner of the object read, write, delete the entire object, by checking the “sub” from the Cognito User Account.
This is what I implemented in the AWS Lambda using ExpressJS:
app.get("/user/:id", async function (req, res) {
const partitionKey = req.params.id;
const authProvider =
req.apiGateway.event.requestContext.identity.cognitoAuthenticationProvider;
const [userId] = authProvider.match(IDP_REGEX);
const isOwner =
userId != null && userId != undefined && userId === partitionKey;
const getItemParams = {
TableName: tableName,
Key: {
id: partitionKey,
},
ProjectionExpression: isOwner ? "" : "id, firstName, lastName",
};
try {
const data = await ddbDocClient.send(new GetCommand(getItemParams));
if (!data.Item) {
res.statusCode = 404;
return res.json({ error: "Item not found", url: req.url });
}
res.json({
success: "get call succeed!",
url: req.url,
body: req.body,
data,
});
} catch (error) {
res.statusCode = 500;
res.json({ error, url: req.url, body: req.body });
}
});
The call fails with a 502 error, when I’m logged in the with account of the owner of the object, but it works when I’m signed out and retrieve specific attributes. I’m failing to understand how to implement the Lambda based on that IAM Policy.
I’ve tried following various tutorial and documentation but as of now I wasn’t able to find anything useful.