如何使用 IAM 在 AWS Lambda 中调用 AppSync?

Posted

技术标签:

【中文标题】如何使用 IAM 在 AWS Lambda 中调用 AppSync?【英文标题】:How can I use IAM to invoke AppSync wtihin AWS Lambda? 【发布时间】:2021-07-18 12:51:44 【问题描述】:

我目前正在使用 AppSync 在 AWS Lambda 中实施订阅变更。我想使用 IAM 并避免使用任何其他类型的 AUTH 机制,因为我在 AWS 堆栈中调用它。不幸的是,我收到以下 403 错误:

(摘自 SQS 的 CloudWatch 日志)

 
    "errorMessage": "Response not successful: Received status code 403",
    "name": "ServerError",
    "errorType": "UnrecognizedClientException",
    "message": "The security token included in the request is invalid."
 

我已尝试遵循这些无济于事,但我不知道我错过了什么:

https://medium.com/@jan.hesters/how-to-use-aws-appsync-in-lambda-functions-e593a9cef1d5 https://www.edwardbeazer.com/using-appsync-client-from-lambda/ https://adrianhall.github.io/cloud/2018/10/26/backend-graphql-trigger-appsync/ How to send GraphQL mutation from one server to another? AWS Appsync + HTTP DataSources + AWS IAM AWS Appsync Invoke mutate from Lambda?

这是我当前调用它的代码:

import AWS from "aws-sdk";
import  AWSAppSyncClient  from "aws-appsync";
import  Mutation, mutations  from "./mutations/";
import "cross-fetch/polyfill";

/**
 *
 */

AWS.config.update(
  region: Config.region,
);

export class AppSyncClient 
  client: AWSAppSyncClient<any>;
  constructor() 
    if (!env.APPSYNC_ENDPOINT) 
      throw new Error("APPSYNC_ENDPOINT not defined");
    

    /**
     * We create the AppSyncClient with the AWS_IAM
     * authentication.
     */
    this.client = new AWSAppSyncClient(
      url: env.APPSYNC_ENDPOINT,
      region: Config.region,
      auth: 
        credentials: AWS.config.credentials!,
        type: "AWS_IAM",
      ,
      disableOffline: true,
    );
  

  /**
   * Sends a mutation on the AppSync Client
   * @param mutate The Mutation that will be sent with the variables.
   * @returns
   */
  sendMutation(mutate: Mutation) 
    const mutation = mutations[mutate.type] as any;
    const variables = mutate.variables;
    console.log("Sending the mutation");
    console.log("Variables is ", JSON.stringify(variables));
    return this.client.mutate(
      mutation,
      fetchPolicy: "network-only",
      variables,
    );
  

这是来自 Lambda SQS 的当前 IAM:


    "Statement": [
        
            "Action": [
                "appsync:GraphQL"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:appsync:us-east-2:747936726382:apis/myapi"
            ]
        
    ],
    "Version": "2012-10-17"

我知道这不是 lambda 的 IAM 问题,因为我曾尝试暂时授予它完全访问权限,但仍然出现 403 错误。

我还验证了 AppSync 已配置 IAM 权限(作为附加提供者)。

你们有什么想法吗?我印象深刻,这是一个几乎没有配置参考的鬼主题。

【问题讨论】:

【参考方案1】:

我终于成功了。我第三次去重读Adrian Hall's post,它确实让我找到了解决方案。

请注意,我安装了不需要的 AWS AppSync 客户端,但它简化了流程(否则您必须自己签署 URL。有关内容,请参阅 Adrian Hall 的帖子)。

有几件事:

您需要通过包含 cross-fetch 来填充“获取”(否则您将受到来自 AppSync 内部使用的 Apollo 客户端的不变违规的影响)。 您需要将 lambda 的内部 IAM 凭据(我什至不知道存在)传递给 AppSyncClient 的配置部分。 您需要为 lambda 的 IAM 角色添加适当的权限,在本例中:["appsync:GraphQL"] 用于操作。

这里有一些代码:

这是 AppSync 代码。

