How to configure 'Pre Token Generation' lambda trigger via SAM? - amazon-web-services

Pre Token Generation trigger: This Lambda trigger allows you to customize an identity token before it is generated: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-pre-token-generation.html
I am looking for a way to configure this trigger via SAM. Something like:
ApiJWTAddCustomClaimFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub ${AWS::StackName}-ApiJWTAddCustomClaimFunction
Description: Modify JWT before token generation
Handler: main
Environment:
Variables:
AUTH_API_URL: !Ref AuthApiUrl
AUTH_SDK_KEYS: !Ref AuthSdkKeys
Policies:
- AWSXrayWriteOnlyAccess
- Statement:
- Sid: Cognito
Effect: Allow
Action:
- cognito-idp:*
Resource: '*'
Events:
???
I found another thread on the same question, but this time via CloudFormation. It says support for this feature is on the roadmap.
PS I am a complete newbie on AWS and cloud computing in general. I apologize if my assumptions make no sense whatsoever.

The documentation says these events are exists. https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-cognito.html#sam-function-cognito-trigger
From this I would try something like:
ApiJWTAddCustomClaimFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub ${AWS::StackName}-ApiJWTAddCustomClaimFunction
Description: Modify JWT before token generation
Handler: main
Environment:
Variables:
AUTH_API_URL: !Ref AuthApiUrl
AUTH_SDK_KEYS: !Ref AuthSdkKeys
Policies:
- AWSXrayWriteOnlyAccess
- Statement:
- Sid: Cognito
Effect: Allow
Action:
- cognito-idp:*
Resource: '*'
Events:
CognitoUserPoolPreTokenGeneration:
Type: Cognito
Properties:
UserPool:
Ref: <<<MyCognitoUserPool>>>
Trigger: PreTokenGeneration

Related

AWS AppSync Lambda Authorizer

I just implemented a lambda resolver in AWS AppSync. The lambda and AppSync live in different projects; The template that provisions the function writes the function ARN to SSM and the template that builds AppSync pulls that SSM parameter down and assigns that ARN to an AdditionalAuthenticationProvider.
The deploy process goes in order synchronously; Lambda (create auth function, set ARN to SSM param) -> AppSync (create API, retrieve SSM param and assign to authorization provider).
When I examine the console, I can see the correct function ARN is assigned as the authentication provider to AppSync.
The problem: when I go to issue a request, the lambda is never invoked, I can check CloudWatch and verify no invocations - I am just met with the response.
{
"errors" : [ {
"errorType" : "BadRequestException"
} ]
}
If I do not provide a value to the authorization header, I get a 401 - which is the expected behavior of the lambda authorization directive, rejecting any requests without a value in that header before proceeding to the function.
So it would appear that something isn't plumbed correctly, something is missing that I can't find in a doc to allow invocation.
The gotcha: if I go into the console and assign this same function ARN manually, everything works fine and stays working fine. It would seem that, perhaps, the console is doing something behind the scenes that my deploy is not, but I cannot seem to correctly identify what is missing.
I've been following this document https://docs.aws.amazon.com/appsync/latest/devguide/security-authz.html#aws-lambda-authorization and one note gives me pause - and I have set these trust permissions, AFAIK.
Lambda functions used for authorization require a principal policy for appsync.amazonaws.com to be applied on them to allow AWS AppSync to call them. This action is done automatically in the AWS AppSync console
Here is the SAM template (without input params)
Resources:
ServiceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ lambda.amazonaws.com, appsync.amazonaws.com ]
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: logs
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: "*"
- Effect: Allow
Action:
- xray:*
Resource: "*"
- PolicyName: ssm
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: ssm:*
Resource: "*"
LambdaPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref AuthorizationFunction
Action: lambda:Invoke
Principal: appsync.amazonaws.com
AuthorizationFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: <code-uri>
Handler: app.lambda
Runtime: nodejs14.x
Role: !GetAtt ServiceRole.Arn
Tracing: Active
FunctionARNParameter:
Type: AWS::SSM::Parameter
Properties:
Type: String
Name: <name>
Value: !GetAtt AuthorizationFunction.Arn
Maybe typing it out my problem was just what I needed. The last thing I tried, LambdaPermission was the key - but the action was incorrect and needed to be InvokeFunction.
I also chose to assign the FunctionName as the lambda ARN instead of the name
LambdaPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !GetAtt PPSAuthorizationFunction.Arn
Action: lambda: InvokeFunction # <--
Principal: appsync.amazonaws.com
Hope this is useful to someone!

