Add existing user pool to a lambda trigger in SAM - amazon-web-services

The documentation
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-cognito.html
Says to reference User pool created in the same template. I can't believe that there's no way to reference existing user pool - is this right?
Is there any way to reference it in SAM as a lambda trigger if the user pool already exists?
Any time I try to reference existing user pool it throws an error.

Oh Dear,
I'm facing the same problem and...
It seems to be impossible regarding this https://github.com/aws/serverless-application-model/blob/develop/versions/2016-10-31.md#cognito
NOTE: To specify a Cognito UserPool as an event source for a Lambda
function, both resources have to be declared in the same template. AWS
SAM does not support specifying an existing UserPool as an event
source.
There is the same issue with S3 bucket: https://github.com/aws/serverless-application-model/issues/124#

Although I am using serverless instead of SAM I managed to solve a similar issue by adding the 'existing' parameter like this:
functions:
postConfirmation:
handler: app/main/lambda_handler.handler
events:
- cognitoUserPool:
pool: MyUserPoolName
existing: true
trigger: PostConfirmation

Related

AWS CloudFormation: Cognito LambdaTrigger CustomEmailSender - Property "Not currently supported by AWS CloudFormation." and CDK usage

Generally what means Property "Not currently supported by AWS CloudFormation" for a CDK implementation, specifically:
In the CloudFormation Properties for the Cognito Userpool Lambda Config it says:
CustomEmailSender - Not currently supported by AWS CloudFormation.
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpool-lambdaconfig.html
In the CDK for Cognito.CfnUssrPool this property is described:
https://docs.aws.amazon.com/cdk/api/latest/docs/#aws-cdk_aws-cognito.CfnUserPool.LambdaConfigProperty.html#customemailsender
My question now is whether this can be implemented with CDK at all? Currently, our Cognito is provided completely via CDK and I would like to keep it that way.
Edit:
I found a link (Using CustomEmailSender with CFN) where it says that contrary to the documentation it does seem to work and only the documentation has not been updated, I will test this and give feedback.
After testing CustomEmailSender CDK implementation, I have to say that the AWS CloudFormation Documentation hasn't a current state. So it is possible to use this function by CFN and CDK. AWS Doc CFN Cognito CustomEmailSender
ToDos in CDK:
Configure Cognito: instead of using the property emailConfiguration you have to use lambdaConfig:
lambdaConfig: {
customEmailSender: { lambdaArn: customSenderEmailLambdaArn, lambdaVersion: 'V1_0' },
// the version is an ENUM so be careful when you set it
kmsKeyId: kmsKeyArn,
},
As you see here you have also to set up a KMS Key (you can adjust an existing one or create a new KMS key). The most important thing here is that you allow the action kms:CreateGrant to Cognito AND the Lambda function!
Another important ToDo is to add your Lambda the permission for Cognito, action cognito-idp:InvokeFunction.
The big advantage of using CustomEmailSender instead of the common Lambda Triggers that you don't have to set all the triggers in you CDK code or in the Cognito Console (all email events will be sent automatically to your lambda).

Lambda#Edge through Go SDK

