Allow access to file only from specific Lambda [s3] - amazon-web-services

A s3 bucket (static web hosting) have a certain policy that deny access to everyone concerning a certain file.
How can I allow only a specific lambda function to access it ? (using only the bucket policy)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Authentication",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"NotResource": "arn:aws:s3:::web/auth.html"
}
]
}
UPDATE : Changing the previous policy with this one gives the desired result
{
"Version": "2012-10-17",
"Id": "Policy1477651215159",
"Statement": [
{
"Sid": "Console administration",
"Effect": "Allow",
"NotPrincipal": {
"AWS": "arn:aws:iam::XXXX:role/role_lambda"
},
"Action": "s3:GetObject",
"NotResource": "arn:aws:s3:::web/auth.html"
}
]
}

Lambda functions run in a Execution Role. You can make a customer IAM Role for your lambda function. See this
Then you can use that IAM Role to grant access to that S3 Object. See this article for steps to follow.

This is a CloudFormation snippet. You can allow your Lambda role access to S3 using the following IAM policy statement:
"LambdaRolePolicy" : {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "Lambda",
"PolicyDocument": {
"Statement" : [ {
"Action" : [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Effect" : "Allow",
"Resource" : {
"Fn::Join": [ "", [
"arn:aws:s3:::",
{ "Ref": "S3Bucket" },
"/*"
] ]
}
} ]
},
"Roles" : [ { "Ref": "RootRole" } ]
}
}
S3Bucket resource is your S3 bucket and RootRole is the Lambda role.

Related

AWS Role with a PolicyDocument assuming itself

I am trying to understand code written by coworker that has left.
Can anyone tell me why we have a Policy that assume the role it's attached too, what is it suppose to do?
{
"Role1": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
}
}
]
},
"ManagedPolicyArns": [],
"Policies": []
},
"AssumeRolePermissions": {
"Type": "AWS::IAM::Policy",
"DependsOn": "Role1",
"Properties": {
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": { "Fn::GetAtt": [ "Role1", "Arn" ] }
}
]
},
"PolicyName": "Assume_Role",
"Roles": [{ "Ref": "Role1" }]
}
}
}
}
I know a trust policy is useful in the case I want Role2 to assume Role1's permissions.
From the new update (https://aws.amazon.com/blogs/security/announcing-an-update-to-iam-role-trust-policy-behavior/) if seems in that case I need both of them in the trust policy but what if I don't do that, is there a use case for assuming its own role?
Thanks
"Role1": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": { "Fn::GetAtt": [ "Role1", "Arn" ] }
}
}
]
},
"ManagedPolicyArns": [],
"Policies": []
}
Thanks to #JohnRotenstein and AWS support:
A role assuming itself is a rare use case that while valid isn't an AWS best practice, with AWS recommending using multiple roles instead.
Some of these use cases involve self-assuming in conjunction with a 'scoped-down' policy to obtain a different privilege level, or using a single role and policy throughout the development => build => test => production environment, or can be used to rotate the access/secret keys used by the role since when you role chain the session only last one hour.
All that being said in the majority of cases a self assuming role is a step that depends on use case.

Custom resource name for IAM role defined in user-pool-group-precedence.json Amplify

I have an Amplify project and want to have a custom resource string per environment. For example I have the below defined in my user-pool-group-precedence.json file:
[{
"groupName": "example",
"precedence": 1,
"customPolicies": [
{
"PolicyName": "example-policy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Policy01",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::s3bucket-*/"],
"Effect": "Allow"
}
]
}
]
}]
I have multiple s3 buckets (1 per environment). For example s3bucket-dev and s3bucket-qa. Currently the above policy grants access to all my s3 buckets in different environments. How do I go about defining a single bucket per environment? Ideally I want something like
arn:aws:s3:::s3bucket-${aws:env}/
I looked at using conditions but was unsure how to implement them in order to achieve my goal.
Since this policy will be added to the amplify cloudformation template, Amplify already provides the parameter env in that target template. I suppose you will just have to reference it in your policy like this to make it dynamic as per your environment (Fn::Join does what you need):
[{
"groupName": "example",
"precedence": 1,
"customPolicies": [
{
"PolicyName": "example-policy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Policy01",
"Action": ["s3:GetObject"],
"Resource": {
"Fn::Join": [
"",
[
"arn:aws:s3:::s3bucket-",
{
"Ref": "env"
},
"/"
]
]
},
"Effect": "Allow"
}
]
}
]
}]

