AWS Lambda Access Denied on Pre-Signed CloudFront URL - amazon-web-services

I was following the guide from https://docs.aws.amazon.com/solutions/latest/serverless-image-handler/deployment.html to create a new Lambda Function over my CloudFront distribution. However, I have an extra requirement to only use the pre-signed URLs. The idea is that my service generates the CloudFront pre-signed URL and gives that URL to the client to access it. However, client should be able to invoke the Lambda Function on that URL.
For example the following should be possible:
Service returns the URL https://dfg565mo4z0svb.cloudfront.net/portrait.jpeg?Expires=1540724061&Signature=VLfwYdHrLM91wzFyOg0S3C6PKkKWghfOiZzt1-ew~gt0HPK~Sap0~5PHVHCEDHgHIQfwb0~oAZQ1igOOiRigzMTQ-ew~uSIR7-dsd~QJlAuceO5f2cDB2hopC5~trEgRTMnQSozPlbrFSwthveVBlZPVI3s2YapZgC7pqZB08IKIYtcXKjRfMPkxgumV5P-~Dj7rK5fdfvLyvTUTxIwrt3WLndOydBjxxUsL-6D-Hkdz8uWi6u59-sg__&Key-Pair-Id=BPKDVBLKFPWSDLIAXN8I
The client should be able to invoke Lambda like this: https://dfg565mo4z0svb.cloudfront.net/fit-in/100x100/portrait.jpeg?Expires=1540724061&Signature=VLfwYdHrLM91wzFyOg0S3C6PKkKWghfOiZzt1-ew~gt0HPK~Sap0~5PHVHCEDHgHIQfwb0~oAZQ1igOOiRigzMTQ-ew~uSIR7-dsd~QJlAuceO5f2cDB2hopC5~trEgRTMnQSozPlbrFSwthveVBlZPVI3s2YapZgC7pqZB08IKIYtcXKjRfMPkxgumV5P-~Dj7rK5fdfvLyvTUTxIwrt3WLndOydBjxxUsL-6D-Hkdz8uWi6u59-sg__&Key-Pair-Id=BPKDVBLKFPWSDLIAXN8I
where /fit-in/100x100/ is the Lambda Function.
All of that works by the default, but if I set the Restrict Viewer Access
(Use Signed URLs or Signed Cookies) option under Origin Behaviour to Yes, then suddenly any call to my Lambda Function returns the Access Denied response.
IAM Policy of the Role that my Lambda Function is using
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::myBucket/*"
}
]
}
Bucket Policy
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EN2PJ6YY7V8EE"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::myBucket/*"
},
{
"Sid": "2",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E2EM2OLBKAK85T"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::myBucket/*"
}
]
}
How can I use the presigned URLs with Lambda?

Related

AWS Lambda S3 Access Denied

I have a lambda function using a role with the following policy excerpt
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::ipwl-lambda-config/*",
"arn:aws:s3:::ipwl-lambda-config"
]
}
My bucket policy looks like the following
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyUnEncryptedObjectUploads",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::ipwl-lambda-config/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "aws:kms"
}
}
},
{
"Sid": "AllowLambda",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::accountid:role/iam_for_lambda"
},
"Action": [
"s3:ListBucket",
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::ipwl-lambda-config/*",
"arn:aws:s3:::ipwl-lambda-config"
]
}
]
}
I've allowed GetObject and ListBucket on both the role and the bucket policy. However when my function runs
s3_obj = s3_res.Object(s3_bucket, s3_object)
I get
[ERROR] ClientError: An error occurred (AccessDenied) when calling the
GetObject operation: Access Denied
What more permissions do I have to add? The object is there, I can get it when I run the code locally using an admin role.
Update
I've checked to make sure the bucket and object names are correct dozens of times. The exception is actually coming from the second line here according to the stacktrace
s3_res = boto3.resource('s3')
s3_obj = s3_res.Object(s3_bucket, s3_object)
data = s3_obj.get()['Body'].read()
KMS should only be a factor for PutObject. We have a support account so I may check with them and update with their findings.
To download a KMS-encrypted object from S3, you not only need to be able to get the object. You also need to be able to decrypt the AWS KMS key.
Here's an example of an IAM policy that your Lambda function should have:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "s3get",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::ipwl-lambda-config/*"
},
{
"Sid": "kmsdecrypt",
"Effect": "Allow",
"Action": "kms:Decrypt",
"Resource": "arn:aws:kms:example-region-1:123456789012:key/example-key-id"
}
]
}
The key policy also needs to allow the IAM role to decrypt the key, something like this:
{
"Sid": "kmsdecrypt",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/xyz"
},
"Action": "kms:Decrypt",
"Resource": "*"
}

lambda cannot access to s3 bucket restricted by cloudfront

I have a s3 bucket as origin of a cloudfront. The bucket have all public access blocked. I create a lambda function that download, process and upload s3 object. I create a role for the lambda and add a non public policy, according the meaning of public for amazon resources.. Here is the policy
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3LambdaAccessObject",
"Effect": "Allow",
"Action": "s3:*Object",
"Resource": "arn:aws:s3:::XXXXXXXXXXXXX-dev-videos-origin/*",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:lambda:us-east-1:XXXXXXXXXXXXX:function:YYYYYYYYYYYY_conversor"
}
}
},
{
"Sid": "S3LambdaListBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::XXXXXXXXXXXXX-dev-videos-origin",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:lambda:us-east-1:XXXXXXXXXXXXX:function:YYYYYYYYYYY_conversor"
}
}
}
However, i get access denied code when trying to download and upload a file to the s3 via sdk.
I even has added the lamnda to the s3 policies but still no result:
{
"Version": "2012-10-17",
"Id": "aws_iam_policy_document_origin",
"Statement": [
{
"Sid": "S3GetObjectForCloudFront",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXXXXXXXX"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::XXXXXXXXXXX-origin/*"
},
{
"Sid": "S3ListBucketForCloudFront",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXXXXXXXX"
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::XXXXXXXXXXX-origin"
},
{
"Sid": "S3PutObjectForCloudFront",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity XXXXXXXXXXX"
},
"Action": [
"s3:PutObjectVersionAcl",
"s3:PutObjectAcl",
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::XXXXXXXXXXX-origin/private/*"
},
{
"Sid": "S3LambdaAccessObject",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:*Object",
"Resource": "arn:aws:s3:::XXXXXXXXXXX-origin/*",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:lambda:us-east-1:YYYYYYYYYYY:function:XXXXXXXXXXX"
}
}
},
{
"Sid": "S3LambdaListBucket",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::XXXXXXXXXXX-origin",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:lambda:us-east-1:YYYYYYYYYYY:function:XXXXXXXXXXX"
}
}
}
]
}
]
}
The lambda work just fine if the public access blocking is removed. What I am doing wrong?
The whitelist for the Lambda function Arn will not work as the Lambda function connects using its Lambda role to perform any of these interactions.
Instead you will need to whitelist the IAM role that your Lambda has attached to it. This is done by using the Principal of the IAM role Arn.
You will still need to ensure that the IAM role contains the permissions it needs to access S3 additionally.
The problem is that the code that I was testing try to upload a file with public ACL policy, what is denied by the s3, having all the public access blocked. The blocking also prevent any account or service to update this non public policy for the bucket or object: https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html

403 on S3 bucket object in browser

I've a private bucket with OAI and CloudFront. When I upload an item to the bucket I can visit it using the CloudFront URL but not via the S3 url:
My policy looks like this
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontRead",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity xxx"
},
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": "arn:aws:s3:::xxx/*"
}
]
}
My IAM user has the permission to upload and get from the bucket.
Now I want that my user (or my account) can visit the S3 URL (not the CloudFront URL) to access the object in the bucket without the need to make the bucket public.
How can I do this?
I tried to update the bucket policy like this but it didn't work.
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontRead",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity xxx"
},
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": "arn:aws:s3:::xxx/*"
},
{
"Sid": "AllowPolicyRead",
"Effect": "Allow",
"Principal": {
"AWS": "xxxxx"
},
"Action": [
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": "arn:aws:s3:::xxx/*"
}
]
}
From the CLI my user can get and upload objects.
IAM or bucket policies give you API level access to S3. It is not possible to download S3 files without making buckets public.

API Gateway Resource policy returning 403

So I'm trying to restrict access on API Gateway for one API endpoint for Auth0 to call when a user has signed Up.
I've tried a few permutations on this, the example below in my mind should work that doesn't.
I allow everything.
As a test, I specifically allowed one endpoint also.
Then I deny everyone the securedEnpoint
Then I allow auth0 IP addresses access to the securedEnd endpoint - my IP was also on that list I've removed it for security.
The securedEndpoint doesn't have an authorizer attached, with this policy applied ALL endpoints return 403 from APIG - I'm using serverless to deploy this, what you see below is the resulting JSON from the resource policy section in the APIG console.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "eu-west-2:ACCOUNT_ID:API_ID/*/*/*"
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "eu-west-2:ACCOUNT_ID:API_ID/*/*/allowedEndPoint"
},
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "eu-west-2:ACCOUNT_ID:API_ID/*/POST/securedEndpoint"
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "eu-west-2:ACCOUNT_ID:API_ID/*/POST/securedEndpoint",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"138.91.154.99",
"54.183.64.135",
"54.67.77.38",
"54.67.15.170",
"54.183.204.205",
"54.173.21.107",
"54.85.173.28",
"35.167.74.121",
"35.160.3.103",
"35.166.202.113",
"52.14.40.253",
"52.14.38.78",
"52.14.17.114",
"52.71.209.77",
"34.195.142.251",
"52.200.94.42"
]
}
}
}
]
}

AWS Lambda Access Denied

A brief explanation of my setup.
I have an AWS S3 bucket with access set to Not Public which is called myBucket
I have a CloudFront distribution over the myBucket
I have created a lambda function (serverless image handler)
The desired behaviour is that my images are only accessible through my CloudFront distribution (and not directly using the S3 URL), and that I should be able to call my lambda function through the CloudFront URL.
Now what happens is that I am able to get my image like this:
https://d32by75bmg47jh.cloudfront.net/portrait.jpeg
But, I am not able to get the image by calling lambda:
https://d32by75bmg47jh.cloudfront.net/fit-in/500x500/portrait.jpeg
I am getting the Access Denied error when I try to call it with lambda.
My Bucket Policy looks like this:
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E2FGH21TNURTU9"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::myBucket/*"
}
}
In my Lambda Console have set my Lambda function to use the Execution role: lambda_basic_execution. In the IAM Console it's policy looks like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::myBucket/*"
}
]
}
Why am I still getting the Access Denied when I try to access my image through lambda?