How does S3 get permission from Lambda trigger? - amazon-web-services

I'm working out the security details for working with Lambda. One thing I can't find out is how S3 gets permission to push to Lambda when you add a trigger from the Lambda console or via S3 - Properties - Events. I know how it works using the CLI and I know you could do it via the SDK but I also noticed it isn't always necessary. Mostly the trigger just 'works' without me adding any permissions. Does anybody know why?
And is there a way to find out what Permissions S3/an S3 bucket has? I know there's a tab 'Permissions' but that's not giving me any information. I also know about Truster Advisor but that's just telling me there's no explicit problem with the permissions. I'm wondering if I can get a list of permissions though?
I hope someone can help me out, thanks in advance!

Adding a trigger in the console is the equivalent of assigning permissions and setting a bucket notification. You can see the policy associated with a particular lambda function by using the get-policy cli command:
aws lambda get-policy --function-name <name>
This will tell you what the policy is for your function. Including the resources with rights to invoke it. This policy isn't applied to the S3 bucket, but instead your lambda function.
You can also see what your bucket is set up to notify in the console under Properties > Events or review this with the cli using the get-bucket-notification command:
aws s3api get-bucket-notification --bucket <bucket>

Related

Amazon S3 Access Denied when calling aws lambda publish-layer-version CLI

I tried to run aws lambda publish-layer-version command line in my local console using my personal aws credentials, but I've got an Amazon S3 Access Denied error for the bucket in which the zip layer is stored.
aws lambda publish-layer-version --layer-name layer_name --content S3Bucket=bucket_name,S3Key=layers/libs.zip
An error occurred (AccessDeniedException) when calling the PublishLayerVersion operation: Your access has been denied by S3, please make sure your request credentials have permission to GetObject for {URI of layer in my S3 bucket}. S3 Error Code: AccessDenied. S3 Error Message: Access Denied
When I'm running the aws cp command in the same bucket, it all works perfectly fine
aws s3 cp s3://bucket_name/layers/libs.zip libs.zip
So I assume that the aws lambda command line is using an other role than the one used when I'm running the aws cp command line ? Or maybe it uses another mecanism that I just don't know. But I couldn't find any thing about it in the AWS documentation.
I've just read that AWS can return a 403 it couldn't find the file. So maybe it could be an issue with the command syntax ?
Thank you for your help.
For your call to publish-layer-version you may need to specify the --content parameter with 3 parts:
S3Bucket=string,S3Key=string,S3ObjectVersion=string
It looks like you are missing S3ObjectVersion. I don't know what the AWS behavior is for evaluating and applying the parts of that parameter, but it could be attempting to do something more since the version is not specified and hence giving you that error. Or it could be returning an error code that is not quite right and is misleading. Try adding S3ObjectVersion and let me know what you get.
Otherwise, AWS permission evaluation can be complex. I like this AWS diagram below, so it is a good one to follow to track down permissions issues, but I suspect that AccessDenied is a bit of a red herring in this case:
Your Lambda does not have privileges (S3:GetObject).
Try running aws sts get-caller-identity. This will give you the IAM role your command line is using.
Go to IAM dashboard, check this role associated with your Lambda execution. If you use AWS wizard, it automatically creates a role called oneClick_lambda_s3_exec_role. Click on Show Policy. It will look something like attached image.Make sure S3:GetObject is listed.
Also, AWS returns 403 (access denied) when the file does not exist. Be sure the target file is in the S3 bucket.

Writing to Amazon S3 bucket from Lambda results in "InvalidARN: ARN accountID does not match regex "[0-9]{12}""