I am trying to associate a Lambda#Edge Function using the AWS Go SDK.
Creating the Function by hand in the console and assigning it to the Cloudfront distro using the SDK => works.
Creating the Function (using the same IAM role from 1.) in the code w/o assigning to cloudfront => works.
Assigning the created function from 2. by hand in the console => fails.
Assigning the created function from 2. via the SDK => fails.
Deploying the created function from 2. by hand in the lambda console (Actions => deploy to lambda#edge) => works. => after this the function can be assigned by hand and by code w/o problems...
The error in 3. and 4. is the same:
InvalidLambdaFunctionAssociation: Lambda#Edge cannot retrieve the specified Lambda function. Update the IAM policy to add permission: lambda:GetFunction for resource: arn:aws:lambda:us-east-1:123456789:function:example:1 and try again.
What confuses me is that I am reusing the same role that was created during 1.
This is how I create the function by code:
lam := lambda.New(session)
lam.CreateFunction(&lambda.CreateFunctionInput{
FunctionName: aws.String("example"),
Handler: aws.String("index.handler"),
Runtime: aws.String("nodejs12.x"),
Role: aws.String("arn:aws:iam::123456:role/service-role/existing-role"),
Code: &lambda.FunctionCode{
S3Bucket: aws.String("bucket-xyz"),
S3Key: aws.String("source.zip"),
},
}) // works w/o issues
lam.AddPermission(&lambda.AddPermissionInput{
FunctionName: aws.String("example"),
StatementId: aws.String("AllowExecutionFromCloudFront"),
SourceArn: aws.String("arn:aws:cloudfront::12333456:distribution/CDNID1234"),
Principal: aws.String("edgelambda.amazonaws.com"),
Action: aws.String("lambda:GetFunction"),
}) // also works w/o error
// assigning the created lambda function would now fail
using
go 1.13
github.com/aws/aws-sdk-go v1.31.8
I found the issue.
The error has absolutely nothing to do with the actual problem. Very misleading error if you ask me.
All that's been missing is a published version of the lambda function at hand.
To achieve that using the Go SDK you have to do:
lam := lambda.New(session)
lam.PublishVersion(&lambda.PublishVersionInput{
FunctionName: aws.String("example"),
Description: aws.String("Dont forget to publish ;)"),
})
using the CLI you would want to do the following:
aws lambda publish-version --function-name example --description "Dont forget to publish"
It actually makes sense that you cannot use a function that hasn't been published. However the error from AWS didn't really help there.
Hopefully this can help anybody!
This error occurred for me because the IAM user didn't have adequate permissions to access versions of the Lambda function.
Before (only one resource specifying the Lambda function):
arn:aws:lambda:<region>:*:function:<function_name>
After (additional wildcard resource for versions of the Lambda function):
arn:aws:lambda:<region>:*:function:<function_name>
arn:aws:lambda:<region>:*:function:<function_name>:*

How to avoid giving `iam:CreateRole` permission when using existing S3 bucket to trigger Lambda function?

I am trying to deploy an AWS Lambda function that gets triggered when an AVRO file is written to an existing S3 bucket.
My serverless.yml configuration is as follows:
service: braze-lambdas
provider:
name: aws
runtime: python3.7
region: us-west-1
role: arn:aws:iam::<account_id>:role/<role_name>
stage: dev
deploymentBucket:
name: serverless-framework-dev-us-west-1
serverSideEncryption: AES256
functions:
hello:
handler: handler.hello
events:
- s3:
bucket: <company>-dev-ec2-us-west-2
existing: true
events: s3:ObjectCreated:*
rules:
- prefix: gaurav/lambdas/123/
- suffix: .avro
When I run serverless deploy, I get the following error:
ServerlessError: An error occurred: IamRoleCustomResourcesLambdaExecution - API: iam:CreateRole User: arn:aws:sts::<account_id>:assumed-role/serverless-framework-dev/jenkins_braze_lambdas_deploy is not authorized to perform: iam:CreateRole on resource: arn:aws:iam::<account_id>:role/braze-lambdas-dev-IamRoleCustomResourcesLambdaExec-1M5QQI6P2ZYUH.
I see some mentions of Serverless needing iam:CreateRole because of how CloudFormation works but can anyone confirm if that is the only solution if I want to use existing: true? Is there another way around it except using the old Serverless plugin that was used prior to the framework adding support for the existing: true configuration?
Also, what is 1M5QQI6P2ZYUH in arn:aws:iam::<account_id>:role/braze-lambdas-dev-IamRoleCustomResourcesLambdaExec-1M5QQI6P2ZYUH? Is it a random identifier? Does this mean that Serverless will try to create a new IAM role every time I try to deploy the Lambda function?
I've just encountered this, and overcome it.
I also have a lambda for which I want to attach an s3 event to an already existing bucket.
My place of work has recently tightened up AWS Account Security by the use of Permission Boundaries.
So i've encountered the very similar error during deployment
Serverless Error ---------------------------------------
An error occurred: IamRoleCustomResourcesLambdaExecution - API: iam:CreateRole User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/xx-crossaccount-xx/aws-sdk-js-1600789080576 is not authorized to perform: iam:CreateRole on resource: arn:aws:iam::XXXXXXXXXXXX:role/my-existing-bucket-IamRoleCustomResourcesLambdaExec-LS075CH394GN.
If you read Using existing buckets on the serverless site, it says
NOTE: Using the existing config will add an additional Lambda function and IAM Role to your stack. The Lambda function backs-up the Custom S3 Resource which is used to support existing S3 buckets.
In my case I needed to further customise this extra role that serverless creates so that it is also assigned the permission boundary my employer has defined should exist on all roles. This happens in the resources: section.
If your employer is using permission boundaries you'll obviously need to know the correct ARN to use
resources:
Resources:
IamRoleCustomResourcesLambdaExecution:
Type: AWS::IAM::Role
Properties:
PermissionsBoundary: arn:aws:iam::XXXXXXXXXXXX:policy/xxxxxxxxxxxx-global-boundary
Some info on the serverless Resources config
Have a look at your own serverless.yaml, you may already have a permission boundary defined in the provider section. If so you'll find it under rolePermissionsBoundary, this was added in I think version 1.64 of serverless
provider:
rolePermissionsBoundary: arn:aws:iam::XXXXXXXXXXXX:policy/xxxxxxxxxxxx-global-boundary
If so, you can should be able to use that ARN in the resources: sample I've posted here.
For testing purpose we can use:
provider:
name: aws
runtime: python3.8
region: us-east-1
iamRoleStatements:
- Effect: Allow
Action: "*"
Resource: "*"
For running sls deploy, I would suggest you use a role/user/policy with Administrator privileges.
If you're restricted due to your InfoSec team or the like, then I suggest you have your InfoSec team have a look at docs for "AWS IAM Permission Requirements for Serverless Framework Deploy." Here's a good link discussing it: https://github.com/serverless/serverless/issues/1439. At the very least, they should add iam:CreateRole and that can get you unblocked for today.
Now I will address your individual questions:
can anyone confirm if that is the only solution if I want to use existing: true
Apples and oranges. Your S3 configuration has nothing to do with your error message. iam:CreateRole must be added to the policy of whatever/whoever is doing sls deploy.
Also, what is 1M5QQI6P2ZYUH in arn:aws:iam::<account_id>:role/braze-lambdas-dev-IamRoleCustomResourcesLambdaExec-1M5QQI6P2ZYUH? Is it a random identifier? Does this mean that serverless will try to create a new role every time I try to deploy the function?
Yes, it is a random identifier
No, sls will not create a new role every time. This unique ID is cached and re-used for updates to an existing stack.
If a stack is destroyed/recreated, it will assign a generate a new unique ID.

Serverless framework Cognito Userpool Pre Token Generator

I have a PreTokenGenerator function which adds an additional claim to the id token.
In my serverless.yml I have the following definition.
functions:
issueAuthToken:
handler: src/handlers/cognitoPreToken.handler
events:
- cognitoUserPool:
pool: ${self:provider.stage}-user-pool
trigger: PreTokenGeneration
This runs and deploys, however does not wire up the user pool trigger in the userpool (see below)
How can I get this trigger to be setup? The documentation seems to be pretty lacking when it comes to cognito triggers
Pre Token Generation is currently not available in the UserPool LambdaConfig and hence not supported by CloudFormation (which serverless framework use). At the moment it can only be configured via console or AWS CLI.
According to Serverless documentation, you should inform the attribute existing: true and this is very critical if you don't want to create a new Cognito User Pool using-existing-pools
Also according to this forum this feature is now covered by AWS CloudFormation AWS Forum
This is a recent feature implemented by Serverless, so make sure you have the latest version installed.
Here is my Serverless configuration code:
preTokenGenerator:
name: ${self:service}-${self:provider.stage}-preTokenGenerator
description: Lambda service to list blog articles
role: LambdaRole
handler: functions/general/blog.list
events:
- cognitoUserPool:
pool: my-pool-name
trigger: PreTokenGeneration
existing: true
I literally duplicated an existing function and changed its trigger.
cognito-lambda-function

How to describe AWS Lambda function test events in CloudFormation template?

I describe existing AWS Lambda function in CloudFormation template and I face with the next issue. In our Lambda we configured few test events which helps us to verify some usecases (I mean functionality from the screenshot below).
But I don't see any abilities to add these test events to the CloudFormation template. AWS documentation don't help me with that. Is that possible at all or are there any workarounds how to export and import Lambda function test events?
Lambda test functionality is available only in the UI console, You can use Cloudformation Custom Resource to invoke a function from a cloudformation template. Resource properties allow AWS CloudFormation to create a custom payload to send to the Lambda function.
Sample code:
Resources:
EnableLogs:
Type: Custom::EnableLogs
Version: '1.0'
Properties:
ServiceToken: arn:aws:lambda:us-east-1:acc:function:rds-EnableRDSLogs-1O6XLL6LWNR5Z
DBInstanceIdentifier: mydb
the event parameter provides the resource properties. ex:
event['ResourceProperties']['DBInstanceIdentifier']