2
votes

I'm using the serverless framework to upload an AWS Lambda function to be used as a data source in AppSync. The serverless.yml that I have is very basic:

service: mongoose-lambda-srvrls
provider:
  name: aws
  runtime: nodejs6.10
  region: us-west-2
functions:
  mongoose: 
    handler: index.handler 

When I run an AppSync GraphQL query I get the error:

{
  "data": {
    "getPost": null
  },
  "errors": [
    {
      "path": [
        "getPost"
      ],
      "data": null,
      "errorType": "Lambda:AWSLambdaException",
      "errorInfo": null,
      "locations": [
        {
          "line": 43,
          "column": 2
        }
      ],
      "message": "User: arn:aws:sts::433333333335:assumed-role/appsync-datasource-lam-kkzuep-mongoose-lambda-srvr/APPSYNC_ASSUME_ROLE is not authorized to perform: lambda:InvokeFunction on resource: arn:aws:lambda:us-west-2:43333333333335:function:mongoose-lambda-srvrls-dev-mongoose (Service: AWSLambda; Status Code: 403; Error Code: AccessDeniedException; Request ID: 9fa82eb9-3a64-11e8-88a1-09c4e639fc45)"
    }
  ]
}

I'm pretty sure that I need to flesh out my YML so that this lambda stack will play nice with AppSync but I'm not quite sure what to do.


A little more info. When looking at the resources in Lambda's CloudFormation, I see:

IamRoleLambdaExecution  mongoose-lambda-srvrls-dev-us-west-2-lambdaRole AWS::IAM::Role
MongooseLambdaFunction  mongoose-lambda-srvrls-dev-mongoose AWS::Lambda::Function   
MongooseLambdaVersionwCQ1...    arn:aws:lambda:us-west-2:4542242445:function:mongoose-lambda-srvrls-dev-mongoose:4  AWS::Lambda::Version    
MongooseLogGroup    /aws/lambda/mongoose-lambda-srvrls-dev-mongoose AWS::Logs::LogGroup 
ServerlessDeploymentBucket  mongoose-lambda-srvrls-d-serverlessdeploymentbuck-qwp8sdfgjr    AWS::S3::Bucket

Whereas in the Lambda that I made using the AppSync docs (AWS CLI) has the following CloudFormation resources:

AppSyncLambdaInvokePolicy   Fulls-AppS-15SHASDFSADZ03N  AWS::IAM::Policy
AppSyncServiceRole  Fullstack-Lamba-AppSyncServiceRole-DK8QHASDFE5R AWS::IAM::Role
LambdaExecutionRole Fullstack-Lamba-LambdaExecutionRole-OJHASDF3AHG1    AWS::IAM::Role  
LambdaFunction  fullstack-lambda    AWS::Lambda::Function
2
I think AWS made a simple typo in their docs, see stackoverflow.com/a/50984496/1480391Yves M.

2 Answers

4
votes

It looks like the role you gave AppSync to run the lambda function does not have permission to invoke that particular lambda.

You will need to create or modify a role so it has the following permissions.

The IAM role should have a policy which enables anybody who assumes it to run/invoke your lambda function:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:Invoke"
            ],
            "Resource": "arn:aws:lambda:REGION:ACCOUNTNUMBER:function/LAMBDA_FUNCTION"
        }
    ]
}

The role should also have a trust policy. This trust policy will allow AppSync to assume the role on your behalf. This is how AppSync invokes your lambda whenever a graphQL request comes in.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "appsync.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Once you have an IAM role with necessary permissions, you will need to make sure it is associated with the lambda data source in AppSync. You can select the role in the Data Sources section of the AppSync console or use the AppSync CLI to update the lambda data source and make it use your role.

For more information about creating a lambda function which plays nice with AppSync, here is the documentation: https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-lambda-resolvers.html#configure-data-source-for-aws-lambda

2
votes

I think they made a mistake in the https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-lambda-resolvers.html#configure-data-source-for-aws-lambda documentation.

The allowed action should be lambda:InvokeFunction and NOT lambda:Invoke

This is working:

{
  "Version"   : "2012-10-17",
  "Statement" : [{
    "Effect"    : "Allow",
    "Action"    : "lambda:InvokeFunction",
    "Resource"  : "arn:aws:lambda:REGION:ACCOUNTNUMBER:function/LAMBDA_FUNCTION"
  }]
}