Been digging through tutorials for days, but they all say the same thing, and it seems like I should be in slam dunk territory here, but I get the above error whenever I try to read or write from my Amazon S3 bucket.
I only have one AWS account, so my lambda function should be owned by the same account as my Amazon S3 bucket. I have given my lambda role s3:GetObject and PutObject permissions, as well as just s3:*, I have verified that my S3 bucket policy is not denying access explicitly, but nothing changes the message.
I am new to AWS policies and permissions, but google isn't giving up a lot of other people getting this message. I don't know where I am supposed to be supplying my AccountID or why it isn't already there. Would be grateful for any insights.
EDIT: I have added AmazonS3FullAccess to my policies and removed my previous policy, which only allowed GetObject and PutObject specifically. Sadly, behavior has not changed.
Here are a couple of screenshots:
And, since my roles seem to be correct, here is my code, any chance there is anything here that could be causing my problem?
You should use the bucket name only - without the full arn stuff.
You can solve this issue by ensuring that the IAM role associated with your Lambda function has the correct permissions. For example, here is the IAM role i use to invoke Amazon S3 operations from a Lambda function:
Also make sure in the Lambda console, you select the proper IAM role, as shown here:
Had this issue but I later realized I provided s3 arn instead of the bucket name as an environment variable
I got this problem when I had incorrect REGION in S3Client inicialization. Here is the correct code example (change region to yours):
const REGION = "eu-central-1"; //e.g. "us-east-1"
const s3Client = new S3Client({ region: REGION });
Source: step 2 in AWS Getting started in Node.js Tutorial

Sending message to AWS Lambda from AWS Pinpoint Custom Channel