Cryptic CloudFormation failure when creating CloudFront Distribution

I have a CloudFormation template set up to track a CloudFront distribution among other things. Getting this set up, I created an AWS::CertificateManager::Certificate and an AWS::CloudFront::Distribution resource, where the CDN just serves from a non-website S3 origin.
When I run the change set, I get this incredibly vague failure.
"Access denied for operation 'AWS::CloudFront::Distribution'." kind of loses me here. For one thing, it's not clear to me what operation this is supposed to be. On top of that, the stack rollback after this is incomplete. The CloudFormation events don't even show an attempt to remove the CDN or the cert, and when I try to hit the CloudFront URL from my browser, it works flawlessly, so I am not even sure what my template was trying to do here that failed. In fact, the only reason this is an issue for me is because the incomplete rollback tries to revert my lambdas in the stack to nodejs8.10, which causes larger failures. If that weren't an issue, I don't know that I would feel the effects of this vague error.
Template, based on the static site sample from a couple of years ago:
AWSTemplateFormatVersion: 2010-09-09
Transform:
- AWS::Serverless-2016-10-31
- AWS::CodeStar
Parameters:
ProjectId:
Type: String
Description: AWS CodeStar projectID used to associate new resources to team members
CodeDeployRole:
Type: String
Description: IAM role to allow AWS CodeDeploy to manage deployment of AWS Lambda functions
Stage:
Type: String
Description: The name for a project pipeline stage, such as Staging or Prod, for which resources are provisioned and deployed.
Default: ''
Globals:
Api:
BinaryMediaTypes:
- image~1png
Function:
Runtime: nodejs14.x
AutoPublishAlias: live
DeploymentPreference:
Enabled: true
Type: Canary10Percent5Minutes
Role: !Ref CodeDeployRole
Resources:
MahCert:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: domain.com
DomainValidationOptions:
- DomainName: domain.com
HostedZoneId: Z2GZX5ZQI1HO5L
SubjectAlternativeNames:
- '*.domain.com'
CertificateTransparencyLoggingPreference: ENABLED
ValidationMethod: DNS
CloudFrontCDN:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Comment: Source for all static resources
PriceClass: PriceClass_100
Aliases:
- domain.com
ViewerCertificate:
AcmCertificateArn: !Ref MahCert
MinimumProtocolVersion: TLSv1.2_2021
SslSupportMethod: sni-only
DefaultRootObject: index.html
DefaultCacheBehavior:
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: b2884449-e4de-46a7-ac36-70bc7f1ddd6d
TargetOriginId: SiteBucket
Enabled: True
Origins:
- DomainName: <my_bucket>.s3.amazonaws.com
Id: SiteBucket
S3OriginConfig:
OriginAccessIdentity: ''
ServerlessRestApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
DefinitionBody:
swagger: 2.0
info:
title: Static resource proxy
paths:
/static/{proxy+}:
get:
x-amazon-apigateway-integration:
httpMethod: ANY
type: http_proxy
uri: <my_bucket>.s3.amazonaws.com/static/{proxy}
responses: {}
GetHelloWorld:
Type: AWS::Serverless::Function
Properties:
Handler: index.get
Role:
Fn::GetAtt:
- LambdaExecutionRole
- Arn
Events:
GetEvent:
Type: Api
Properties:
Path: /
Method: get
ProxyEvent:
Type: Api
Properties:
Path: /{proxy+}
Method: any
GetStaticContent:
Type: AWS::Serverless::Function
Properties:
Handler: index.getResource
Role:
Fn::GetAtt:
- LambdaExecutionRole
- Arn
Events:
GetResourceEvent:
Type: Api
Properties:
Path: /static/{folder}/{file}
Method: get
GetQuote:
Type: AWS::Serverless::Function
Properties:
Handler: index.getQuote
Role:
Fn::GetAtt:
- LambdaDynamoDBReadRole
- Arn
Events:
GetRandomQuoteEvent:
Type: Api
Properties:
Path: /getquote
Method: get
GetQuoteEvent:
Type: Api
Properties:
Path: /getquote/{id}
Method: get
LambdaExecutionRole:
Description: Creating service role in IAM for AWS Lambda
Type: AWS::IAM::Role
Properties:
RoleName: !Sub 'CodeStar-${ProjectId}-Execution${Stage}'
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [lambda.amazonaws.com]
Action: sts:AssumeRole
Path: /
ManagedPolicyArns:
- !Sub 'arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
PermissionsBoundary: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/CodeStar_${ProjectId}_PermissionsBoundary'
LambdaDynamoDBReadRole:
Description: Creating service role in IAM for AWS Lambda
Type: AWS::IAM::Role
Properties:
RoleName: !Sub '${ProjectId}-DynamoDB-Read'
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [lambda.amazonaws.com]
Action: sts:AssumeRole
Path: /
Policies:
-
PolicyName: "dynamodb-read-quotes"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- "dynamodb:GetItem"
- "dynamodb:DescribeTable"
Resource: "<dynamo_arn>"
ManagedPolicyArns:
- !Sub 'arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
Note - domain.com is not the actual domain I'm using here.
Updates:
I deleted the stack completely and recreated it from this template, thinking something was wrong with the history of the stack. However, I got the same error.
The IAM role that the stack uses has these permissions
Indeed, the problem persisted even after granting this role full write access to CloudFront resources.
Based on the chat discussion.
The cause of the issue was found to be missing IAM permissions for the IAM role that is used to deploy the stack. Specifically, the permission that was missing was:
cloudfront:GetDistribution - Grants permission to get the information about a web distribution
Adding that permission to the role, solved the problem.
To find the missing permission, CloudTrial's Event History was used.

