amazon-web-services - 如何使用 IAM 通过 AWS Lambda 调用 AppSync?

标签 amazon-web-services aws-lambda graphql aws-appsync

我目前正在使用 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 权限(作为附加提供程序)。
    你们有什么想法吗?我印象深刻的是,这是一个很少有配置引用的幽灵主题。

    最佳答案

    我终于搞定了。第三次去重读Adrian Hall's post ,它确实让我找到了解决方案。
    请注意,我安装了不需要的 AWS AppSync 客户端,但它简化了过程(否则您必须自己签署 URL。有关这一点,请参阅 Adrian Hall 的帖子)。
    有几件事:

  • 您需要通过包含 cross-fetch 来填充“fetch” (否则,您将受到来自 AppSync 内部使用的 Apollo Client 的 Invariant Violation 的影响)。
  • 您需要将 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
    enter image description here
    这是执行 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
    }
    

    关于amazon-web-services - 如何使用 IAM 通过 AWS Lambda 调用 AppSync?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67244764/

    相关文章:

    amazon-web-services - 如何使用 CLI 在 S3-Bucket 上添加基于 AWS-Lambda 的触发器

    apache - 如何在 aws 普通 ec2 实例上更新我的 SSL 证书

    amazon-web-services - 如何防止 AWS Lambda 自动从 SQS 队列中删除消息,而是以编程方式删除它?

    javascript - apollo graphql 突变 - JSON 输入意外结束

    graphql - 返回 Graphql 计数

    amazon-web-services - 服务角色 EMR_DefaultRole 没有足够的 EC2 权限

    amazon-web-services - 如何从 VPC 私有(private)子网访问 Internet

    amazon-web-services - 如果记录是由 AWS cognito 中的确认后触发器创建的,那么谁是 DynamoDB 中记录的所有者

    java - 使用 aws lambda c# 裁剪图像(使用 Java 解决)

    graphql - 将多个查询的结果合并到一个数组中