I am trying to send messages to my AWS Lambda Function from AWS Pinpoint through custom channel as described here
My problem is about granting permission to AWS Pinpoint to invoke my lambda function. The AWS CLI command provided in the documentation for granting permission is not working. When I execute the aws lambda add-permission command from AWS CLI like described in the documentation, I got the following error:
"no matches found: arn:aws:mobiletargeting:us-east-1:<account-id>:apps/*"
The result doesn't change if I change the ARN to any of the below:
arn:aws:mobiletargeting:us-east-1:<account-id>:apps/<pinpoint-app-id>/*
arn:aws:mobiletargeting:us-east-1:<account-id>:apps/<pinpoint-app-id>/campaigns/*
arn:aws:mobiletargeting:us-east-1:<account-id>:/apps/<pinpoint-app-id>/*
arn:aws:mobiletargeting:us-east-1:<account-id>:/apps/<pinpoint-app-id>/campaigns/*
I tried the same with AWS Cloudformation instead of AWS CLI, I succeeded to grant permission to AWS Pinpoint to invoke my lambda function. At least the Resource Based Policy appeared in the "Permissions" tab of my AWS Lambda Function Console. The source ARN like condition is
arn:aws:mobiletargeting:us-east-1:<account-id>:apps/<pinpoint-app-id>/*
But, when I try to create a campaign under the same pinpoint application (i.e., project) I got the following error message:
"Amazon Pinpoint couldn’t invoke the Lambda function that you specified for custom delivery. Verify that a function policy is assigned to the function and that Amazon Pinpoint is authorized to invoke the function."
I tried different SourceArn like condition including the followings, but the result is the same:
arn:aws:mobiletargeting:us-east-1:<account-id>:apps/<pinpoint-app-id>/*
arn:aws:mobiletargeting:us-east-1:<account-id>:apps/<pinpoint-app-id>/campaigns/*
arn:aws:mobiletargeting:us-east-1:<account-id>:apps/*
arn:aws:mobiletargeting:us-east-1:<account-id>:*
arn:aws:mobiletargeting:us-east-1:<account-id>:/apps/*
Couldn't figure out what the problem is. Any idea about what I am missing will be greatly appreciated.
Thanks in advance!
Interesting but the same aws lambda add-permission command that returned no matches found: arn:aws:mobiletargeting:us-east-1:<account-id>:apps/* is working after sudo su.
This is probably too late, but for anyone that has a similar problem and don't want to go through the whole cloudformation template at least for now.
I had the same issue with
"no matches found: arn:aws:mobiletargeting:us-east-1::apps/*".
It was due to my terminal behaving weirdly with '*', so adding single quotes around the arn worked, like:
arn:aws:mobiletargeting:us-east-1:<account-id>:apps/<pinpoint-app-id>/*

Deploying an AWS Lambda from a different account

I have a Lambda .jar that I build from a Jenkins box in an AWS account ("Account_Bld"). Once built, I copy the .jar over to an S3 bucket in a different AWS account ("Account_Dst"), and I attempt to update the Lambda in Account_Dst based on the newly copied .jar in S3.
I'm using this command as part of my deploy script, which is a slight modification of another version that works when everything is located in the same account:
aws lambda update-function-code --function-name arn:aws:lambda:us-east-1:{Account_Dst_Id}:function:{lambda_function_name} --zip-file fileb://{jar_file_relative_path} --region us-east-1
Not surprisingly, I get this error:
An error occurred (AccessDeniedException) when calling the UpdateFunctionCode operation: User: arn:aws:sts::{Account_Bld_Id}:assumed-role/{jenkins_ec2_role}/{jenkins_ec2_instance_id} is not authorized to perform: lambda:UpdateFunctionCode on resource: arn:aws:lambda:us-east-1:{Account_Dst_Id}:function:{lambda_function_name}
I have given jenkins_ec2_role rights to update the Lambda in the other account, but it makes sense that I would need to reciprocate those rights somewhere in Account_Dst -- assuming there is a simple solution to this problem.
Now, possible resolutions. I could assume a role in Account_Dst that has the correct rights and update the Lambda, but that's more setup hassle than it is worth to me right now. I've seen some Google suggestions that I could use CodePipeline, but obviously I'm using Jenkins, so that doesn't seem like a good solution, either.
So, the question is, is there an easy solution here that I am missing?
This is now possible. A Lambda resource based policy can be configured to allow a principal from another account to perform actions e.g. lambda:UpdateFunctionCode or lambda:Invoke.
In case of UpdateFunctionCode, the documentation states:
FunctionName
The name of the Lambda function.
Name formats
Function name – my-function.
Function ARN – arn:aws:lambda:us-west-2:123456789012:function:my-function.
Partial ARN – 123456789012:function:my-function.
...
Source: https://docs.aws.amazon.com/lambda/latest/dg/API_UpdateFunctionCode.html
The Lambda Function permission in account 222222222222 must be configured to allow the principal from account 111111111111 to update the function code:
aws lambda add-permission --function-name my-function --statement-id xaccount --action lambda:UpdateFunctionCode --principal 111111111111 --output out.txt
Source:
https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html#permissions-resource-xaccountinvoke
Then the function code in account 222222222222 can be updated from account 111111111111:
aws lambda update-function-code --function-name arn:aws:lambda:us-west-2:222222222222:function:my-function --zip-file fileb://soure.zip
Granting permissions in Account_Bld to access Account_Dst is not sufficient to gain access to another account. This is good, because you wouldn't want people granting themselves access to other people's accounts.
The destination account needs to accept the incoming request. The method varies by service. For example, Amazon S3 can create a Bucket Policy to permit access from other accounts, as can Amazon SQS.
However, there is no such concept in Lambda to configure incoming requests from other accounts. There is simply nowhere that can be configured to allow update-function-code from another account.
Therefore, you will need to do as you suggested:
Create an IAM User or IAM Role in Account_Dst
Use the credentials from the Account_Dst IAM User (simplest) or use the existing Account_Bld credentials to assume the Role in Account_Dst (a few more lines of code)
Call update-function-code using those credentials

configure Amazon s3 bucket to run Lambda function created in another account

Is it possible to configure S3 bucket to run a Lambda function created in a different account? Basically what I'm trying to accomplish is that when new items are added to S3 bucket I want to run a lambda function in another account
You can do this by providing the full Lambda Function ARN to your S3 bucket. For example inside your bucket settings in the AWS Console:
This article will help you configure the correct IAM for cross account invocation. Also take a look at the AWS Lambda Permissions Model. Note that as far as I know the bucket and the Lambda function have to be in the same region!