What is SourceArn in aws lambda permission

This is my cft for lambda, I upload the jar file to s3 and then upload to lambda through s3, I completed the LambdaRole and LambdaFunction section, in the permission section, what should be the SourceArn? I went through the lambda official doc but didn't find any example.
Also, can anyone take a look to see if this cft is correct or not? Thanks!
ConfigurationLambdaRole:
Type: "AWS::IAM::Role"
Properties:
RoleName: 'configuration-sqs-lambda'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
- events.amazonaws.com
- s3.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSQSFullAccess
- arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
ConfigurationLambdaFunction:
Type: AWS::Lambda::Function
Properties:
Description: 'configuration service with lambda'
FunctionName: 'configuration-lambda'
Handler: com.lambda.handler.EventHandler::handleRequest
Runtime: Java 11
MemorySize: 128
Timeout: 120
Code:
S3Bucket: configurationlambda
S3Key: lambda-service-1.0.0-SNAPSHOT.jar
Role: !GetAtt ConfiguratioLambdaRole.Arn
ConfigurationLambdaInvokePermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName:
Fn::GetAtt:
- ConfigurationLambdaFunction
- Arn
Action: 'lambda:InvokeFunction'
Principal: s3.amazonaws.com
SourceArn: ''
You are creating a Role to run your lambda, a lambda function, and permissions for something to invoke that lambda. The SourceArn is the thing that will invoke the lambda. So in your case it sounds like you want an S3 bucket to invoke the lambda, so the SourceArn would be the ARN of the S3 bucket.
This tutorial relates to what you are doing--specifically step 8 under the "Create the Lambda function" section.
Your CF template generally looks correct. The only thing I see that will be assuming this role is lambda.amazonaws.com, so the role may not need to list the following in the AssumeRolePolicyDocument section:
- events.amazonaws.com
- s3.amazonaws.com
Also see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-permission.html

How to add policy to access secret with lambda function AWS SAM

