使用awsappsynclient在一个ECS容器(Fargate)与AWS_IAM认证模式-返回403 Unrecog



我们在ECS Fargate容器中有以下代码,但是它不断返回错误。当使用IAM身份验证和正确的角色设置在lambda中运行相同的代码时,我能够成功运行此。

错误
Network error: Response not successful: Received status code 403
UnrecognizedClientException
The security token included in the request is invalid.

代码
import 'isomorphic-fetch';
import AWSAppSyncClient, { AUTH_TYPE } from 'aws-appsync';
import AWS from 'aws-sdk';
// Setup variables for client
const graphqlEndpoint = process.env.GRAPHQL_ENDPOINT;
const awsRegion = process.env.AWS_DEFAULT_REGION;
const client = new AWSAppSyncClient({
url: graphqlEndpoint,
region: awsRegion,
auth: {
type: AUTH_TYPE.AWS_IAM,
credentials: AWS.config.credentials,
},
disableOffline: true,
})

Cloudformation

TaskDefinition:
Type: "AWS::ECS::TaskDefinition"
Properties:
ContainerDefinitions:
- Ommitted
Cpu: !FindInMap [CpuMap, !Ref Cpu, Cpu]
ExecutionRoleArn: !GetAtt "TaskExecutionRole.Arn"
Family: !Ref "AWS::StackName"
Memory: !FindInMap [MemoryMap, !Ref Memory, Memory]
NetworkMode: awsvpc
RequiresCompatibilities: [FARGATE]
TaskRoleArn: !GetAtt "TaskRole.Arn"
TaskRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: "ecs-tasks.amazonaws.com"
Action: "sts:AssumeRole"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/AWSAppSyncInvokeFullAccess" # Invoke Access for AppSync

我最终发现这是AppSyncClient无法正确加载ECS中的凭据的结果。

根据ECS中IAM角色的AWS文档,凭据加载与其他AWS服务不同。Amazon ECS代理没有在env变量中填充凭据,而是用凭据的路径填充AWS_CONTAINER_CREDENTIALS_RELATIVE_URI变量。我能够通过首先手动加载ECS凭据并将其传递给AWSAppSyncClient,成功地使AWSAppSyncClientECS容器中与IAM身份验证一起工作。下面的例子成功了。

// AWSAppSyncClient needs to be provided ECS IAM credentials explicitly
const credentials = new AWS.ECSCredentials({
httpOptions: { timeout: 50000 },
maxRetries: 10,
});
AWS.config.credentials = credentials;
// Setup AppSync Config
const AppSyncConfig = {
url: graphqlEndpoint,
region: awsRegion,
auth: {
type: AUTH_TYPE.AWS_IAM,
credentials: AWS.config.credentials,
},
disableOffline: true,
};

这是对原始答案的扩展,包含有关AWS SDK for JavaScript v3的信息。

v3使用@aws-sdk/credential-providers包中的fromContainerMetadata()方法。

使用例子:

import { fromContainerMetadata } from "@aws-sdk/credential-providers"; // ES6 import
// const { fromContainerMetadata } = require("@aws-sdk/credential-providers"); // CommonJS import
const client = new FooClient({
credentials: fromContainerMetadata({
// Optional. The connection timeout (in milliseconds) to apply to any remote requests.
// If not specified, a default value of `1000` (one second) is used.
timeout: 1000,
// Optional. The maximum number of times any HTTP connections should be retried. If not
// specified, a default value of `0` will be used.
maxRetries: 0,
}),
});

最新更新