Como integrar API Gateway com s3 em CDK

Sep 12 2020

Os documentos são muito claros ao fazer isso no console, https://docs.aws.amazon.com/apigateway/latest/developerguide/integrating-api-with-aws-services-s3.html, mas replicar em CDK é muito doloroso.

Minha dúvida é como criar uma API Rest apoiada em s3 (sem lambda no meio) no CDK, ou pelo menos como funciona o apigateway.AwsIntegration.

Tentei muitas coisas e percebi que estava programando às cegas. Já fiz várias integrações entre restApi, lambda, sqs, dynamoDB, s3 e todas elas foram muito fáceis. Mas a integração direta do API Gateway com o S3 está prestes a me fazer chorar.

Preciso que uma restAPI armazene a carga útil da solicitação diretamente em um balde S3.

Isso é o que eu já tentei:

Adicione um estatuto de política ao 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        
      });

Achei que isso deveria ser o suficiente para resolver problemas de permissões, mas quando adicionei a Integração AWS à API, assim:

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

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

Estou entendendo:

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)

Não sei como especificar esse Role ARN, não encontrei isso nos documentos. Também não sei se adicionar política ao restAPI era necessário. Eu estava tentando replicar o exemplo aqui no CDK.

Respostas

3 Chun Sep 14 2020 at 18:19

A seguir não está o conjunto completo, mas isso deve lhe dar algumas idéias. Fiz coisas semelhantes no SQS, também chorei naquela época


    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"
        }
      ]});
  }
1 olpa Sep 14 2020 at 04:20

No documento que você vinculou (https://docs.aws.amazon.com/apigateway/latest/developerguide/integrating-api-with-aws-services-s3.html), seção "Configurar permissões de IAM para a API para invocar ações do Amazon S3", a política que você precisa usar é totalmente diferente da que você codificou.

Sua política, se aplicada a um balde, diria: se a solicitação for do serviço "gateway da API", permita put:*ações. Essa abordagem é para outros casos de uso.

De acordo com a documentação, você precisa de:

  • criar uma função
  • a função deve conter políticas:
    1. ações permitidas ( put:*no seu caso)
    2. permitir que o gateway api mude para a função.
  • usar a função em apigateway.RestApi

A política (1) deve ser óbvia, a (2) conforme fornecida na documentação é:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "apigateway.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
} 
1 Marcin Sep 14 2020 at 08:02

Pela sua descrição, parece-me que você não está fornecendo a função IAM para sua integração. Você está fornecendo uma políticaRestApi somente para a qual é uma política baseada em recursos para sua API. Em outras palavras, não se aplica a suas integrações, mas especifica quem pode executar sua API. Geralmente você não o usa se quiser tornar sua API pública.

Para integração com AWS, você deve fornecer a função IAM com permissões S3 usando IntegrationOptions . Especificamente, por meio da credentialsopção:

Uma função IAM que o API Gateway assume .

Os documentos do CloudFormation, nos quais o CDK mapeia, têm mais detalhes sobre a integração Credentials:

As credenciais necessárias para a integração. Para especificar uma função AWS Identity and Access Management (IAM) que o API Gateway assume, especifique o Amazon Resource Name (ARN) da função. Para exigir que a identidade do chamador seja transmitida a partir da solicitação, especifique arn: aws: iam ::: user / .

Para usar permissões baseadas em recursos na função AWS Lambda (Lambda), não especifique esta propriedade. Use o recurso AWS :: Lambda :: Permission para permitir que o API Gateway chame a função. Para obter mais informações, consulte Permitir que o Amazon API Gateway invoque uma função Lambda no AWS Lambda Developer Guide.