Serverless Lambda Resource Based Policy - All Principles - amazon-web-services

I am trying to define in the serverless YAML file with a resource based policy that ** allows any rule from EventBridge ** to invoke the function; this is due to in my application, EventBridge rules are dynamically generated.
In the AWS's console, it does not allow create a Lambda permission's EventBridge with wildcard.
The following was my attempt but it did not generate any resource policy when deployed:
provider:
resourcePolicy: ${self:custom.resourcePolicies.test}
... other things
custom:
resourcePolicies:
test:
- Effect: Allow
Principal: "*"
Action: lambda:InvokeFunction
... other things
Guidance appreciated.

I found an answer in this post by henhal on serverless forums.
Basically you have to create new resource of AWS::Lambda::Permission type.
resources:
Resources:
InvokeGenerateReportLambda:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:invokeFunction
FunctionName: ${env:LAMBDA_FUNCTION_ARN}
Principal: events.amazonaws.com
SourceArn: ${env:RULE_ARN} #can include wildcards

Related

Creating a AWS WorkMail Lambda invoke permission in CloudFormation

When I create a Lambda::Permission resource in Cloudformation I have an issue with validating the principal. Currently I have it set to use the !Sub function and that's not a valid principal according to CloudFormation. Does any one have any experience with creating a workmail invoke permission?
AWSTemplateFormatVersion: 2010-09-09
Resources:
WorkmailInvokePermission:
Type: 'AWS::Lambda::Permission'
Properties:
Action: 'lambda:InvokeFunction'
FunctionName: arn:aws:<region>:<function_arn>
Principal: !Sub workmail.${AWS::Region}.amazonaws.com
Outputs: {}
I figured it out, it was a pretty simple, the problem was I was in a region where Workmail wasn't actually available so it ended up creating an error.

CloudFormation Role using QueuePolicy Ref as a ManagedPolicy in IAM Role Resource?

