I have a cloudformation template that creates a lambda funciton as well as a role for that lambda function. I try assuming the role in the lambda function but keep getting the error :
An error occurred (AccessDenied) when calling the AssumeRole operation: Access denied
Is there a step I'm missing? Not sure why I don't have permission to assume the role. I'm assuming I'm missing some sort of permission if the error I'm getting is access denied as opposed to some execution error.
Cloudformation Snippet :
"LambdaRoleCustomResource": {
"Type": "AWS::IAM::Role",
"Condition": "CreateWebACL",
"DependsOn": "WAFWebACL",
"Properties": {
"RoleName": {
"Fn::Join": ["-", [{
"Ref": "AWS::StackName"
}, "Custom-Resource"]]
},
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": ["lambda.amazonaws.com"]
},
"Action": ["sts:AssumeRole"]
}]
},
"Path": "/",
"Policies": [{
"PolicyName": "S3Access",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"s3:CreateBucket",
"s3:GetBucketLocation",
"s3:GetBucketNotification",
"s3:GetObject",
"s3:ListBucket",
"s3:PutBucketNotification"
],
"Resource": {
"Fn::Join": ["", ["arn:aws:s3:::", {
"Ref": "AccessLogBucket"
}]]
}
}]
}
}
Lambda Function Snippet:
sts_client = boto3.client('sts')
sts_credentials = sts_client.assume_role(RoleArn='arn:aws:iam::XXXXXXXXX:role/portal-cloudfront-waf-Custom-Resource', RoleSessionName='custom-resource-cf-session')
sts_credentials = sts_credentials['Credentials']
cf = boto3.client('cloudformation', aws_access_key_id=sts_credentials['AccessKeyId'], aws_secret_access_key=sts_credentials['SecretAccessKey'], aws_session_token=sts_credentials['SessionToken'])
stack_name = event['ResourceProperties']['StackName']
cf_desc = cf.describe_stacks(StackName=stack_name)
global waf
sts_client = boto3.client('sts')
sts_credentials = sts_client.assume_role(RoleArn='arn:aws:iam::XXXXXXXX:role/portal-cloudfront-waf-Custom-Resource', RoleSessionName='custom-resource-waf-session')
sts_credentials = sts_credentials['Credentials']
s3 = boto3.client('waf', aws_access_key_id=sts_credentials['AccessKeyId'], aws_secret_access_key=sts_credentials['SecretAccessKey'], aws_session_token=sts_credentials['SessionToken'])
waf = boto3.client('waf')
Your Lambda function will automatically use the permissions associated with the Role attached to the function. There is no need to create credentials.
So, just use:
cf = boto3.client('cloudformation')
s3 = boto3.client('waf')
Related
I am creating a cloudformation stack to generate aws instance scheduler in aws gov cloud via TF. The goal is to start/stop ec2 based on tags. Many way to achieve it but I have to use terraform and cloudformation. Here is the repo --> https://github.com/Vinod1908/TestTerraform/blob/master/instanceScheduler.tf
Below is the part of the code where I think I am blocked:
"InstanceSchedulerEncryptionKey": {
"Type": "AWS::KMS::Key",
"Properties": {
"Description": "Key for SNS",
"Enabled": true,
"EnableKeyRotation": true,
"KeyPolicy": {
"Statement": [
{
"Sid": "default",
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::Sub": "arn:$${AWS::Partition}:iam::$${AWS::AccountId}:root"
}
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allows use of key",
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::GetAtt": [
"SchedulerRole",
"Arn"
]
}
},
"Action": [
"kms:GenerateDataKey*",
"kms:Decrypt"
],
"Resource": "*"
}
]
}
}
},
"Code": {
"S3Bucket": {
"Fn::Join": [
"-",
[
"solutions",
{
"Ref": "AWS::Region"
}
]
]
},
"S3Key": "aws-instance-scheduler/v1.3.1/instance-scheduler.zip"
The error :
Error: error waiting for CloudFormation Stack creation: failed to create CloudFormation stack, rollback requested (ROLLBACK_COMPLETE): ["The following resource(s) failed to create: [InstanceSchedulerEncryptionKey, SchedulerRule]. Rollback requested by user."
"Resource creation cancelled" "Parameter arn:aws:lambda:us-gov-west-1:###########..:function:Schedule-InstanceSchedulerMain is not valid. Reason: Provided Arn is not in correct format. (Service: AmazonCloudWatchEvents; Status Code: 400; Error Code: ValidationException; Request ID: 37adac0c-6758-4b4f-ac86-0d0140742c80; Proxy: null)"]
Not sure if it's doable in gov cloud but I am looking for potential solutions and found this https://github.com/awslabs/aws-instance-scheduler/issues/11. I am testing it but no success yet.. please help !!
Adding a new line:
Thank you all for the response. My issue was using the correct arn arn:aws-us-gov
I just apply the code and it's going through. Now I am getting this below and I am sure it's related to the policy/role on my s3. Please let me know what is wrong in my code below. Any thoughts?
the s3 code part:
"SchedulerPolicy": {
"Type": "AWS::IAM::Policy",
"Metadata": {
"cfn_nag": {
"rules_to_suppress": [
{
"id": "W12",
"reason": "All policies have been scoped to be as restrictive as possible. This solution needs to access ec2/rds resources across all regions."
}
]
}
},
"Properties": {
"PolicyName": "SchedulerPolicy",
"Roles": [
{
"Ref": "SchedulerRole"
}
],
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:PutRetentionPolicy"
],
"Resource": [
{
"Fn::Join": [
":",
[
"arn:aws-us-gov:logs",
{
"Ref": "AWS::Region"
},
{
"Ref": "AWS::AccountId"
},
"log-group",
{
"Ref": "SchedulerLogGroup"
},
"*"
]
]
},
{
"Fn::Join": [
":",
[
"arn:aws-us-gov:logs",
{
"Ref": "AWS::Region"
},
{
"Ref": "AWS::AccountId"
},
"log-group:/aws/lambda/*"
]
]
}
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:*"
],
"Resource": {
"Fn::Join": [
":",
[
"arn:aws-us-gov:s3:::instanceschedulertest",
"arn:aws-us-gov:s3:::instanceschedulertest/*"
]
]
}
},
{
"Effect": "Allow",
"Action": [
"rds:DeleteDBSnapshot",
"rds:DescribeDBSnapshots",
"rds:StopDBInstance"
],
"Resource": {
"Fn::Join": [
":",
[
"arn:aws-us-gov:rds:*",
{
"Ref": "AWS::AccountId"
},
"snapshot:*"
]
]
}
},
{
"Effect": "Allow",
"Action": [
"rds:AddTagsToResource",
"rds:RemoveTagsFromResource",
"rds:DescribeDBSnapshots",
"rds:StartDBInstance",
"rds:StopDBInstance"
The error:
Error: error waiting for CloudFormation Stack creation: failed to create CloudFormation stack, rollback requested (ROLLBACK_COMPLETE): ["The following resource(s) failed to create: [Main]. Rollback requested by user." "Your access has been denied by S3, please make sure your request credentials have permission to GetObject for solutions-us-gov-west-1/aws-instance-scheduler/v1.3.1/instance-scheduler.zip. S3 Error Code: AccessDenied. S3 Error Message: Access Denied (Service: AWSLambdaInternal; Status Code: 403; Error Code: AccessDeniedException; Request ID: 95db6874-d4ad-4499-95f7-f73777a6d4db; Proxy: null)"]
Thank you all for all the pointers I really appreciate your input.
The reason why it is failing is because you are forming the wrong ARN in your Terraform Code.
In your repo,
link
Replace these following lines with respect to Lambda: 1047, 1358, 1420 as "arn:aws-us-gov:lambda" instead of "arn:aws:lambda".
As per the documentation of aws: The ARN should be in this format arn:aws-us-gov:lambda:account-id:function:function-name.
The answer to your question is to update the above-mentioned line. But I am sure you will get errors with respect to other resources as all resources which you are creating are in the Us-Region. So please update all the necessary Joining Function Arn lines which your forming in your code. :)
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.
I want to limit access to my elasticsearch clusters on aws by defining Access Policies that would limit access to iam users, a specific lambda function and the appsync api.
I have defined the following access policies in the elasticsearch resource on cloudformation, but this is failing with an error: Service: AWSElasticsearch; Status Code: 409; Error Code: InvalidTypeException;
How do I fix my policy so that it works?
"Type": "AWS::Elasticsearch::Domain",
"Properties": {
"AccessPolicies": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
{
"Fn::Join": [
"",
[
"arn:aws:lambda:",
{"Ref": "AWS::Region"},
":",
{"Ref": "AWS::AccountId"},
":function:",
{"Ref": "DdEsLambdaFunctionName"},
"-",
{"Ref": "env"}
]
]
},
{
"Fn::Join": [
"",
[
{"Ref": "GraphQLAPI"},
"/*"
]
]
}
]
},
"Action": [
"es:ESHttp*"
]
},
{
"Effect": "Allow",
"Principal": [
{
"AWS": {
"Fn::Join": [
"",
[
"arn:aws:iam::",
{"Ref": "AWS::AccountId"},
":user/*"
]
]
}
}
],
"Action": "*"
}
]
},...}
Not sure if this is the core issue, but your first Principal is incorrect.
You specified Service but you provide lambda ARN. The ARN is of type AWS principal, not Service. Possibly GraphQLAPI is also an ARN, which again is not a Service principal, but AWS Principal.
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.
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.