I am trying to give access permission of secret manager to my lambda function in SAM template but it is giving me error that policy statement is malformed.
Policies:
- Statement:
- Sid: AWSSecretsManagerGetSecretValuePolicy
Effect: Allow
Action: secretsmanager:GetSecretValue
Resource: <arn >
Can some one let me know the correct way of adding policy to my lambda function.
I am using SAM template (Type: AWS::Serverless::Function)
This policy only accepts ARN of a secret, so secret name will not work. https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-policy-template-list.html#secrets-manager-get-secret-value-policy
Below works for me.
Resources:
MyFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: MyProject/
Handler: app
Policies:
- AWSSecretsManagerGetSecretValuePolicy:
SecretArn: 'arn:aws:secretsmanager:####'
or passing it as a parameter
- AWSSecretsManagerGetSecretValuePolicy:
SecretArn: !Ref RdsSecretArn
There are SAM Policy Templates where one of them is AWSSecretsManagerGetSecretValuePolicy you can use them directly in the definition.
Or if you wanna manage the policies yourself.
QueryFunction:
Type: AWS::Serverless::Function
Properties:
Handler: lambda_handler.lambda
Policies:
- AmazonDynamoDBFullAccess
- AWSLambdaVPCAccessExecutionRole
- SSMParameterReadPolicy:
ParameterName: parameter_name
- Statement:
- Effect: Allow
Action:
- dynamodb:*
Resource: 'resource_arn'
Runtime: python3.7
Try this :
Policies:
- Version: '2012-10-17'
Statement:
- Sid: AWSSecretsManagerGetSecretValuePolicy
Effect: Allow
Action: secretsmanager:GetSecretValue
Resource: <arn >
This policy on the lambda works for me (YAML)
Policies:
- AWSSecretsManagerGetSecretValuePolicy:
SecretArn:
Ref: THE_NAME_YOU_GAVE_YOUR_SECRET_RESOURCE

AWS SAM managed policy for SSM get parameter

Is there any managed policy similar to DynamoDBReadPolicy for the ssm:GetParameter* permission for a Lambda function? I'm using aws-sam-cli and trying to follow this, but when I try to fetch the parameters when using sam local start-api, I get the following error:
InvalidAction: The action or operation requested is invalid. Verify that the action is typed correctly.
Here is the snippet where I try to get the parameter:
const ssm = new AWS.SSM();
const param = {
Name: "param1",
WithDecryption: true
};
const secret = await ssm.getParameter(param).promise();
The relevant template sections are below. Thanks!
KeyAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: 'param1Key'
TargetKeyId: !Ref Key
Key:
Type: AWS::KMS::Key
Properties:
KeyPolicy:
Id: default
Statement:
- Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
Action:
- 'kms:Create*'
- 'kms:Encrypt'
- 'kms:Describe*'
- 'kms:Enable*'
- 'kms:List*'
- 'kms:Put*'
- 'kms:Update*'
- 'kms:Revoke*'
- 'kms:Disable*'
- 'kms:Get*'
- 'kms:Delete*'
- 'kms:ScheduleKeyDeletion'
- 'kms:CancelKeyDeletion'
Resource: '*'
Sid: Allow root account all permissions except to decrypt the key
Version: 2012-10-17
LambdaFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ../
Handler: app.lambda
Runtime: nodejs8.10
Policies:
- DynamoDBReadPolicy:
TableName: !Ref Table
- KMSDecryptPolicy:
KeyId: !Ref Key
# I think I need the ssm policy here
The available SAM policy templates are listed in their Github repository. None of these policy templates grants permissions for any SSM operation, so you can't use a SAM policy template to grant your AWS Lambda function access to SSM parameters as of now.
What you can do as a workaround is to manually add the required policy statement inline to your policies. That would look like:
LambdaFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ../
Handler: app.lambda
Runtime: nodejs8.10
Policies:
- DynamoDBReadPolicy:
TableName: !Ref Table
- KMSDecryptPolicy:
KeyId: !Ref Key
- Statement:
- Action:
- ssm:GetParameter
Effect: Allow
Resource: arn:aws:ssm:region:account-id:parameter/parameter_name
You should also consider opening a pull request for adding a policy template for SSM parameter access to SAM, as such a template would of course be a more convenient way to express such permissions. From my experience the developers are very friendly and always welcome such additions.
Update: There is a SSMParameterReadPolicy now available in AWS SAM, so instead of using the workaround you can now simply do:
LambdaFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ../
Handler: app.lambda
Runtime: nodejs8.10
Policies:
- DynamoDBReadPolicy:
TableName: !Ref Table
- KMSDecryptPolicy:
KeyId: !Ref Key
- SSMParameterReadPolicy:
ParameterName: parameter_name