I am trying to make an IAM Role via CloudFormation and am getting this error when trying to attach a QueuePolicy resource to an IAM::Role resource.
ARN stack-personSQSPolicy-3F02ILJ96DB1 is not valid. (Service: AmazonIdentityManagement; Status Code: 400; Error Code: InvalidInput; Request ID: 4410ba76-30ce-4d15-be3c-6d5040f971f0)
Here is my CloudFormation Role and Policy definition:
APIGatewaySQSRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Statement:
- Action: 'sts:AssumeRole'
Effect: Allow
Principal:
Service: apigateway.amazonaws.com
Version: 2012-10-17
ManagedPolicyArns:
- !Ref personSQSPolicy
- 'arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs'
personSQSPolicy:
Type: 'AWS::SQS::QueuePolicy'
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
Effect: Allow
Action: 'sqs:SendMessage'
Resource: !GetAtt personSQS.Arn
Queues:
- !Ref personSQS
What's the point of Type: 'AWS::SQS::QueuePolicy' If it doesn't allow the use as an Arn in the Role resource? It seems like I still have to manually create that policy in the IAM Role resource block.
Policies:
- PolicyDocument:
Statement:
- Action: sqs:SendMessage
Effect: Allow
Resource: !GetAtt 'personSQS.Arn'
PolicyName: apig-sqs-send-msg-policy
Is there a way to avoid this?
Since SQS Queues can be publicly accessible, they need a mechanism for security if people are going to access it without a role.
This is why you have a QueuePolicy AWS::SQS::QueuePolicy that you can define for the queue and it can be applied to one or more queues. It will help you define who's allowed to access it, how etc directly from the point of view of the queue.
You then attach your QueuePolicy to your Queue(s) with the Cloudformation attribute Queues (see: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-policy.html#cfn-sqs-queuepolicy-queues)
If you want to define a role for accessing your queue, yes you'll have to describe kind of the same policy but this time from the point of view of the resource accessing it but I still recommend that you secure the access to your queue with a Queue Policy.
As for your last question, defining the QueuePolicy and attaching it to your queue is the right way to do it.
Watch out, the Queues attribute expect a list of Queue URLs, not ARNs.

How do I grant a rotation Lambda access to AWS Secrets Manager

Using the serverless framework, I am trying to build a Lambda function that periodically rotates a secret stored in AWS Secrets Manager.
I am having trouble configuring the roles needed for the Secret Manager to execute the Lambda. In my serverless.yml I have defined the following resources:
resources:
Resources:
RotateKeysRole:
Type: AWS::IAM::Role
Properties:
RoleName: rotate-keys-role
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
- secretsmanager.amazonaws.com
Action: sts:AssumeRole
and attach this role to the rotation Lambda like this:
functions:
rotateKeys:
handler: lambdas.rotate_keys.handler
role: RotateKeysRole
Yet, when I try to set up Secrets Manager to use this Lambda for rotating secrets I will get the following error message:
Secrets Manager cannot invoke the specified Lambda function. Ensure
that the function policy grants access to the principal
secretsmanager.amazonaws.com
which puzzles me as this principal is specified. Inspecting the role in the IAM console did not reveal anything that seemed wrong to me.
How do I correctly configure the role setup in this scenario?
The procedure of setting up permissions for a lambda function which rotates AWS Secrets Manager secrets is explained in the docs. [1]
To put it in a nutshell, you need two steps:
Add a trust policy to the lambda function. This can be achieved using the CloudFormation resource AWS::Lambda::Permission in the serverless.yml file. However, it is a little bit tricky to set this up, because you need to depend on the function being created. That is why the DependsOn is necessary and its value must be structured as follows: <function-name-with-first-letter-uppercase>LambdaFunction.
Add statements for the lambda function to call the AWS Secrets Manager API to update the secret. In the following example, I added these statements (for the Single user rotation case - see docs [1]) to the customer managed policy called rotateKeysPolicy.
Note: The function name is referenced in the DependsOn attribute. It is also referenced in the condition StringEquals and the attribute FunctionName as: arn:aws:lambda:${self:custom.region}:${self:custom.accountId}:function:${self:service}-${self:provider.stage}-rotateKeys. Keep in mind to change them if you change your function name.
Here is how the serverless.yml file should look like:
service:
name: <your-service-name>
provider:
name: aws
region: '<your-region>'
custom:
region: ${self:provider.region}
accountId: <your-account-id>
resources:
Resources:
FunctionRole:
Type: AWS::IAM::Role
Properties:
RoleName: basic-function-role
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: rotateKeysPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- secretsmanager:DescribeSecret
- secretsmanager:GetSecretValue
- secretsmanager:PutSecretValue
- secretsmanager:UpdateSecretVersionStage
Resource: '*'
Condition:
StringEquals:
'secretsmanager:resource/AllowRotationLambdaArn': "arn:aws:lambda:${self:custom.region}:${self:custom.accountId}:function:${self:service}-${self:provider.stage}-rotateKeys"
- Effect: Allow
Action:
- secretsmanager:GetRandomPassword
Resource: '*'
- Effect: Allow
Action:
- ec2:CreateNetworkInterface
- ec2:DeleteNetworkInterface
- ec2:DescribeNetworkInterfaces
Resource: '*'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
LambdaInvokePermission:
Type: AWS::Lambda::Permission
DependsOn: RotateKeysLambdaFunction
Properties:
FunctionName: "arn:aws:lambda:${self:custom.region}:${self:custom.accountId}:function:${self:service}-${self:provider.stage}-rotateKeys"
Action: lambda:InvokeFunction
Principal: 'secretsmanager.amazonaws.com'
functions:
rotateKeys:
handler: lambdas.rotate_keys.handler
role: FunctionRole
You have to replace <your-service-name>, <your-region>, <your-account-id> and upload your rotation code using e.g. the package -> include attributes.
Note: There are templates for the lambda function which update the secrets. [2][3]
Please also keep in mind to configure your VPC correctly for the lambda function being able to access the AWS Secrets Manager service over the network. [4]
References
[1] https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets-required-permissions.html
[2] https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets-create-generic-template.html
[3] https://github.com/aws-samples/aws-secrets-manager-rotation-lambdas
[4] https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotation-network-rqmts.html
I had the same issue today. I ran this and it worked for me:
aws lambda add-permission \
--function-name ARN_of_lambda_function \
--principal secretsmanager.amazonaws.com \
--action lambda:InvokeFunction \
--statement-id SecretsManagerAccess
https://docs.aws.amazon.com/secretsmanager/latest/userguide/troubleshoot_rotation.html
Your policy is incorrect.
The service is secretsmanager but the action you defined is sts:AssumeRole which is from AWS Security Token Service.
A full access policy would be:
Effect: "Allow"
Action: "secretsmanager:*"
Resource: "*"
But you should limit the actions and the Resource the lambda can use.
For this you can use the policy builder which can be found in IAM->Policies.
After creating a policy in the editor you can click on the JSON Tab and see the format. Then you need to adapt it to your serverless yaml format.
I hope I can help you!
Dominik

How to setup Cloudwatch log for a Lambda created in Cloudformation

After creating a Lambda function in Cloudformation, I would like to be able to setup the Cloudwatch Logs expiration in the same Cloudformation script.
eg:
MyLambdaRole:
Type: AWS::Iam::Role
...
Properties:
...
Policies:
-
PolicyName: "myPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- "logs:CreateLogGroup"
- "logs:CreateLogStream"
- "logs:PutLogEvents"
Resource: "arn:aws:logs:*:*:*"
MyLambda:
Type: AWS::Lambda::Function
Properties:
...
Role: !GetAtt [ MyLambdaRole, Arn ]
However, CloudFormation does not allow to modify/update Logs that are reserved for AWS: "Log groups starting with AWS/ are reserved for AWS."
Is there a workaround for this? Since there is no way to setup the log name in the Lambda resource creation, maybe there is some way to specify it in the Role definition I can't find.
Try this and use RetentionInDays attribute to change the logs expire after time
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Join ['/', ['/aws/lambda', !Ref MyLambda]]
RetentionInDays: 7 # days
Note: the issue of the LogGroup failing to create will appear if the log group name already exists( will exist if MyLambda already exists). The workaround would be to delete and create stack.
No, there is not. As you wrote, it's a log group owned by AWS and you can't give yourself more permissions in a role than AWS would allow. Therefore, you can't allow yourself to modify their log group.
Use the AWS Serverless application Model, takes care of the deployment, roles and logs outbox and you always can add your custom cloudformation code https://github.com/awslabs/serverless-application-model
they already have a lot of examples ready to go.

Serverless framework 1.0 : Converting Cloudformation to Yaml for AWS Firehose

Does anyone know of a definitive guide for converting cloudformation to yaml in Serverless v1.0?
I can make quite a few things work but I'm completely stuck on how to setup Firehose and allow a lambda to write to it.
I think the resources section would look something like this:
resources:
Resources:
FirehoseBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: my-firehose-bucket
FirehoseDeliveryStream:
Type: AWS::KinesisFirehose::DeliveryStream
Properties:
DeliveryStreamName: "FirehoseDeliveryStream"
S3DestinationConfiguration:
BucketARN:
Fn::Join:
- ''
- - 'arn:aws:s3:::'
- Ref: FirehoseBucket
BufferingHints:
IntervalInSeconds: 60
SizeInMBs: 5
CompressionFormat: GZIP
Prefix: ${prefix}
RoleARN: "arn:aws:iam::${account-number}:role/${project}-${env}-IamRoleLambda"
But I have no idea how to convert the Cloudformation for the IAM section, which is described here: http://docs.aws.amazon.com/firehose/latest/dev/controlling-access.html.
Any pointers, examples or guides on CF->Yaml conversion much appreciated!
The IAM statements for the Lambda Execution Role (ie the role that the Lambda function assumes when executing) is not specified in the resources.
So if you need permissions to do something from inside your Lambda function you need to give the assumed role permission.
This is specified in the provider section. So in your case (I just copied something from your link, you will have to change it to what you need) it will be something like this (assuming nodejs runtime):
provider:
name: aws
runtime: nodejs4.3
iamRoleStatements:
- Effect: Allow
Action:
- firehose:DeleteDeliveryStream
- firehose:PutRecord
- firehose:PutRecordBatch
- firehose:UpdateDestination
Resource:
- arn:aws:firehose:region:account-id:deliverystream/delivery-stream-name
- Effect: Allow
Action:
- logs:PutLogEvents
Resource:
- arn:aws:logs:region:account-id:log-group:log-group-name:log-stream:log-stream-name
Bonus: For general resources specified in cloud formation json format use an online converter from json to yaml. Much easier to get the started that way.