'Create API Gateway that can read non-public S3 bucket using CDK

I am trying to create a proxy API Gateway using CDK that can access non-public S3 bucket. To do this, I created a role:

const role = new iam.Role(this, 'apigw-s3-readonly-role', {
  roleName: 'ApiGw-S3-ReadOnly',
  assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'),
})

role.addToPolicy(new iam.PolicyStatement({
  resources: [bucket.bucketArn],
  actions: ['s3:GetObject']
}))

And created an API like this:

const api = new apigw.RestApi(this, 'TestApi')

api.root
  .addResource('{file}')
  .addMethod('GET', new apigw.AwsIntegration({
    service: 's3',
    integrationHttpMethod: 'GET',
    path: 'my-test-bucket/{file}',
    options: {
      credentialsRole: role,
      requestParameters: {
        'integration.request.path.file': 'method.request.path.file'
      },
      integrationResponses: [{
        statusCode: "200"
      }]
    }
  }), {
    requestParameters: {
      'method.request.path.file': true
    }
  })

But this requires S3 bucket public. I think this is because it sends http request to S3 but I allowed only s3:GetObject in the role.

So, how can I change the API gateway to allow access S3 bucket objects without making them public.

I tried the following code, which looked promising as it states action GetObject, but it didn't work.

api.root
  .addResource('{file}')
  .addMethod('GET', new apigw.AwsIntegration({
    service: 's3',
    action: 'GetObject',
    actionParameters: {
      Bucket: 'my-test-bucket',
      Key: 'file'
    },
    ...


Solution 1:[1]

Your policy has a problem. The GetObject permission should be applied to the object not to the bucket.

role.addToPolicy(new iam.PolicyStatement({
  resources: [`${bucket.bucketArn}/*`],
  actions: ['s3:GetObject']
}))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Arun Kamalanathan