Restrict all access to a s3 bucket and allow 1 IAM user

As a plan to deprecate s3 objects, I am revoking all access apart from mine. I tried 2 ways but I see I am not able to see the bucket policy.
Error message from console:
You don’t have permission to get bucket policy
You or your AWS administrator must update your IAM permissions to allow s3:GetBucketPolicy. After you obtain the necessary permission, refresh the page. Learn more about Identity and access management in Amazon S3
First:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::ck",
"arn:aws:s3:::k/*"
],
"Condition": {
"StringNotLike": {
"aws:userId": [
"AIDA"
]
}
}
}
]
}
Second:
{
"Id": "bucketPolicy",
"Statement": [
{
"Action": "s3:*",
"Effect": "Deny",
"NotPrincipal": {
"AWS": [
"arn:aws:iam::0220:user/an"
]
},
"Resource": [
"arn:aws:s3:::tes",
"arn:aws:s3:::tes/*"
]
}
],
"Version": "2012-10-17"
}

Cannot set S3 trigger for Lambda function in AWS

I've been all over the internet looking for a solution to this. I have been trying to setup an AWS Lambda function to send a message to SNS every time a file is uploaded to a particular S3 bucket, according to this tutorial. At this point, I have the function setup and I can invoke it successfully. However, when I attempt to connect the function to S3, I get an error stating An error occurred (InvalidArgument) when calling the PutBucketNotification operation: Unable to validate the following destination configurations. According to this article, I should be able to add a permission that will let S3 invoke the Lambda function, like this:
aws lambda add-permission \
--function-name my-file-upload \
--principal s3.amazonaws.com \
--statement-id AcceptFromImport \
--action "lambda:InvokeFunction" \
--source-arn arn:aws:s3:::file-import \
--source-account my_account_id
I did this, and noticed that the policy associated with the Lambda function updated and appeared to be correct. However, the error persists. I've looked at a similar question, here, but none of the solutions here worked.
Execution Role ARN: arn:aws:iam::my_account_id:role/lambda-upload-stream
Execution Role (lambda-upload-stream) trust relationship:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Execution Role policy (my-file-upload):
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AccessObject",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::file-import/*"
},
{
"Sid": "SendUpdate",
"Effect": "Allow",
"Action": "sns:Publish",
"Resource": "arn:aws:sns:ap-northeast-1:my_account_id:comm-in"
}
]
}
Lambda function ARN: arn:aws:lambda:ap-northeast-1:my_account_id:function:my-file-upload
Lambda function role document
{
"roleName": "lambda-upload-stream",
"policies": [
{
"name": "my-file-upload",
"id": "AWS_ACCESS_KEY_ID",
"type": "managed",
"arn": "arn:aws:iam::my_account_id:policy/my-file-upload",
"document": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AccessObject",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::file-import/*"
},
{
"Sid": "SendUpdate",
"Effect": "Allow",
"Action": "sns:Publish",
"Resource": "arn:aws:sns:ap-northeast-1:my_account_id:comm-in"
}
]
}
}
],
"resources": {
"s3": {
"service": {
"name": "Amazon S3",
"icon": "data:image/svg+xml;base64,very_long_base64_string1"
},
"statements": [
{
"resource": "arn:aws:s3:::file-import/*",
"service": "s3",
"effect": "Allow",
"action": "s3:GetObject",
"source": {
"index": "AccessObject",
"policyName": "my-file-upload",
"policyType": "managed"
}
}
]
},
"sns": {
"service": {
"name": "Amazon SNS",
"icon": "data:image/svg+xml;base64,very_long_base64_string2"
},
"statements": [
{
"resource": "arn:aws:sns:ap-northeast-1:my_account_id:comm-in",
"service": "sns",
"effect": "Allow",
"action": "sns:Publish",
"source": {
"index": "SendUpdate",
"policyName": "my-file-upload",
"policyType": "managed"
}
}
]
}
},
"trustedEntities": [
"lambda.amazonaws.com"
]
}
Lambda function resource policy:
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:ap-northeast-1:my_account_id:function:my-file-upload",
"Condition": {
"StringEquals": {
"AWS:SourceAccount": "my_account_id"
},
"ArnLike": {
"AWS:SourceArn": "arn:aws:s3:::file-import"
}
}
}
]
}
My question is: what am I doing wrong here and how do I fix it?
The thing you need to create is called a "Resource-based policy", and is what should be created by aws lambda add-permission.
A Resource-based policy gives S3 permission to invoke your lambda. This is a property on your lambda itself, and is not part of your lambda's IAM role (Your lambda's IAM role controls what your lambda can do, a Resource-based policy controls who can do what to your lambda. You can view this resource in the UI on the aws console by going to your lambda, clicking "Permissions" and scrolling down to "Resource-based policy". The keyword you want to look out for is lambda:InvokeFunction, which is what gives other things permission to call your lambda, including other AWS accounts, and other AWS services on your account (like s3).
That being said, the command you ran should have created this policy. Did you make sure to replace my_account_id with your actual account id when you ran the command?
In addition, make sure you replace --source-arn arn:aws:s3:::file-import with the actual ARN of your bucket (I assume you had to create a bucket with a different name because s3 buckets must have globally unique names, and file-import is almost surely already taken)
I figured out what the problem was. My initial command was:
aws s3api put-bucket-notification --bucket azure-erp-import \
--notification-configuration "CloudFunctionConfiguration={Id=file-uploaded,Events=[],Event=s3:ObjectCreated:*,CloudFunction=arn:aws:lambda:ap-northeast-1:my_account_id:function:my-file-upload,InvocationRole=arn:aws:iam::my_account_id:role/lambda-upload-stream}"
This failed because the arn:aws:iam::my_account_id:role/lambda-upload-stream role doesn't have permissions to call lambda:InvokeFunction on the lambda function. Removing this value fixed the error.