// The code is written in TypeScript.
// https://adrianhall.github.io/cloud/2018/10/26/backend-graphql-trigger-appsync/
// https://www.edwardbeazer.com/using-appsync-client-from-lambda/
import  env  from "process";
import  Config, env as Env  from "../../../../shared";
// This is such a bad practice
import AWS from "aws-sdk";
import  AWSAppSyncClient  from "aws-appsync";
import  Mutation, mutations  from "./mutations/";
// Very important, otherwise it won't work!!! You'll have Invariant Violation 
// from Apollo Client.
import "cross-fetch/polyfill";

/**
 *
 */
AWS.config.update(
  region: Config.region,
  credentials: new AWS.Credentials(
    env.AWS_ACCESS_KEY_ID!,
    env.AWS_SECRET_ACCESS_KEY!,
    env.AWS_SESSION_TOKEN!
  ),
);

export class AppSyncClient 
  client: AWSAppSyncClient<any>;
  constructor() 
    // Your AppSync endpoint - The Full URL.
    if (!Env.APPSYNC_ENDPOINT) 
      throw new Error("APPSYNC_ENDPOINT not defined");
    

    /**
     * We create the AppSyncClient with the AWS_IAM
     * authentication.
     */
    this.client = new AWSAppSyncClient(
      url: Env.APPSYNC_ENDPOINT,
      region: Config.region,
      auth: 
        credentials: AWS.config.credentials!,
        type: "AWS_IAM",
      ,
      disableOffline: true,
    );
  

  /**
   * Sends a mutation on the AppSync Client
   * @param mutate The Mutation that will be sent with the variables.
   * @returns
   */
  // The mutation is a object that holds the mutation in 
  // the `gql` tag. You can ommit this part. 
  sendMutation(mutate: Mutation) 
    const mutation = mutations[mutate.type] as any;
    const variables = mutate.variables;
    // This is the important part.
    return this.client.mutate(
      mutation,
      // Specify "no-cache" in the policy. 
      // network-only won't work.
      fetchPolicy: "no-cache",
      variables,
    );
  


我们需要在 AppSync 授权机制中启用 IAM。是的,可以启用多个身份验证。我目前正在同时使用 OPEN_ID 和 IAM。

https://us-east-2.console.aws.amazon.com/appsync/home?region=us-east-2#/myappsync-id/v1/settings

这是执行 GQL 的 Lambda IAM 策略:


    "Statement": [
        
            "Action": [
                "appsync:GraphQL"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:appsync:us-east-2:747936726382:apis/ogolfgja65edlmhkcpp3lcmwli/*"
           
            ]
        
    ],
    "Version": "2012-10-17"

您可以进一步restrict here in the following fashion: arn:$Partition:appsync:$Region:$Account:apis/$GraphQLAPIId/types/$TypeName/fields/$FieldName

arn:aws:appsync:us-east-2:747936726382:apis/ogolfgja65edlmhkcpp3lcmwli/types/Mutation/field/myCustomField"

请注意,我们需要更好地限制这一点,因为我们目前正在为其提供对 API 的完全访问权限。

在您的 .gql 文件(AppSync GraphQL 架构)中,将 @aws_iam 指令添加到用于将订阅发送到的突变中,以限制来自前端的访问。

  type Mutation 
  addUsersMutationSubscription(
    input: AddUsersSagaResultInput!
  ): AddUsersSagaResult @aws_iam

【讨论】:

以上是关于如何使用 IAM 在 AWS Lambda 中调用 AppSync?的主要内容,如果未能解决你的问题,请参考以下文章

AWS Lambda 无法调用 Cognito Identity - IAM 角色

AWS Lambda:即使在STS:AssumeRole成功之后,lambda函数仍然使用旧的IAM角色

即使 IAM 角色具有完整的 Redshift 权限,AWS Lambda 在调用 Redshift 的“CreateCluster”操作时也会出现“拒绝访问”错误

在方法请求中使用 AWS_IAM 授权时需要 AWS Gateway 自定义授权者吗?

在 Cloudformation 模板中为 AWS API Gateway 使用 IAM 角色

Lambda 代入具有细粒度权限的 AWS IAM 角色