如何使用 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 自定义授权者吗?