Error Updating Stack to Add S3 Trigger

I successfully created a lambda function and S3 bucket using a cloudformation stack. I then ran an update to the stack to add a trigger to the S3 bucket to invoke a lambda function.
When I run the update it's giving the following error:
Unable to validate the following destination configurations (Service: Amazon S3; Status Code: 400; Error Code: InvalidArgument; Request ID: XXXXX; S3 Extended Request ID: XXXXX
This is the update JSON I'm using to add the trigger to the S3 bucket:
"MyBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": "my-bucket",
"NotificationConfiguration": {
"LambdaConfigurations": [
{
"Event": "s3:ObjectCreated:*",
"Function": "arn:aws:lambda:ap-southeast-2:my-lambda-arn"
}
]
}
I then added an IAM role to give access to the S3 bucket to invoke a lambda function:
"ResourceAccess": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Path": "/",
"Policies": [
{
"PolicyName": "giveaccesstodeltas3",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:ap-southeast-2:my-lambda-arn",
"Condition": {
"StringEquals": {
"AWS:SourceAccount": "123456"
},
"ArnLike": {
"AWS:SourceArn": "arn:aws:s3:::my-bucket"
}
}
}
]
}
}
]
}
It's giving an error saying:
Policy document should not specify a principal. (Service: AmazonIdentityManagement; Status Code: 400; Error Code: MalformedPolicyDocument; Request ID: XXXXXX)
In order to add this trigger, you must give your S3 bucket permission to invoke the lambda function. In addition, your lambda must have permission to invoke whatever services it affects. My guess is you are missing the first permissions to give:
permissions for your S3 bucket to invoke your lambda function.
You can create a policy similar to the following to give the appropriate permissions to your S3 bucket:
{
"Version": "2012-10-17",
"Id": "default",
"Statement": [
{
"Sid": "<optional>",
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "<ArnToYourFunction>",
"Condition": {
"StringEquals": {
"AWS:SourceAccount": "<YourAccountId>"
},
"ArnLike": {
"AWS:SourceArn": "arn:aws:s3:::<YourBucketName>"
}
}
}
]
}
See this AWS documentation for more info.