如何在 CDK 中将 API Gateway 与 s3 集成

How to integrate API Gateway with s3 in CDK

在控制台中执行此操作的文档非常清楚,https://docs.aws.amazon.com/apigateway/latest/developerguide/integrating-api-with-aws-services-s3.html,但在 CDK 中复制真的很痛苦。

我的问题是如何在 CDK 中创建一个由 s3(中间没有 lambda)支持的 Rest API,或者至少 apigateway.AwsIntegration 是如何工作的。

我已经尝试了很多东西并且意识到我是编码盲人。 我已经在 restApi、lambda、sqs、dynamoDB、s3 之间进行了多次集成,所有这些都非常简单。但是直接将API Gateway 与S3 集成在一起简直要让我哭了。

我需要一个 restAPI 将请求负载直接存储到 S3 存储桶。

这是我已经尝试过的:

向 RestApi 添加政策声明:

const apiResourcePolicy = new iam.PolicyDocument({
        statements: [
          new iam.PolicyStatement({
            effect: iam.Effect.ALLOW,
            actions: ['s3:Put*'],            
            resources: [bucket.bucketName],
            principals: [new ServicePrincipal('apigateway.amazonaws.com')]
          })          
        ]
      });

const api = new apigateway.RestApi(this, "dispatch-api", {
        restApiName: "my api name",
        description: "api description",
        policy: apiResourcePolicy        
      });

我认为这应该足以解决权限问题,但是当我将 AWS 集成添加到 API 时,如下所示:

const getS3Integration = new apigateway.AwsIntegration({
        service: "s3",        
        path: bucket.bucketName,                               
      });

api.root.addMethod("PUT", getS3Integration, {
    requestValidator: requestValidator,
    requestModels: {"application/json": myModel},
  });

我得到:

1:41:11 PM | CREATE_FAILED        | AWS::ApiGateway::Method           | XXXXXXXXXXXXXXXX
Role ARN must be specified for AWS integrations (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: xxxxxxxxxxxxxxxxxxxxx; Proxy:
null)

我不知道如何指定角色 ARN,我在文档中没有找到。也不知道是否有必要向 restAPI 添加策略。我试图在 CDK 中复制示例 here

在您链接的文档 (https://docs.aws.amazon.com/apigateway/latest/developerguide/integrating-api-with-aws-services-s3.html) 中,“为 API 设置 IAM 权限以调用 Amazon S3 操作”部分,您需要使用的策略与您使用的策略完全不同编码。

如果应用于存储桶,您的策略会说:如果请求来自服务“api 网关”,则允许 put:* 操作。此方法适用于其他用例。

根据文档,您需要:

  • 创建角色
  • 该角色应包含策略:
    1. 允许的操作(put:* 在你的情况下)
    2. 允许api网关切换角色。
  • 使用 apigateway.RestApi
  • 中的角色

策略 (1) 应该是显而易见的,文档中给出的 (2) 是:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
} 

根据您的描述,在我看来您没有为您的集成提供 IAM 角色。您只为 RestApi 提供 policy,这是为您的 API 提供的 resource-based 政策。换句话说,它不适用于您的集成,而是指定谁可以执行您的 API。如果你想让你的 API public.

通常你不会使用它

对于 AWS 集成,您应该使用 IntegrationOptions 为 IAM 角色提供 S3 权限。具体来说,通过credentials选项:

An IAM role that API Gateway assumes.

CDK 映射到的 CloudFormation 文档有 more details 集成 Credentials:

The credentials that are required for the integration. To specify an AWS Identity and Access Management (IAM) role that API Gateway assumes, specify the role's Amazon Resource Name (ARN). To require that the caller's identity be passed through from the request, specify arn:aws:iam:::user/.

To use resource-based permissions on the AWS Lambda (Lambda) function, don't specify this property. Use the AWS::Lambda::Permission resource to permit API Gateway to call the function. For more information, see Allow Amazon API Gateway to Invoke a Lambda Function in the AWS Lambda Developer Guide.

以下内容并不完整,但应该会给您一些想法。我在SQS上做过类似的事情,当时我也哭了


    const bucket = new s3.Bucket(this, 'storage');

    const executeRole = new iam.Role(this, "role", {
      assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'),
      path: "/service-role/"
    });

    bucket.grantReadWrite(executeRole);

    const api = new apigateway.RestApi(this, 's3api');

    const s3Integration = new apigateway.AwsIntegration({
      service: 's3',
      integrationHttpMethod: "PUT",
      path: "{bucket}",
      options : {
        credentialsRole: executeRole,
        // should have all kind of path mapping..        
      }
    })

    api.root.addResource("{folder}").addMethod("PUT", s3Integration, {
      methodResponses: [
        {
          statusCode: "200"
        }
      ]});
  }