aws-amplify / amplify-category-api

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development. This plugin provides functionality for the API category, allowing for the creation and management of GraphQL and REST based backends for your amplify project.
https://docs.amplify.aws/
Apache License 2.0
89 stars 79 forks source link

Accessing graphql lambda resolvers is breaking using iam auth. Not Authorized to access lambda resolver. #2121

Closed DevTGhosh closed 10 months ago

DevTGhosh commented 11 months ago

How did you install the Amplify CLI?

npm

If applicable, what version of Node.js are you using?

v16.20.1

Amplify CLI Version

12.8.2

What operating system are you using?

Mac

Did you make any manual changes to the cloud resources managed by Amplify? Please describe the changes made.

No

Describe the bug

I have a lambda (emailScrapper) that access's another grapqhl lambda resolver (purchaseLambda) through graphql api and it has been showing me the unauthorization issue for the past week. Everything was working fine till last week. No changes have been made from my side that could affect this.

  1. The emailScrapper lambda that gets called can access and update another grapqhl model but it can't access the graphql custom lambda resolver.

Expected behavior

For the lambda to be abel to call another graphql resolver.

Reproduction steps

schema.graphql

type Company
  @model
  @auth(
    rules: [
      { allow: groups, groups: ["companyAdmin"], operations: [ read, update] }
       { allow: private, provider: iam }
    ]
  ) {
  id: ID!
  name: String
  }

  type Mutation {
     purchaseLambda:  (preparePurchaseId: ID!
  ): CustomResolverStatusResponse
    @function(name: "purchaseLambda-${env}")
        @auth(rules: [{ allow: private, provider: iam }, { allow: groups, groups: ["companyAdmin"] }])

   }

Within emailScrapper lambda give it access to graphql from this https://docs.amplify.aws/react/build-a-backend/graphqlapi/connect-from-server-runtime/#commonjs

api file for calling graphql resolver lambda

     import { Sha256 } from '@aws-crypto/sha256-js'
import { defaultProvider } from '@aws-sdk/credential-provider-node'
import { HttpRequest } from '@aws-sdk/protocol-http'
import { SignatureV4 } from '@aws-sdk/signature-v4'
import { print } from 'graphql'
import gql from 'graphql-tag'
import log from 'lambda-log'
// * We use node fetch version 2.6.6 because v3+ uses ESM not commonjs which is what typescript is outputting right now
import fetch, { Request } from 'node-fetch'
const Sentry = require('@sentry/serverless')

const AWS_REGION = process.env.AWS_REGION || 'eu-west-2'

const GraphqlAPIUrl = process.env
    .API_CHEDARV2STAGING_GRAPHQLAPIENDPOINTOUTPUT as string
log.info('AWS_REGION: ', { AWS_REGION })
log.info('GraphqlAPIUrl: ', { GraphqlAPIUrl })

const purchaseLambda = gql`
  mutation purchaseLambda(
    $preparePurchaseId: ID!
  ) {
    purchaseLambda(
      preparePurchaseId: $preparePurchaseId
    ) {
      status
    }
  }
`

async function apiCallsForPurchase({
    preparePurchaseId,
}: {

    preparePurchaseId: string
}) {
    try {
        const endpoint = new URL(GraphqlAPIUrl)
        console.log('endpoint: ', endpoint)
        const signer = new SignatureV4({
            credentials: defaultProvider(),
            region: AWS_REGION,
            service: 'appsync',
            sha256: Sha256,
        })
        const mutationVariable = {

            preparePurchaseId,
        }
        log.info('mutationVariable', mutationVariable)

        const mutationRequestToBeSigned = new HttpRequest({
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                host: endpoint.host,
            },
            hostname: endpoint.host,
            body: JSON.stringify({
                operationName: 'purchaseLambda',
                query: print(purchaseLambda),
                variables: mutationVariable,
            }),
            path: endpoint.pathname,
        })

        const signedMutation = await signer.sign(mutationRequestToBeSigned)
        // @ts-ignore
        const requestMutation = new Request(endpoint, signedMutation)
        let statusCode = 200
        let body = {} as any
        let response
        let purchaseResult
        try {
            response = await fetch(requestMutation)
            body = await response.json()
            if (body?.errors) statusCode = 400
            else purchaseResult = body.data
        } catch (error: any) {
            Sentry.captureException(error)
            log.error(error)
            statusCode = 500
            body = {
                errors: [
                    {
                        message: error?.message,
                    },
                ],
            }
        }
        log.info('statusCode Mutation', { statusCode })
        log.info('body of Mutation', body)
        log.info('purchase lambda', purchaseResult)

        return
    } catch (err: any) {
        Sentry.captureException(err)
        log.error(err)
    }
}

export default apiCallsForPurchase

Project Identifier

9416a52d4390bc60fee0f1de8176ba91

Log output

``` # Put your logs below this line ```

Additional information

No response

Before submitting, please confirm:

phani-srikar commented 11 months ago

This seems to be related to https://github.com/aws-amplify/amplify-category-api/issues/2060. This regression is fixed in https://github.com/aws-amplify/amplify-category-api/pull/2062 and pending release.

dpilch commented 10 months ago

The fix is available in v12.10.0 of the CLI.